diff --git a/app/controllers/Account.scala b/app/controllers/Account.scala
index 938b0c03b1371..3802e73ba49f3 100644
--- a/app/controllers/Account.scala
+++ b/app/controllers/Account.scala
@@ -102,6 +102,7 @@ final class Account(
me.value,
withFollows = apiC.userWithFollows,
withTrophies = false,
+ withCanChallenge = false,
forWiki = wikiGranted
)
.dmap { JsonOk(_) }
diff --git a/app/controllers/Api.scala b/app/controllers/Api.scala
index 17947ad1ffa0c..f6c3ad921adb0 100644
--- a/app/controllers/Api.scala
+++ b/app/controllers/Api.scala
@@ -47,7 +47,8 @@ final class Api(
.extended(
name,
withFollows = userWithFollows,
- withTrophies = getBool("trophies")
+ withTrophies = getBool("trophies"),
+ withCanChallenge = getBool("challenge")
)
.map(toApiResult)
.map(toHttp)
diff --git a/app/controllers/Auth.scala b/app/controllers/Auth.scala
index 2a64071ea7e71..c9370ddbba3f8 100644
--- a/app/controllers/Auth.scala
+++ b/app/controllers/Auth.scala
@@ -40,12 +40,11 @@ final class Auth(
): Fu[Result] =
api
.saveAuthentication(u.id, ctx.mobileApiVersion)
- .flatMap { sessionId =>
+ .flatMap: sessionId =>
negotiate(
result.fold(Redirect(getReferrer))(_(getReferrer)),
mobileUserOk(u, sessionId)
).map(authenticateCookie(sessionId, remember))
- }
.recoverWith(authRecovery)
private def authenticateAppealUser(u: UserModel, redirect: String => Result)(using
@@ -53,10 +52,9 @@ final class Auth(
): Fu[Result] =
api.appeal
.saveAuthentication(u.id)
- .flatMap { sessionId =>
+ .flatMap: sessionId =>
authenticateCookie(sessionId, remember = false):
redirect(routes.Appeal.landing.url)
- }
.recoverWith(authRecovery)
private def authenticateCookie(sessionId: String, remember: Boolean)(
diff --git a/app/controllers/BulkPairing.scala b/app/controllers/BulkPairing.scala
index e12c1a1dbd745..7abc651851961 100644
--- a/app/controllers/BulkPairing.scala
+++ b/app/controllers/BulkPairing.scala
@@ -5,8 +5,9 @@ import play.api.libs.json.*
import lila.app.*
import lila.common.Json.given
import lila.challenge.ChallengeBulkSetup
+import lila.api.GameApiV2
-final class BulkPairing(env: Env) extends LilaController(env):
+final class BulkPairing(gameC: => Game, apiC: => Api, env: Env) extends LilaController(env):
def list = ScopedBody(_.Challenge.Bulk) { _ ?=> me ?=>
env.challenge.bulk
@@ -23,6 +24,24 @@ final class BulkPairing(env: Env) extends LilaController(env):
JsonOk(ChallengeBulkSetup.toJson(bulk))
}
+ def games(id: String) = ScopedBody(_.Challenge.Bulk) { _ ?=> me ?=>
+ env.challenge.bulk
+ .findBy(id, me)
+ .map:
+ _.fold(notFoundText()): bulk =>
+ val config = GameApiV2.ByIdsConfig(
+ ids = bulk.games.map(_.id),
+ format = GameApiV2.Format.byRequest(req),
+ flags = gameC
+ .requestPgnFlags(extended = false)
+ .copy(delayMoves = false),
+ perSecond = MaxPerSecond(50)
+ )
+ apiC.GlobalConcurrencyLimitPerIP
+ .download(req.ipAddress)(env.api.gameApiV2.exportByIds(config)): source =>
+ noProxyBuffer(Ok.chunked(source)).as(gameC.gameContentType(config))
+ }
+
def delete(id: String) = ScopedBody(_.Challenge.Bulk) { _ ?=> me ?=>
env.challenge.bulk
.deleteBy(id, me)
diff --git a/app/controllers/Challenge.scala b/app/controllers/Challenge.scala
index 4c4e8fffbcee3..070426baceb29 100644
--- a/app/controllers/Challenge.scala
+++ b/app/controllers/Challenge.scala
@@ -274,7 +274,7 @@ final class Challenge(
case None => redir
case Some(dest) if ctx.is(dest) => redir
case Some(dest) =>
- env.challenge.granter.isDenied(dest, c.perfType).flatMap {
+ env.challenge.granter.isDenied(dest, c.perfType.key.some).flatMap {
case Some(denied) =>
showChallenge(c, lila.challenge.ChallengeDenied.translated(denied).some)
case None => api.setDestUser(c, dest).inject(redir)
@@ -303,7 +303,7 @@ final class Challenge(
limit.challengeUser(me, rateLimited, cost = cost):
for
challenge <- makeOauthChallenge(config, me, destUser)
- grant <- env.challenge.granter.isDenied(destUser, config.perfType)
+ grant <- env.challenge.granter.isDenied(destUser, config.perfKey.some)
res <- grant match
case Some(denied) =>
fuccess:
@@ -376,7 +376,7 @@ final class Challenge(
NoBot:
Found(env.game.gameRepo.game(gameId)): g =>
g.opponentOf(me).flatMap(_.userId).so(env.user.repo.byId).orNotFound { opponent =>
- env.challenge.granter.isDenied(opponent, g.perfKey).flatMap {
+ env.challenge.granter.isDenied(opponent, g.perfKey.some).flatMap {
case Some(d) => BadRequest(jsonError(lila.challenge.ChallengeDenied.translated(d)))
case _ =>
api.offerRematchForGame(g, me).map {
diff --git a/app/controllers/ForumCateg.scala b/app/controllers/ForumCateg.scala
index b960398dd7962..cc62a504da88c 100644
--- a/app/controllers/ForumCateg.scala
+++ b/app/controllers/ForumCateg.scala
@@ -35,3 +35,12 @@ final class ForumCateg(env: Env) extends LilaController(env) with ForumControlle
if canRead then Ok.page(views.forum.categ.show(categ, topics, canWrite, stickyPosts))
else notFound
yield res
+
+ def modFeed(slug: ForumCategId, page: Int) = Secure(_.ModerateForum) { ctx ?=> _ ?=>
+ Found(env.forum.categRepo.byId(slug)): categ =>
+ for
+ posts <- env.forum.paginator.recent(categ, page)
+ postViews <- posts.mapFutureList(env.forum.postApi.views)
+ page <- renderPage(views.forum.categ.modFeed(categ, postViews))
+ yield Ok(page)
+ }
diff --git a/app/controllers/ForumPost.scala b/app/controllers/ForumPost.scala
index 24216c5853b28..3661e13cfc796 100644
--- a/app/controllers/ForumPost.scala
+++ b/app/controllers/ForumPost.scala
@@ -108,6 +108,21 @@ final class ForumPost(env: Env) extends LilaController(env) with ForumController
NoContent
}
+ def relocate(id: ForumPostId) = SecureBody(_.ModerateForum) { ctx ?=> me ?=>
+ Found(postApi.getPost(id).flatMapz(postApi.viewOf)): post =>
+ forms.relocateTo
+ .bindFromRequest()
+ .value
+ .so: to =>
+ env.forum.topicApi
+ .relocate(post.topic.id, to)
+ .inject:
+ post.post.userId.foreach: op =>
+ val newUrl = routes.ForumTopic.show(to, post.topic.slug, 1).url
+ env.msg.api.systemPost(op, MsgPreset.forumRelocation(post.topic.name, newUrl))
+ Redirect(routes.ForumCateg.show(to)).flashSuccess
+ }
+
def react(categId: ForumCategId, id: ForumPostId, reaction: String, v: Boolean) = Auth { _ ?=> me ?=>
CategGrantWrite(categId):
FoundSnip(postApi.react(categId, id, reaction, v)): post =>
diff --git a/app/controllers/Mod.scala b/app/controllers/Mod.scala
index 0499854ac93ac..79bf7ccc98542 100644
--- a/app/controllers/Mod.scala
+++ b/app/controllers/Mod.scala
@@ -159,16 +159,14 @@ final class Mod(
bindForm(lila.user.UserForm.title)(
_ => redirect(username, mod = true),
title =>
- doSetTitle(username.id, title, public = true).inject:
+ doSetTitle(username.id, title).inject:
redirect(username, mod = false)
)
}
- protected[controllers] def doSetTitle(userId: UserId, title: Option[chess.PlayerTitle], public: Boolean)(
- using Me
- ) = for
- _ <- (public || title.isEmpty).so(modApi.setTitle(userId, title))
- _ <- title.so(env.mailer.automaticEmail.onTitleSet(userId, _, public))
+ protected[controllers] def doSetTitle(userId: UserId, title: Option[chess.PlayerTitle])(using Me) = for
+ _ <- modApi.setTitle(userId, title)
+ _ <- title.so(env.mailer.automaticEmail.onTitleSet(userId, _))
yield ()
def setEmail(username: UserStr) = SecureBody(_.SetEmail) { ctx ?=> me ?=>
@@ -470,7 +468,7 @@ final class Mod(
} >> {
Permission
.ofDbKeys(permissions)
- .exists(_.grants(Permission.SeeReport))
+ .exists(p => p.grants(Permission.SeeReport) || p.grants(Permission.Developer))
.so(env.plan.api.setLifetime(user))
}).inject(Redirect(routes.Mod.permissions(user.username)).flashSuccess)
)
diff --git a/app/controllers/RelayRound.scala b/app/controllers/RelayRound.scala
index 57586cd408e68..a6e3748d3f3be 100644
--- a/app/controllers/RelayRound.scala
+++ b/app/controllers/RelayRound.scala
@@ -94,9 +94,9 @@ final class RelayRound(
)
}
- def reset(id: RelayRoundId) = Auth { ctx ?=> me ?=>
+ def reset(id: RelayRoundId) = AuthOrScoped(_.Study.Write) { ctx ?=> me ?=>
Found(env.relay.api.byIdAndContributor(id)): rt =>
- env.relay.api.reset(rt.round).inject(Redirect(rt.path))
+ env.relay.api.reset(rt.round) >> negotiate(Redirect(rt.path), jsonOkResult)
}
def show(ts: String, rs: String, id: RelayRoundId, embed: Option[UserStr]) =
@@ -122,13 +122,29 @@ final class RelayRound(
Found(env.study.studyRepo.byId(rt.round.studyId)): study =>
studyC.CanView(study)(
for
- group <- env.relay.api.withTours.get(rt.tour.id)
- previews <- env.study.preview.jsonList(study.id)
- yield JsonOk(env.relay.jsonView.withUrlAndPreviews(rt.withStudy(study), previews, group))
+ group <- env.relay.api.withTours.get(rt.tour.id)
+ previews <- env.study.preview.jsonList.withoutInitialEmpty(study.id)
+ targetRound <- env.relay.api.officialTarget(rt.round)
+ yield JsonOk(
+ env.relay.jsonView.withUrlAndPreviews(rt.withStudy(study), previews, group, targetRound)
+ )
)(studyC.privateUnauthorizedJson, studyC.privateForbiddenJson)
- def pgn(ts: String, rs: String, id: StudyId) = studyC.pgn(id)
- def apiPgn = studyC.apiPgn
+ def pgn(ts: String, rs: String, id: RelayRoundId) = Open:
+ pgnWithFlags(ts, rs, id)
+
+ def apiPgn(id: RelayRoundId) = AnonOrScoped(_.Study.Read): ctx ?=>
+ pgnWithFlags("-", "-", id)
+
+ private def pgnWithFlags(ts: String, rs: String, id: RelayRoundId)(using Context): Fu[Result] =
+ studyC.pgnWithFlags(
+ id.into(StudyId),
+ _.copy(
+ site = s"${env.net.baseUrl}${routes.RelayRound.show(ts, rs, id)}".some,
+ comments = false,
+ variations = false
+ )
+ )
def apiMyRounds = Scoped(_.Study.Read) { ctx ?=> _ ?=>
val source = env.relay.api.myRounds(MaxPerSecond(20), getIntAs[Max]("nb")).map(env.relay.jsonView.myRound)
@@ -174,6 +190,13 @@ final class RelayRound(
env.relay.teamTable.tableJson(rt.relay).map(JsonStrOk)
}(Unauthorized, Forbidden)
+ def stats(id: RelayRoundId) = Open:
+ env.relay.stats
+ .get(id)
+ .map: stats =>
+ import lila.relay.JsonView.given
+ JsonOk(stats)
+
private def WithRoundAndTour(@nowarn ts: String, @nowarn rs: String, id: RelayRoundId)(
f: RoundModel.WithTour => Fu[Result]
)(using ctx: Context): Fu[Result] =
diff --git a/app/controllers/RelayTour.scala b/app/controllers/RelayTour.scala
index 1ea846a2b2e83..c04b581aa592a 100644
--- a/app/controllers/RelayTour.scala
+++ b/app/controllers/RelayTour.scala
@@ -115,7 +115,7 @@ final class RelayTour(env: Env, apiC: => Api) extends LilaController(env):
setup =>
env.relay.api.tourUpdate(nav.tour, setup) >>
negotiate(
- Redirect(routes.RelayTour.show(nav.tour.slug, nav.tour.id)),
+ Redirect(routes.RelayTour.edit(nav.tour.id)).flashSuccess,
jsonOkResult
)
)
@@ -189,13 +189,6 @@ final class RelayTour(env: Env, apiC: => Api) extends LilaController(env):
asAttachmentStream(s"${env.relay.pgnStream.filename(tour)}.pgn"):
Ok.chunked(source).as(pgnContentType)
- def stats(id: RelayTourId) = Open:
- Found(env.relay.api.tourById(id)): tour =>
- env.relay.stats
- .get(tour.id)
- .flatMap: stats =>
- Ok.page(views.relay.tour.stats(tour, stats))
-
def apiIndex = Anon:
apiC.jsonDownload:
env.relay.tourStream
diff --git a/app/controllers/Report.scala b/app/controllers/Report.scala
index e6de5e57dec2a..eb738613ea763 100644
--- a/app/controllers/Report.scala
+++ b/app/controllers/Report.scala
@@ -153,7 +153,7 @@ final class Report(env: Env, userC: => User, modC: => Mod) extends LilaControlle
text = s"$pid\n\n"
)
case _ => form
- views.report.form(filledForm, user)
+ views.report.ui.form(filledForm, user)
}
}
@@ -162,7 +162,7 @@ final class Report(env: Env, userC: => User, modC: => Mod) extends LilaControlle
err =>
for
user <- getUserStr("username").so(env.user.repo.byId)
- page <- renderPage(views.report.form(err, user))
+ page <- renderPage(views.report.ui.form(err, user))
yield BadRequest(page),
data =>
if me.is(data.user.id) then BadRequest("You cannot report yourself")
diff --git a/app/controllers/Setup.scala b/app/controllers/Setup.scala
index 23125ee8e9074..62c5d85c372c1 100644
--- a/app/controllers/Setup.scala
+++ b/app/controllers/Setup.scala
@@ -48,7 +48,7 @@ final class Setup(
for
origUser <- ctx.user.soFu(env.user.perfsRepo.withPerf(_, config.perfType))
destUser <- userId.so(env.user.api.enabledWithPerf(_, config.perfType))
- denied <- destUser.so(u => env.challenge.granter.isDenied(u.user, config.perfType))
+ denied <- destUser.so(u => env.challenge.granter.isDenied(u.user, config.perfKey.some))
result <- denied match
case Some(denied) =>
val message = lila.challenge.ChallengeDenied.translated(denied)
diff --git a/app/controllers/Study.scala b/app/controllers/Study.scala
index 13d7f269a664c..f911b5ce423da 100644
--- a/app/controllers/Study.scala
+++ b/app/controllers/Study.scala
@@ -15,6 +15,7 @@ import lila.study.JsonView.JsData
import lila.study.Study.WithChapter
import lila.study.actorApi.{ BecomeStudyAdmin, Who }
import lila.study.{ Chapter, Settings, Orders, Study as StudyModel, StudyForm }
+import lila.study.PgnDump.WithFlags
import lila.tree.Node.partitionTreeJsonWriter
import lila.core.misc.lpv.LpvEmbed
import lila.core.net.IpAddress
@@ -242,7 +243,7 @@ final class Study(
division = division
)
)
- withMembers = !study.isRelay || isGrantedOpt(_.StudyAdmin)
+ withMembers = !study.isRelay || isGrantedOpt(_.StudyAdmin) || ctx.me.exists(study.isMember)
studyJson <- env.study.jsonView(study, previews, chapter, fedNames.some, withMembers = withMembers)
yield WithChapter(study, chapter) -> JsData(
study = studyJson,
@@ -319,11 +320,12 @@ final class Study(
def delete(id: StudyId) = Auth { _ ?=> me ?=>
Found(env.study.api.byIdAndOwnerOrAdmin(id, me)): study =>
- env.study.api.delete(study) >> env.relay.api
- .deleteRound(id.into(RelayRoundId))
- .map:
- case None => Redirect(routes.Study.mine(Order.hot))
- case Some(tour) => Redirect(routes.RelayTour.show(tour.slug, tour.id))
+ for
+ round <- env.relay.api.deleteRound(id.into(RelayRoundId))
+ _ <- env.study.api.delete(study)
+ yield round match
+ case None => Redirect(routes.Study.mine(Order.hot))
+ case Some(tour) => Redirect(routes.RelayTour.show(tour.slug, tour.id))
}
def apiChapterDelete(id: StudyId, chapterId: StudyChapterId) = ScopedBody(_.Study.Write) { _ ?=> me ?=>
@@ -411,27 +413,23 @@ final class Study(
}
def pgn(id: StudyId) = Open:
+ pgnWithFlags(id, identity)
+
+ def apiPgn(id: StudyId) = AnonOrScoped(_.Study.Read): ctx ?=>
+ pgnWithFlags(id, identity)
+
+ def pgnWithFlags(id: StudyId, flags: Update[WithFlags])(using Context) =
Found(env.study.api.byId(id)): study =>
HeadLastModifiedAt(study.updatedAt):
- limit.studyPgn(ctx.ip, rateLimited, msg = id.value):
- CanView(study, study.settings.shareable.some)(doPgn(study))(
+ val limiter = if study.isRelay then limit.relayPgn else limit.studyPgn
+ limiter[Fu[Result]](req.ipAddress, rateLimited, msg = id.value):
+ CanView(study, study.settings.shareable.some)(doPgn(study, flags))(
privateUnauthorizedFu(study),
privateForbiddenFu(study)
)
- def apiPgn(id: StudyId) = AnonOrScoped(_.Study.Read): ctx ?=>
- env.study.api.byId(id).flatMap {
- _.fold(studyNotFoundText.toFuccess): study =>
- HeadLastModifiedAt(study.updatedAt):
- limit.studyPgn[Fu[Result]](req.ipAddress, rateLimited, msg = id.value):
- CanView(study, study.settings.shareable.some)(doPgn(study))(
- privateUnauthorizedText,
- privateForbiddenText
- )
- }
-
- private def doPgn(study: StudyModel)(using RequestHeader, Option[Me]) =
- Ok.chunked(env.study.pgnDump.chaptersOf(study, requestPgnFlags).throttle(16, 1.second))
+ private def doPgn(study: StudyModel, flags: Update[WithFlags])(using RequestHeader, Option[Me]) =
+ Ok.chunked(env.study.pgnDump.chaptersOf(study, flags(requestPgnFlags)).throttle(20, 1.second))
.pipe(asAttachmentStream(s"${env.study.pgnDump.filename(study)}.pgn"))
.as(pgnContentType)
.withDateHeaders(lastModified(study.updatedAt))
@@ -494,12 +492,13 @@ final class Study(
.map(lila.study.JsonView.metadata)
private def requestPgnFlags(using RequestHeader) =
- lila.study.PgnDump.WithFlags(
+ WithFlags(
comments = getBoolOpt("comments") | true,
variations = getBoolOpt("variations") | true,
clocks = getBoolOpt("clocks") | true,
source = getBool("source"),
- orientation = getBool("orientation")
+ orientation = getBool("orientation"),
+ site = none
)
def chapterGif(id: StudyId, chapterId: StudyChapterId, theme: Option[String], piece: Option[String]) = Open:
diff --git a/app/controllers/TeamApi.scala b/app/controllers/TeamApi.scala
index ca55d42d0f963..32f961d5bc1c4 100644
--- a/app/controllers/TeamApi.scala
+++ b/app/controllers/TeamApi.scala
@@ -50,9 +50,10 @@ final class TeamApi(env: Env, apiC: => Api) extends LilaController(env):
else ctx.me.so(api.belongsTo(team.id, _))
canView.map:
if _ then
+ val full = getBool("full")
apiC.jsonDownload(
env.team
- .memberStream(team, MaxPerSecond(20))
+ .memberStream(team, full)
.map: (user, joinedAt) =>
env.api.userApi.one(user, joinedAt.some)
)
diff --git a/app/controllers/TitleVerify.scala b/app/controllers/TitleVerify.scala
index 68f89b6057368..ef1ea5b1e345b 100644
--- a/app/controllers/TitleVerify.scala
+++ b/app/controllers/TitleVerify.scala
@@ -123,10 +123,12 @@ final class TitleVerify(env: Env, cmsC: => Cms, reportC: => report.Report, userC
private def onApproved(req: TitleRequest)(using Context, Me) =
for
user <- env.user.api.byId(req.userId).orFail(s"User ${req.userId} not found")
- _ <- modC.doSetTitle(user.id, req.data.title.some, req.data.public)
+ _ <- modC.doSetTitle(user.id, req.data.title.some)
url = s"${env.net.baseUrl}${routes.TitleVerify.show(req.id)}"
note = s"Title verified: ${req.data.title}. Public: ${if req.data.public then "Yes" else "No"}. $url"
_ <- env.user.noteApi.write(user.id, note, modOnly = true, dox = false)
+ _ <- req.data.public.so:
+ env.user.repo.setRealName(user.id, req.data.realName)
_ <- req.data.coach.so:
env.user.repo.addPermission(user.id, lila.core.perm.Permission.Coach)
_ <- req.data.coach.so:
diff --git a/app/controllers/User.scala b/app/controllers/User.scala
index 86e0a888576aa..5d5322282509e 100644
--- a/app/controllers/User.scala
+++ b/app/controllers/User.scala
@@ -66,6 +66,12 @@ final class User(
apiGames(u, GameFilter.All.name, 1)
)
+ def search(term: String) = Open: _ ?=>
+ UserStr.read(term) match
+ case Some(username) => Redirect(routes.User.show(username)).toFuccess
+ case _ if isGrantedOpt(_.UserSearch) => Redirect(s"${routes.Mod.search}?q=$term").toFuccess
+ case _ => notFound
+
private def renderShow(u: UserModel, status: Results.Status = Results.Ok)(using Context): Fu[Result] =
if HTTPRequest.isSynchronousHttp(ctx.req)
then
diff --git a/app/http/CtrlFilters.scala b/app/http/CtrlFilters.scala
index 1bf518af10d08..5259d05c84cc6 100644
--- a/app/http/CtrlFilters.scala
+++ b/app/http/CtrlFilters.scala
@@ -104,7 +104,7 @@ trait CtrlFilters(using Executor) extends ControllerHelpers with ResponseBuilder
max: Max = Max(40),
errorPage: => Fu[Result] = BadRequest("resource too old")
)(result: => Fu[Result]): Fu[Result] =
- if page < max.value && page > 0 then result else errorPage
+ if page <= max.value && page > 0 then result else errorPage
def NotForKids(f: => Fu[Result])(using ctx: Context): Fu[Result] =
if ctx.kid.no then f else notFound
diff --git a/app/views/report.scala b/app/views/report.scala
index 7d3d0f771465e..0ee10a7f127cd 100644
--- a/app/views/report.scala
+++ b/app/views/report.scala
@@ -160,78 +160,3 @@ def layout(filter: String, scores: Room.Scores, pending: PendingCounts)(using
body
)
)
-
-def form(form: Form[?], reqUser: Option[User] = None)(using ctx: Context) =
- Page(trans.site.reportAUser.txt())
- .css("bits.form3")
- .js(
- embedJsUnsafeLoadThen(
- """$('#form3-reason').on('change', function() {
- $('.report-reason').addClass('none').filter('.report-reason-' + this.value).removeClass('none');
- })"""
- )
- ):
- val defaultReason = form("reason").value.orElse(translatedReasonChoices.headOption.map(_._1))
- main(cls := "page-small box box-pad report")(
- h1(cls := "box__top")(trans.site.reportAUser()),
- postForm(
- cls := "form3",
- action := s"${routes.Report.create}${reqUser.so(u => "?username=" + u.username)}"
- )(
- div(cls := "form-group")(
- p(
- a(
- href := routes.Cms.lonePage(lila.core.id.CmsPageKey("report-faq")),
- dataIcon := Icon.InfoCircle,
- cls := "text"
- ):
- "Read more about Lichess reports"
- ),
- ctx.req.queryString
- .contains("postUrl")
- .option(
- p(
- "Here for DMCA or Intellectual Property Take Down Notice? ",
- a(href := lila.web.ui.contact.dmcaUrl)("Complete this form instead"),
- "."
- )
- )
- ),
- form3.globalError(form),
- form3.group(form("username"), trans.site.user(), klass = "field_to complete-parent"): f =>
- reqUser
- .map: user =>
- frag(userLink(user), form3.hidden(f, user.id.value.some))
- .getOrElse:
- div(form3.input(f, klass = "user-autocomplete")(dataTag := "span", autofocus))
- ,
- if ctx.req.queryString contains "reason"
- then form3.hidden(form("reason"))
- else
- form3.group(form("reason"), trans.site.reason()): f =>
- form3.select(f, translatedReasonChoices, trans.site.whatIsIheMatter.txt().some)
- ,
- form3.group(form("text"), trans.site.description(), help = descriptionHelp(~defaultReason).some):
- form3.textarea(_)(rows := 8)
- ,
- form3.actions(
- a(href := routes.Lobby.home)(trans.site.cancel()),
- form3.submit(trans.site.send())
- )
- )
- )
-
-private def descriptionHelp(default: String)(using ctx: Context) = frag:
- import lila.report.Reason.*
- val englishPlease = " Your report will be processed faster if written in English."
- translatedReasonChoices
- .map(_._1)
- .distinct
- .map: key =>
- span(cls := List(s"report-reason report-reason-$key" -> true, "none" -> (default != key))):
- if key == Cheat.key || key == Boost.key then trans.site.reportDescriptionHelp()
- else if key == Username.key then
- "Please explain briefly what about this username is offensive." + englishPlease
- else if key == Comm.key || key == Sexism.key then
- "Please explain briefly what that user said that was abusive." + englishPlease
- else "Please explain briefly what happened." + englishPlease
diff --git a/app/views/title.scala b/app/views/title.scala
index b6659d0ed035d..49a611075dbc5 100644
--- a/app/views/title.scala
+++ b/app/views/title.scala
@@ -34,7 +34,8 @@ object mod:
" ",
player.name
),
- p(player.ratingsStr)
+ p(player.ratingsStr),
+ p("Year of birth: ", player.year.fold("unknown")(_.toString))
)
modUi.show(req, data.user, fide, similar, modZone)
diff --git a/bin/mongodb/indexes.js b/bin/mongodb/indexes.js
index d8cd1e8f29262..9c0fe308eba62 100644
--- a/bin/mongodb/indexes.js
+++ b/bin/mongodb/indexes.js
@@ -202,6 +202,10 @@ db.relay.createIndex({ startsAt: 1 }, { partialFilterExpression: { startsAt: { $
db.relay.createIndex({ startedAt: 1 }, { partialFilterExpression: { startedAt: { $exists: 1 } } });
db.relay.createIndex({ 'sync.until': 1 }, { partialFilterExpression: { 'sync.until': { $exists: 1 } } });
db.relay.createIndex({ tourId: 1 });
+db.relay.createIndex(
+ { 'sync.upstream.roundIds': 1 },
+ { partialFilterExpression: { 'sync.upstream.roundIds': { $exists: 1 } } },
+);
db.oauth2_access_token.createIndex({ userId: 1 });
db.oauth2_access_token.createIndex({ expires: 1 }, { expireAfterSeconds: 0 });
db.cache.createIndex({ e: 1 }, { expireAfterSeconds: 0 });
diff --git a/bin/mongodb/real-name-migrate.js b/bin/mongodb/real-name-migrate.js
new file mode 100644
index 0000000000000..77c442073b87f
--- /dev/null
+++ b/bin/mongodb/real-name-migrate.js
@@ -0,0 +1,17 @@
+const sel = { $or: [{ 'profile.firstName': { $exists: true } }, { 'profile.lastName': { $exists: true } }] };
+
+db.user4
+ .find(sel, { profile: 1 })
+ .limit(1000)
+ .forEach(function (user) {
+ const fullName = ((user.profile.firstName || '') + ' ' + (user.profile.lastName || ''))
+ .trim()
+ .replace(/\s+/g, ' ');
+ db.user4.updateOne(
+ { _id: user._id },
+ {
+ $set: { 'profile.realName': fullName },
+ $unset: { 'profile.firstName': true, 'profile.lastName': true },
+ },
+ );
+ });
diff --git a/bin/mongodb/relay-dates-migrate.js b/bin/mongodb/relay-dates-migrate.js
new file mode 100644
index 0000000000000..93b78b7fa628f
--- /dev/null
+++ b/bin/mongodb/relay-dates-migrate.js
@@ -0,0 +1,32 @@
+// db.relay.aggregate([{$match:{tourId:'KNfeoWE'}},{$project:{name:1,at:{$ifNull:['$startsAt','$startedAt']}}},{$sort:{at:1}},{$group:{_id:null,at:{$push:'$at'}}},{$project:{start:{$first:'$at'},end:{$last:'$at'}}}])
+
+const fetchDates = tourId =>
+ db.relay
+ .aggregate([
+ { $match: { tourId } },
+ { $project: { name: 1, at: { $ifNull: ['$startsAt', '$startedAt'] } } },
+ { $sort: { at: 1 } },
+ { $group: { _id: null, at: { $push: '$at' } } },
+ { $project: { start: { $first: '$at' }, end: { $last: '$at' } } },
+ ])
+ .next();
+
+const cmp = (a, b) => (a ? a.getTime() : 0) == (b ? b.getTime() : 0);
+
+db.relay_tour
+ .find()
+ .sort({ $natural: -1 })
+ .limit(200)
+ .forEach(tour => {
+ const dates = fetchDates(tour._id);
+ if (dates) {
+ if (!cmp(dates?.start, tour.dates?.start)) {
+ console.log(tour._id + ' ' + tour.dates?.start + ' -> ' + dates.start);
+ db.relay_tour.updateOne({ _id: tour._id }, { $set: { 'dates.start': dates.start } });
+ }
+ if (!cmp(dates?.end, tour.dates?.end)) {
+ console.log(tour._id + ' ' + tour.dates?.end + ' -> ' + dates.end);
+ db.relay_tour.updateOne({ _id: tour._id }, { $set: { 'dates.end': dates.end } });
+ }
+ }
+ });
diff --git a/bin/mongodb/relay-lcc-migrate-2.js b/bin/mongodb/relay-lcc-migrate-2.js
new file mode 100644
index 0000000000000..f6ba297a92817
--- /dev/null
+++ b/bin/mongodb/relay-lcc-migrate-2.js
@@ -0,0 +1,31 @@
+const lccUrl = (id, round) => `https://view.livechesscloud.com/#${id}/${round}`;
+
+db.relay
+ .find({ 'sync.upstream.lcc': { $exists: 1 } })
+ .sort({ $natural: -1 })
+ .forEach(relay => {
+ db.relay.updateOne(
+ { _id: relay._id },
+ {
+ $set: {
+ 'sync.upstream': { url: lccUrl(relay.sync.upstream.lcc, relay.sync.upstream.round) },
+ },
+ },
+ );
+ });
+
+db.relay
+ .find({ 'sync.upstream.urls': { $exists: 1 } })
+ .sort({ $natural: -1 })
+ .forEach(relay => {
+ db.relay.updateOne(
+ { _id: relay._id },
+ {
+ $set: {
+ 'sync.upstream.urls': relay.sync.upstream.urls
+ .filter(u => !!u)
+ .map(url => (url.lcc ? lccUrl(url.lcc, url.round) : url.url)),
+ },
+ },
+ );
+ });
diff --git a/bin/mongodb/relay-tour-info-migrate.js b/bin/mongodb/relay-tour-info-migrate.js
new file mode 100644
index 0000000000000..dcff48b26fd6a
--- /dev/null
+++ b/bin/mongodb/relay-tour-info-migrate.js
@@ -0,0 +1,24 @@
+db.relay_tour
+ .find({
+ description: { $exists: true },
+ 'info.dates': { $exists: false },
+ 'info.format': { $exists: false },
+ 'info.tc': { $exists: false },
+ 'info.players': { $exists: false },
+ })
+ .forEach(function (tour) {
+ if (!tour.description.includes('|')) {
+ return;
+ }
+ const split = tour.description.split('|').map(x => x.trim());
+ const info = {};
+ const dates = split.shift();
+ if (dates && /\d/.test(dates)) info.dates = dates;
+ const format = split.shift();
+ if (format) info.format = format;
+ const tc = split.shift();
+ if (tc) info.tc = tc.replace(/time control/i, '').trim();
+ const players = split.shift();
+ if (players) info.players = players;
+ db.relay_tour.updateOne({ _id: tour._id }, { $set: { info: info } });
+ });
diff --git a/build.sbt b/build.sbt
index bb26114807e4c..3c3d522bba750 100644
--- a/build.sbt
+++ b/build.sbt
@@ -393,7 +393,7 @@ lazy val practice = module("practice",
lazy val playban = module("playban",
Seq(memo),
- Seq()
+ tests.bundle
)
lazy val push = module("push",
diff --git a/conf/routes b/conf/routes
index 8cc00de17428e..a4071969f2967 100644
--- a/conf/routes
+++ b/conf/routes
@@ -100,6 +100,7 @@ GET /@/:username/:filterName controllers.User.games(username: UserStr,
GET /@/:username controllers.User.show(username: UserStr)
GET /player/myself controllers.User.myself
GET /player/opponents controllers.User.opponents
+GET /player/search/:term controllers.User.search(term: String)
GET /player controllers.User.list
GET /player/top/:nb/:perfKey controllers.User.topNb(nb: Int, perfKey: PerfKey)
GET /api/player/top/:nb/:perfKey controllers.User.topNbApi(nb: Int, perfKey: PerfKey)
@@ -262,7 +263,6 @@ GET /broadcast/all-private controllers.RelayTour.allPrivate(p
GET /broadcast/:ts/$id<\w{8}> controllers.RelayTour.show(ts, id: RelayTourId)
GET /api/broadcast/$id<\w{8}> controllers.RelayTour.apiShow(id: RelayTourId)
GET /api/broadcast/$tourId<\w{8}>.pgn controllers.RelayTour.pgn(tourId: RelayTourId)
-GET /broadcast/$tourId<\w{8}>/stats controllers.RelayTour.stats(tourId: RelayTourId)
GET /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.edit(tourId: RelayTourId)
POST /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.update(tourId: RelayTourId)
POST /broadcast/$tourId<\w{8}>/delete controllers.RelayTour.delete(tourId: RelayTourId)
@@ -278,11 +278,12 @@ GET /broadcast/round/$roundId<\w{8}>/edit controllers.RelayRound.edit(roundI
POST /broadcast/round/$roundId<\w{8}>/edit controllers.RelayRound.update(roundId: RelayRoundId)
POST /broadcast/round/$roundId<\w{8}>/reset controllers.RelayRound.reset(roundId: RelayRoundId)
POST /broadcast/round/$roundId<\w{8}>/push controllers.RelayRound.push(roundId: RelayRoundId)
+GET /broadcast/round/$roundId<\w{8}>/stats controllers.RelayRound.stats(roundId: RelayRoundId)
POST /api/broadcast/round/$roundId<\w{8}>/push controllers.RelayRound.push(roundId: RelayRoundId)
-GET /broadcast/:ts/:rs/$roundId<\w{8}>.pgn controllers.RelayRound.pgn(ts, rs, roundId: StudyId)
+GET /broadcast/:ts/:rs/$roundId<\w{8}>.pgn controllers.RelayRound.pgn(ts, rs, roundId: RelayRoundId)
GET /broadcast/$roundId<\w{8}>/teams controllers.RelayRound.teamsView(roundId: RelayRoundId)
GET /broadcast/$tourId<\w{8}>/leaderboard controllers.RelayTour.leaderboardView(tourId: RelayTourId)
-GET /api/broadcast/round/$roundId<\w{8}>.pgn controllers.RelayRound.apiPgn(roundId: StudyId)
+GET /api/broadcast/round/$roundId<\w{8}>.pgn controllers.RelayRound.apiPgn(roundId: RelayRoundId)
GET /api/stream/broadcast/round/$roundId<\w{8}>.pgn controllers.RelayRound.stream(roundId: RelayRoundId)
GET /api/broadcast controllers.RelayTour.apiIndex
GET /api/broadcast/top controllers.RelayTour.apiTop(page: Int ?= 1)
@@ -598,15 +599,17 @@ GET /kaladin controllers.Irwin.kaladin
# Forum
GET /forum controllers.ForumCateg.index
GET /forum/search controllers.ForumPost.search(text ?= "", page: Int ?= 1)
-GET /forum/:categId controllers.ForumCateg.show(categId: ForumCategId, page: Int ?= 1)
-GET /forum/:categId/form controllers.ForumTopic.form(categId: ForumCategId)
-POST /forum/:categId/new controllers.ForumTopic.create(categId: ForumCategId)
+GET /forum/:categId controllers.ForumCateg.show(categId: ForumCategId, page: Int ?= 1)
+GET /forum/:categId/form controllers.ForumTopic.form(categId: ForumCategId)
+POST /forum/:categId/new controllers.ForumTopic.create(categId: ForumCategId)
+GET /forum/:categId/mod-feed controllers.ForumCateg.modFeed(categId: ForumCategId, page: Int ?= 1)
GET /forum/participants/:topicId controllers.ForumTopic.participants(topicId: ForumTopicId)
-GET /forum/:categId/:slug controllers.ForumTopic.show(categId: ForumCategId, slug, page: Int ?= 1)
-POST /forum/:categId/:slug/close controllers.ForumTopic.close(categId: ForumCategId, slug)
-POST /forum/:categId/:slug/sticky controllers.ForumTopic.sticky(categId: ForumCategId, slug)
-POST /forum/:categId/:slug/new controllers.ForumPost.create(categId: ForumCategId, slug, page: Int ?= 1)
+GET /forum/:categId/:slug controllers.ForumTopic.show(categId: ForumCategId, slug, page: Int ?= 1)
+POST /forum/:categId/:slug/close controllers.ForumTopic.close(categId: ForumCategId, slug)
+POST /forum/:categId/:slug/sticky controllers.ForumTopic.sticky(categId: ForumCategId, slug)
+POST /forum/:categId/:slug/new controllers.ForumPost.create(categId: ForumCategId, slug, page: Int ?= 1)
POST /forum/delete/:id controllers.ForumPost.delete(id: ForumPostId)
+POST /forum/relocate/:id controllers.ForumPost.relocate(id: ForumPostId)
POST /forum/:categId/react/:id/:reaction/:v controllers.ForumPost.react(categId: ForumCategId, id: ForumPostId, reaction, v: Boolean)
POST /forum/post/:id controllers.ForumPost.edit(id: ForumPostId)
GET /forum/redirect/post/:id controllers.ForumPost.redirect(id: ForumPostId)
@@ -722,6 +725,7 @@ GET /api/bulk-pairing controllers.BulkPairing.list
POST /api/bulk-pairing controllers.BulkPairing.create
GET /api/bulk-pairing/:id controllers.BulkPairing.show(id)
DELETE /api/bulk-pairing/:id controllers.BulkPairing.delete(id)
+GET /api/bulk-pairing/:id/games controllers.BulkPairing.games(id)
POST /api/bulk-pairing/:id/start-clocks controllers.BulkPairing.startClocks(id)
GET /api/games/user/:username controllers.Game.apiExportByUser(username: UserStr)
diff --git a/modules/analyse/src/main/ui/AnalyseI18n.scala b/modules/analyse/src/main/ui/AnalyseI18n.scala
index ce5ab5661c83c..3a7c9b891e514 100644
--- a/modules/analyse/src/main/ui/AnalyseI18n.scala
+++ b/modules/analyse/src/main/ui/AnalyseI18n.scala
@@ -300,6 +300,8 @@ final class GameAnalyseI18n(helpers: Helpers, board: AnalyseI18n):
site.promoteVariation,
site.makeMainLine,
site.deleteFromHere,
+ site.collapseVariations,
+ site.expandVariations,
site.forceVariation,
site.copyVariationPgn,
// practice (also uses checkmate, draw)
diff --git a/modules/api/src/main/Cli.scala b/modules/api/src/main/Cli.scala
index da551708e9062..ba31e32da96ff 100644
--- a/modules/api/src/main/Cli.scala
+++ b/modules/api/src/main/Cli.scala
@@ -5,8 +5,6 @@ import lila.web.AnnounceApi
final private[api] class Cli(
security: lila.security.Env,
- teamSearch: lila.teamSearch.Env,
- forumSearch: lila.forumSearch.Env,
tournament: lila.tournament.Env,
fishnet: lila.fishnet.Env,
study: lila.study.Env,
@@ -55,7 +53,6 @@ final private[api] class Cli(
private def processors =
security.cli.process
- .orElse(teamSearch.cli.process)
.orElse(tournament.cli.process)
.orElse(fishnet.cli.process)
.orElse(study.cli.process)
diff --git a/modules/api/src/main/Env.scala b/modules/api/src/main/Env.scala
index 633b653767d38..5c0e09c731ced 100644
--- a/modules/api/src/main/Env.scala
+++ b/modules/api/src/main/Env.scala
@@ -54,6 +54,7 @@ final class Env(
notifyEnv: lila.notify.Env,
appealApi: lila.appeal.AppealApi,
shutupEnv: lila.shutup.Env,
+ titleEnv: lila.title.Env,
modLogApi: lila.mod.ModlogApi,
activityWriteApi: lila.activity.ActivityWriteApi,
ublogApi: lila.ublog.UblogApi,
diff --git a/modules/api/src/main/PersonalDataExport.scala b/modules/api/src/main/PersonalDataExport.scala
index 5a1a3615cd231..12ac1a8e829fa 100644
--- a/modules/api/src/main/PersonalDataExport.scala
+++ b/modules/api/src/main/PersonalDataExport.scala
@@ -25,6 +25,7 @@ final class PersonalDataExport(
shutupEnv: lila.shutup.Env,
modLogApi: lila.mod.ModlogApi,
reportEnv: lila.report.Env,
+ titleEnv: lila.title.Env,
picfitUrl: lila.memo.PicfitUrl
)(using Executor, Materializer):
@@ -226,10 +227,27 @@ final class PersonalDataExport(
val timeoutMsg = m.details.so(_.split(":").drop(1).mkString(":").trim())
s"${textDate(m.date)}\n${timeoutMsg}$bigSep"
+ val titleRequests = Source.futureSource:
+ titleEnv.api
+ .allOf(user)
+ .map: reqs =>
+ Source:
+ List(textTitle("Title request")) ++ reqs.map: req =>
+ import req.data.*
+ s"""Title: $title
+ | Real name: $realName
+ | FIDE ID: ${fideId | "-"}
+ | Federation URL: ${federationUrl | "-"}
+ | Public: $public
+ | Coach: ${req.data.coach}
+ | Comment: ${comment | "-"}
+ | $bigSep""".stripMargin
+
val outro = Source(List(textTitle("End of data export.")))
List[Source[String, ?]](
intro,
+ titleRequests,
connections,
followedUsers,
streamer,
diff --git a/modules/api/src/main/TextLpvExpand.scala b/modules/api/src/main/TextLpvExpand.scala
index 7b1f88e3a1593..1bead818501e6 100644
--- a/modules/api/src/main/TextLpvExpand.scala
+++ b/modules/api/src/main/TextLpvExpand.scala
@@ -54,6 +54,7 @@ final class TextLpvExpand(
def allPgnsFromText(text: String): Fu[Map[String, LpvEmbed]] =
regex.blogPgnCandidatesRe
.findAllMatchIn(text)
+ .take(20)
.map(_.group(1))
.map:
case regex.gamePgnRe(url, id) => getPgn(GameId(id)).map(id -> _)
diff --git a/modules/api/src/main/UserApi.scala b/modules/api/src/main/UserApi.scala
index 25114a9fce2b1..0b1099aac33e2 100644
--- a/modules/api/src/main/UserApi.scala
+++ b/modules/api/src/main/UserApi.scala
@@ -10,6 +10,7 @@ import lila.core.perm.Granter
import lila.user.Trophy
import lila.rating.PerfType
import lila.core.perf.UserWithPerfs
+import lila.core.LightUser
final class UserApi(
jsonView: lila.user.JsonView,
@@ -27,27 +28,33 @@ final class UserApi(
trophyApi: lila.user.TrophyApi,
shieldApi: lila.tournament.TournamentShieldApi,
revolutionApi: lila.tournament.RevolutionApi,
+ challengeGranter: lila.challenge.ChallengeGranter,
net: NetConfig
)(using Executor, lila.core.i18n.Translator):
- def one(u: UserWithPerfs, joinedAt: Option[Instant] = None): JsObject = {
- addStreaming(jsonView.full(u.user, u.perfs.some, withProfile = true), u.id) ++
- Json.obj("url" -> makeUrl(s"@/${u.username}")) // for app BC
+ def one(u: UserWithPerfs | LightUser, joinedAt: Option[Instant] = None): JsObject = {
+ val (light, userJson) = u match
+ case u: UserWithPerfs => (u.user.light, jsonView.full(u.user, u.perfs.some, withProfile = false))
+ case u: LightUser => (u, Json.toJsObject(u))
+ addStreaming(userJson, light.id) ++
+ Json.obj("url" -> makeUrl(s"@/${light.name}")) // for app BC
}.add("joinedTeamAt", joinedAt)
def extended(
username: UserStr,
withFollows: Boolean,
- withTrophies: Boolean
+ withTrophies: Boolean,
+ withCanChallenge: Boolean
)(using Option[Me], Lang): Fu[Option[JsObject]] =
userApi.withPerfs(username).flatMapz {
- extended(_, withFollows, withTrophies).dmap(some)
+ extended(_, withFollows, withTrophies, withCanChallenge).dmap(some)
}
def extended(
u: User | UserWithPerfs,
withFollows: Boolean,
withTrophies: Boolean,
+ withCanChallenge: Boolean,
forWiki: Boolean = false
)(using as: Option[Me], lang: Lang): Fu[JsObject] =
u.match
@@ -69,6 +76,7 @@ final class UserApi(
gameCache.nbImportedBy(u.id),
(withTrophies && !u.lame).soFu(getTrophiesAndAwards(u.user)),
streamerApi.listed(u.user),
+ withCanChallenge.so(challengeGranter.mayChallenge(u.user).dmap(some)),
forWiki.soFu(userRepo.email(u.id))
).mapN:
(
@@ -83,6 +91,7 @@ final class UserApi(
nbImported,
trophiesAndAwards,
streamer,
+ canChallenge,
email
) =>
jsonView.full(u.user, u.perfs.some, withProfile = true) ++ {
@@ -112,6 +121,7 @@ final class UserApi(
.add("nbFollowing", following)
.add("nbFollowers", withFollows.option(0))
.add("trophies", trophiesAndAwards.map(trophiesJson))
+ .add("canChallenge", canChallenge)
.add(
"streamer",
streamer.map: s =>
diff --git a/modules/challenge/src/main/BSONHandlers.scala b/modules/challenge/src/main/BSONHandlers.scala
index 28109b9c1d9bd..6a01127ee7c7c 100644
--- a/modules/challenge/src/main/BSONHandlers.scala
+++ b/modules/challenge/src/main/BSONHandlers.scala
@@ -13,18 +13,14 @@ private object BSONHandlers:
import Challenge.*
import lila.game.BSONHandlers.given
- given BSONHandler[ColorChoice] = BSONIntegerHandler.as[ColorChoice](
- {
- case 1 => ColorChoice.White
- case 2 => ColorChoice.Black
- case _ => ColorChoice.Random
- },
- {
- case ColorChoice.White => 1
- case ColorChoice.Black => 2
- case ColorChoice.Random => 0
- }
- )
+ given BSONHandler[ColorChoice] =
+ val map = Map(
+ 0 -> ColorChoice.Random,
+ 1 -> ColorChoice.White,
+ 2 -> ColorChoice.Black
+ )
+ valueMapHandler[Int, ColorChoice](map)(i => map.find(_._2 == i).so(_._1))
+
given BSON[TimeControl] with
import chess.Clock
def reads(r: Reader) =
diff --git a/modules/challenge/src/main/ChallengeGranter.scala b/modules/challenge/src/main/ChallengeGranter.scala
index cae67882d0350..cce3747dbc1c1 100644
--- a/modules/challenge/src/main/ChallengeGranter.scala
+++ b/modules/challenge/src/main/ChallengeGranter.scala
@@ -42,38 +42,42 @@ final class ChallengeGranter(
val ratingThreshold = 300
- def isDenied(dest: User, perfKey: PerfKey)(using
+ def mayChallenge(dest: User)(using Executor)(using me: Option[Me]): Fu[Boolean] =
+ isDenied(dest, None).map(_.isEmpty)
+
+ // perfkey is None when we're not yet trying to challenge
+ def isDenied(dest: User, perfKey: Option[PerfKey])(using
Executor
)(using me: Option[Me]): Fu[Option[ChallengeDenied]] = me
- .fold[Fu[Option[ChallengeDenied.Reason]]] {
- prefApi.getChallenge(dest.id).map {
- case lila.core.pref.Challenge.ALWAYS => none
- case _ => YouAreAnon.some
- }
- } { from =>
- type Res = Option[ChallengeDenied.Reason]
- given Conversion[Res, Fu[Res]] = fuccess
- relationApi.fetchRelation(dest.id, from.userId).zip(prefApi.getChallenge(dest.id)).flatMap {
- case (Some(Block), _) => YouAreBlocked.some
- case (_, lila.core.pref.Challenge.NEVER) => TheyDontAcceptChallenges.some
- case (Some(Follow), _) => none // always accept from followed
- case (_, _) if from.marks.engine && !dest.marks.engine => YouAreBlocked.some
- case (_, lila.core.pref.Challenge.FRIEND) => FriendsOnly.some
- case (_, lila.core.pref.Challenge.RATING) =>
- userApi
- .perfsOf(from.value -> dest, primary = false)
- .map: (fromPerfs, destPerfs) =>
- if fromPerfs(perfKey).provisional || destPerfs(perfKey).provisional
- then RatingIsProvisional(perfKey).some
- else
- val diff =
- math.abs(fromPerfs(perfKey).intRating.value - destPerfs(perfKey).intRating.value)
- (diff > ratingThreshold).option(RatingOutsideRange(perfKey))
- case (_, lila.core.pref.Challenge.REGISTERED) => none
- case _ if from == dest => SelfChallenge.some
- case _ => none
- }
- }
+ .match
+ case None =>
+ prefApi.getChallenge(dest.id).map {
+ case lila.core.pref.Challenge.ALWAYS => none
+ case _ => YouAreAnon.some
+ }
+ case Some(from) =>
+ type Res = Option[ChallengeDenied.Reason]
+ given Conversion[Res, Fu[Res]] = fuccess
+ relationApi.fetchRelation(dest.id, from.userId).zip(prefApi.getChallenge(dest.id)).flatMap {
+ case (Some(Block), _) => YouAreBlocked.some
+ case (_, lila.core.pref.Challenge.NEVER) => TheyDontAcceptChallenges.some
+ case (Some(Follow), _) => none // always accept from followed
+ case (_, _) if from.marks.engine && !dest.marks.engine => YouAreBlocked.some
+ case (_, lila.core.pref.Challenge.FRIEND) => FriendsOnly.some
+ case (_, lila.core.pref.Challenge.RATING) =>
+ perfKey.so: pk =>
+ userApi
+ .perfsOf(from.value -> dest, primary = false)
+ .map: (fromPerfs, destPerfs) =>
+ if fromPerfs(pk).provisional || destPerfs(pk).provisional
+ then RatingIsProvisional(pk).some
+ else
+ val diff = math.abs(fromPerfs(pk).intRating.value - destPerfs(pk).intRating.value)
+ (diff > ratingThreshold).option(RatingOutsideRange(pk))
+ case (_, lila.core.pref.Challenge.REGISTERED) => none
+ case _ if from == dest => SelfChallenge.some
+ case _ => none
+ }
.map:
case None if dest.isBot && perfKey == PerfKey.ultraBullet => BotUltraBullet.some
case res => res
diff --git a/modules/challenge/src/main/ui/ChallengeUi.scala b/modules/challenge/src/main/ui/ChallengeUi.scala
index f49a310b9633f..604f877ba12f8 100644
--- a/modules/challenge/src/main/ui/ChallengeUi.scala
+++ b/modules/challenge/src/main/ui/ChallengeUi.scala
@@ -8,6 +8,7 @@ import ScalatagsTemplate.{ *, given }
import lila.core.LightUser
import lila.challenge.Challenge.Status
import lila.core.user.WithPerf
+import lila.core.game.GameRule
final class ChallengeUi(helpers: Helpers):
import helpers.{ *, given }
@@ -50,29 +51,50 @@ final class ChallengeUi(helpers: Helpers):
s"$speed$variant ${c.mode.name} Chess • $players"
private def details(c: Challenge, requestedColor: Option[Color])(using ctx: Context) =
- div(cls := "details")(
- div(
- cls := "variant",
- dataIcon := (if c.initialFen.isDefined then Icon.Feather else c.perfType.icon)
- )(
+ div(cls := "details-wrapper")(
+ div(cls := "content")(
div(
- variantLink(c.variant, c.perfType, c.initialFen),
- br,
- span(cls := "clock"):
- c.daysPerTurn
- .fold(shortClockName(c.clock.map(_.config))): days =>
- if days.value == 1 then trans.site.oneDay()
- else trans.site.nbDays.pluralSame(days.value)
+ cls := "variant",
+ dataIcon := (if c.initialFen.isDefined then Icon.Feather else c.perfType.icon)
+ )(
+ div(
+ variantLink(c.variant, c.perfType, c.initialFen),
+ br,
+ span(cls := "clock"):
+ c.daysPerTurn
+ .fold(shortClockName(c.clock.map(_.config))): days =>
+ if days.value == 1 then trans.site.oneDay()
+ else trans.site.nbDays.pluralSame(days.value)
+ )
+ ),
+ div(cls := "mode")(
+ c.open.fold(c.colorChoice.some)(_.colorFor(requestedColor)).map { colorChoice =>
+ frag(colorChoice.trans(), br)
+ },
+ modeName(c.mode)
)
),
- div(cls := "mode")(
- c.open.fold(c.colorChoice.some)(_.colorFor(requestedColor)).map { colorChoice =>
- frag(colorChoice.trans(), br)
- },
- modeName(c.mode)
+ div(cls := "rules")(
+ h2("Custom rules:"),
+ div(fragList(c.rules.toList.map(showRule), "/"))
)
)
+ private def showRule(r: GameRule) =
+ val (text, flair) = getRuleStyle(r);
+ div(cls := "challenge-rule")(
+ iconFlair(flair),
+ text
+ )
+
+ private def getRuleStyle(r: GameRule): (String, Flair) =
+ r match
+ case GameRule.noAbort => ("No abort", Flair("symbols.cross-mark"));
+ case GameRule.noRematch => ("No rematch", Flair("symbols.recycling-symbol"));
+ case GameRule.noGiveTime => ("No giving of time", Flair("objects.alarm-clock"));
+ case GameRule.noClaimWin => ("No claiming of win", Flair("objects.hourglass-done"));
+ case GameRule.noEarlyDraw => ("No early draw", Flair("people.handshake-light-skin-tone"));
+
def mine(
c: Challenge,
json: JsObject,
diff --git a/modules/coach/src/main/ui/CoachEditUi.scala b/modules/coach/src/main/ui/CoachEditUi.scala
index ec30e74edffdd..4a1e69e9b0894 100644
--- a/modules/coach/src/main/ui/CoachEditUi.scala
+++ b/modules/coach/src/main/ui/CoachEditUi.scala
@@ -47,9 +47,11 @@ final class CoachEditUi(helpers: Helpers, ui: CoachUi):
h3("TODO list before publishing your coach profile"),
ul
),
- div(cls := "picture_wrap")(
- ui.thumbnail(c, 250)(attr("draggable") := "true", cls := "drop-target"),
- div(label("Drag file or"), " ", form3.file.selectImage())
+ form3.fieldset("Picture", toggle = true.some)(
+ div(cls := "form-group coach-edit-picture")(
+ ui.thumbnail(c, 250)(attr("draggable") := "true", cls := "drop-target"),
+ div(label("Drag file or"), " ", form3.file.selectImage())
+ )
)
)
),
diff --git a/modules/common/src/main/Chronometer.scala b/modules/common/src/main/Chronometer.scala
index 0c8b4d37fbccf..6af6ec9ddae42 100644
--- a/modules/common/src/main/Chronometer.scala
+++ b/modules/common/src/main/Chronometer.scala
@@ -1,7 +1,5 @@
package lila.common
-import scala.util.Try
-
object Chronometer:
object futureExtension:
@@ -25,7 +23,7 @@ object Chronometer:
def chronometerTry = Chronometer.lapTry(fua)
def mon(path: lila.mon.TimerPath): Fu[A] = chronometer.mon(path).result
- def monTry(path: Try[A] => lila.mon.TimerPath): Fu[A] =
+ def monTry(path: scala.util.Try[A] => lila.mon.TimerPath): Fu[A] =
chronometerTry.mon(r => path(r)(lila.mon)).result
def monSuccess(path: lila.mon.type => Boolean => kamon.metric.Timer): Fu[A] =
chronometerTry
@@ -72,7 +70,7 @@ object Chronometer:
def showDuration: String = if millis >= 1 then s"$millis ms" else s"$micros micros"
- case class LapTry[A](result: Try[A], nanos: Long):
+ case class LapTry[A](result: scala.util.Try[A], nanos: Long):
def millis = (nanos / 1000000).toInt
case class FuLap[A](lap: Fu[Lap[A]]) extends AnyVal:
@@ -105,7 +103,7 @@ object Chronometer:
case class FuLapTry[A](lap: Fu[LapTry[A]]) extends AnyVal:
- def mon(path: Try[A] => kamon.metric.Timer) =
+ def mon(path: scala.util.Try[A] => kamon.metric.Timer) =
lap.dforeach: l =>
path(l.result).record(l.nanos)
this
diff --git a/modules/common/src/main/Form.scala b/modules/common/src/main/Form.scala
index 3387ee77f3917..f97116eec9bd4 100644
--- a/modules/common/src/main/Form.scala
+++ b/modules/common/src/main/Form.scala
@@ -50,6 +50,9 @@ object Form:
def numberInDouble(choices: Options[Double]) =
of[Double].verifying(mustBeOneOf(choices.map(_._1)), hasKey(choices, _))
+ def stringIn[A](choices: Seq[A])(key: A => String): Mapping[A] =
+ stringIn(choices.map(key).toSet).transform[A](str => choices.find(c => str == key(c)).get, key)
+
def id[Id](size: Int, fixed: Option[Id])(exists: Id => Fu[Boolean])(using
sr: StringRuntime[Id],
rs: SameRuntime[String, Id]
@@ -78,6 +81,10 @@ object Form:
val cleanText: Mapping[String] = of(cleanTextFormatter)
val cleanTextWithSymbols: Mapping[String] = of(cleanTextFormatterWithSymbols)
+ val nonEmptyOrSpace = V.Constraint[String]: t =>
+ if t.linesIterator.exists(_.stripLineEnd.exists(!_.isWhitespace)) then V.Valid
+ else V.Invalid(V.ValidationError("error.required"))
+
private def addLengthConstraints(m: Mapping[String], minLength: Int, maxLength: Int) =
(minLength, maxLength) match
case (min, Int.MaxValue) => m.verifying(Constraints.minLength(min))
@@ -87,9 +94,9 @@ object Form:
def cleanText(minLength: Int = 0, maxLength: Int = Int.MaxValue): Mapping[String] =
addLengthConstraints(cleanText, minLength, maxLength)
- val cleanNonEmptyText: Mapping[String] = cleanText.verifying(Constraints.nonEmpty)
+ val cleanNonEmptyText: Mapping[String] = cleanText.verifying(nonEmptyOrSpace)
def cleanNonEmptyText(minLength: Int = 0, maxLength: Int = Int.MaxValue): Mapping[String] =
- cleanText(minLength, maxLength).verifying(Constraints.nonEmpty)
+ cleanText(minLength, maxLength).verifying(nonEmptyOrSpace)
def cleanTextWithSymbols(minLength: Int = 0, maxLength: Int = Int.MaxValue): Mapping[String] =
addLengthConstraints(cleanTextWithSymbols, minLength, maxLength)
@@ -98,7 +105,7 @@ object Form:
cleanTextWithSymbols(minLength, maxLength).verifying(noSymbolsConstraint)
def cleanNoSymbolsAndNonEmptyText(minLength: Int = 0, maxLength: Int = Int.MaxValue): Mapping[String] =
- cleanNoSymbolsText(minLength, maxLength).verifying(Constraints.nonEmpty)
+ cleanNoSymbolsText(minLength, maxLength).verifying(nonEmptyOrSpace)
private val eventNameConstraint = Constraints.pattern(
regex = """[\p{L}\p{N}-\s:.,;'°ª\+]+""".r,
diff --git a/modules/common/src/main/HTTPRequest.scala b/modules/common/src/main/HTTPRequest.scala
index 0dc2bdee8bded..078e45b38c215 100644
--- a/modules/common/src/main/HTTPRequest.scala
+++ b/modules/common/src/main/HTTPRequest.scala
@@ -64,7 +64,7 @@ object HTTPRequest:
private val crawlerMatcher = UaMatcher:
// spiders/crawlers
- """Googlebot|AdsBot|Google-Read-Aloud|bingbot|BingPreview|facebookexternalhit|SemrushBot|AhrefsBot|PetalBot|Applebot|YandexBot|YandexAdNet|Twitterbot|Baiduspider|Amazonbot|Bytespider""" +
+ """Googlebot|AdsBot|Google-Read-Aloud|bingbot|BingPreview|facebookexternalhit|SemrushBot|AhrefsBot|PetalBot|Applebot|YandexBot|YandexAdNet|Twitterbot|Baiduspider|Amazonbot|Bytespider|yacybot""" +
// http libs
"""|HeadlessChrome|okhttp|axios|wget|curl|python-requests|aiohttp|commons-httpclient|python-urllib|python-httpx|Nessus"""
diff --git a/modules/common/src/main/Json.scala b/modules/common/src/main/Json.scala
index 56b24cdfc8026..a995bb66e7883 100644
--- a/modules/common/src/main/Json.scala
+++ b/modules/common/src/main/Json.scala
@@ -1,8 +1,8 @@
package lila.common
import play.api.libs.json.{ Json as PlayJson, * }
-
import scala.util.NotGiven
+import io.mola.galimatias.URL
object Json:
@@ -18,6 +18,8 @@ object Json:
given Writes[PerfKey] = pk => JsString(PerfKey.value(pk))
+ given Writes[URL] = url => JsString(url.toString)
+
given [A](using Show[A]): KeyWrites[A] with
def writeKey(key: A) = key.show
diff --git a/modules/common/src/main/mon.scala b/modules/common/src/main/mon.scala
index 6fcfe9420ec23..6c261978b7530 100644
--- a/modules/common/src/main/mon.scala
+++ b/modules/common/src/main/mon.scala
@@ -157,6 +157,9 @@ object mon:
object correspondenceEmail:
val emails = histogram("round.correspondenceEmail.emails").withoutTags()
val time = future("round.correspondenceEmail.time")
+ object farming:
+ val bot = counter("round.farming.bot").withoutTags()
+ val provisional = counter("round.farming.provisional").withoutTags()
object playban:
def outcome(out: String) = counter("playban.outcome").withTag("outcome", out)
object ban:
@@ -277,16 +280,20 @@ object mon:
def zoneSegment(name: String) = future("mod.zone.segment", name)
object relay:
private def by(official: Boolean) = if official then "official" else "user"
- private def relay(official: Boolean, slug: String) =
- tags("by" -> by(official), "slug" -> slug)
- def ongoing(official: Boolean) = gauge("relay.ongoing").withTag("by", by(official))
- def games(official: Boolean, slug: String) = gauge("relay.games").withTags(relay(official, slug))
- def moves(official: Boolean, slug: String) = counter("relay.moves").withTags(relay(official, slug))
- def fetchTime(official: Boolean, slug: String) = timer("relay.fetch.time").withTags(relay(official, slug))
- def syncTime(official: Boolean, slug: String) = timer("relay.sync.time").withTags(relay(official, slug))
- def tourCrowd(tourId: RelayTourId) = gauge("relay.tour.crowd").withTag("tour", tourId.value)
+ private def relay(official: Boolean, id: RelayTourId, slug: String) =
+ tags("by" -> by(official), "slug" -> s"$slug/$id")
+ def ongoing(official: Boolean) = gauge("relay.ongoing").withTag("by", by(official))
+ def games(official: Boolean, id: RelayTourId, slug: String) =
+ gauge("relay.games").withTags(relay(official, id, slug))
+ def moves(official: Boolean, id: RelayTourId, slug: String) =
+ counter("relay.moves").withTags(relay(official, id, slug))
+ def fetchTime(official: Boolean, id: RelayTourId, slug: String) =
+ timer("relay.fetch.time").withTags(relay(official, id, slug))
+ def syncTime(official: Boolean, id: RelayTourId, slug: String) =
+ timer("relay.sync.time").withTags(relay(official, id, slug))
def httpGet(host: String, proxy: Option[String]) =
future("relay.http.get", tags("host" -> host, "proxy" -> proxy.getOrElse("none")))
+ val dedup = counter("relay.fetch.dedup").withoutTags()
object bot:
def moves(username: String) = counter("bot.moves").withTag("name", username)
@@ -328,6 +335,9 @@ object mon:
object verifyMailApi:
def fetch(success: Boolean, ok: Boolean) =
timer("verifyMail.fetch").withTags(tags("success" -> successTag(success), "ok" -> ok))
+ object mailcheckApi:
+ def fetch(success: Boolean, ok: Boolean) =
+ timer("mailcheck.fetch").withTags(tags("success" -> successTag(success), "ok" -> ok))
def usersAlikeTime(field: String) = timer("security.usersAlike.time").withTag("field", field)
def usersAlikeFound(field: String) = histogram("security.usersAlike.found").withTag("field", field)
object hCaptcha:
diff --git a/modules/core/src/main/game/Game.scala b/modules/core/src/main/game/Game.scala
index 749eef64a3c59..b120971e5635d 100644
--- a/modules/core/src/main/game/Game.scala
+++ b/modules/core/src/main/game/Game.scala
@@ -73,7 +73,7 @@ case class Game(
def turnOf(c: Color): Boolean = c == turnColor
def turnOf(u: User): Boolean = player(u).exists(turnOf)
- def playedTurns = ply - startedAtPly
+ def playedTurns: Ply = ply - startedAtPly
def flagged = (status == Status.Outoftime).option(turnColor)
diff --git a/modules/core/src/main/team.scala b/modules/core/src/main/team.scala
index f5dc3d3bb5984..1b2dc5536440f 100644
--- a/modules/core/src/main/team.scala
+++ b/modules/core/src/main/team.scala
@@ -56,8 +56,6 @@ case class TeamData(
)
case class TeamCreate(team: TeamData)
case class TeamUpdate(team: TeamData, byMod: Boolean)(using val me: MyId)
-case class TeamDelete(id: TeamId)
-case class TeamDisable(id: TeamId)
case class JoinTeam(id: TeamId, userId: UserId)
case class IsLeader(id: TeamId, userId: UserId, promise: Promise[Boolean])
case class IsLeaderOf(leaderId: UserId, memberId: UserId, promise: Promise[Boolean])
diff --git a/modules/core/src/main/user.scala b/modules/core/src/main/user.scala
index 74f4cf4e69603..4566fcc78a67e 100644
--- a/modules/core/src/main/user.scala
+++ b/modules/core/src/main/user.scala
@@ -111,8 +111,7 @@ object user:
@Key("country") flag: Option[String] = None,
location: Option[String] = None,
bio: Option[String] = None,
- firstName: Option[String] = None,
- lastName: Option[String] = None,
+ realName: Option[String] = None,
fideRating: Option[Int] = None,
uscfRating: Option[Int] = None,
ecfRating: Option[Int] = None,
@@ -121,10 +120,7 @@ object user:
dsbRating: Option[Int] = None,
links: Option[String] = None
):
- def nonEmptyRealName =
- List(ne(firstName), ne(lastName)).flatten match
- case Nil => none
- case names => (names.mkString(" ")).some
+ def nonEmptyRealName = ne(realName)
def nonEmptyLocation = ne(location)
@@ -133,9 +129,10 @@ object user:
def isEmpty = completionPercent == 0
def completionPercent: Int =
- 100 * List(flag, bio, firstName, lastName).count(_.isDefined) / 4
+ 100 * List(flag, bio, realName).count(_.isDefined) / 4
private def ne(str: Option[String]) = str.filter(_.nonEmpty)
+
end Profile
object Profile:
diff --git a/modules/coreI18n/src/main/key.scala b/modules/coreI18n/src/main/key.scala
index 00da5602b6fc9..6f04bc38d9e2d 100644
--- a/modules/coreI18n/src/main/key.scala
+++ b/modules/coreI18n/src/main/key.scala
@@ -355,9 +355,6 @@ object I18nKey:
val `safeTournamentName`: I18nKey = "safeTournamentName"
val `inappropriateNameWarning`: I18nKey = "inappropriateNameWarning"
val `emptyTournamentName`: I18nKey = "emptyTournamentName"
- val `recommendNotTouching`: I18nKey = "recommendNotTouching"
- val `fewerPlayers`: I18nKey = "fewerPlayers"
- val `showAdvancedSettings`: I18nKey = "showAdvancedSettings"
val `makePrivateTournament`: I18nKey = "makePrivateTournament"
val `join`: I18nKey = "join"
val `withdraw`: I18nKey = "withdraw"
@@ -397,8 +394,7 @@ object I18nKey:
val `ifNoneLeaveEmpty`: I18nKey = "ifNoneLeaveEmpty"
val `profile`: I18nKey = "profile"
val `editProfile`: I18nKey = "editProfile"
- val `firstName`: I18nKey = "firstName"
- val `lastName`: I18nKey = "lastName"
+ val `realName`: I18nKey = "realName"
val `setFlair`: I18nKey = "setFlair"
val `flair`: I18nKey = "flair"
val `youCanHideFlair`: I18nKey = "youCanHideFlair"
@@ -441,7 +437,6 @@ object I18nKey:
val `reason`: I18nKey = "reason"
val `whatIsIheMatter`: I18nKey = "whatIsIheMatter"
val `cheat`: I18nKey = "cheat"
- val `insult`: I18nKey = "insult"
val `troll`: I18nKey = "troll"
val `ratingManipulation`: I18nKey = "ratingManipulation"
val `other`: I18nKey = "other"
@@ -478,6 +473,7 @@ object I18nKey:
val `slow`: I18nKey = "slow"
val `insideTheBoard`: I18nKey = "insideTheBoard"
val `outsideTheBoard`: I18nKey = "outsideTheBoard"
+ val `allSquaresOfTheBoard`: I18nKey = "allSquaresOfTheBoard"
val `onSlowGames`: I18nKey = "onSlowGames"
val `always`: I18nKey = "always"
val `never`: I18nKey = "never"
@@ -1671,8 +1667,6 @@ object I18nKey:
val `startDate`: I18nKey = "broadcast:startDate"
val `startDateHelp`: I18nKey = "broadcast:startDateHelp"
val `credits`: I18nKey = "broadcast:credits"
- val `broadcastUrl`: I18nKey = "broadcast:broadcastUrl"
- val `currentRoundUrl`: I18nKey = "broadcast:currentRoundUrl"
val `currentGameUrl`: I18nKey = "broadcast:currentGameUrl"
val `downloadAllRounds`: I18nKey = "broadcast:downloadAllRounds"
val `resetRound`: I18nKey = "broadcast:resetRound"
@@ -1687,6 +1681,15 @@ object I18nKey:
val `replacePlayerTags`: I18nKey = "broadcast:replacePlayerTags"
val `periodInSeconds`: I18nKey = "broadcast:periodInSeconds"
val `periodInSecondsHelp`: I18nKey = "broadcast:periodInSecondsHelp"
+ val `fideFederations`: I18nKey = "broadcast:fideFederations"
+ val `top10Rating`: I18nKey = "broadcast:top10Rating"
+ val `fidePlayers`: I18nKey = "broadcast:fidePlayers"
+ val `fidePlayerNotFound`: I18nKey = "broadcast:fidePlayerNotFound"
+ val `fideProfile`: I18nKey = "broadcast:fideProfile"
+ val `federation`: I18nKey = "broadcast:federation"
+ val `ageThisYear`: I18nKey = "broadcast:ageThisYear"
+ val `unrated`: I18nKey = "broadcast:unrated"
+ val `recentTournaments`: I18nKey = "broadcast:recentTournaments"
val `nbBroadcasts`: I18nKey = "broadcast:nbBroadcasts"
object streamer:
diff --git a/modules/fide/src/main/FidePlayer.scala b/modules/fide/src/main/FidePlayer.scala
index fb678935364ff..6e362bbc7481b 100644
--- a/modules/fide/src/main/FidePlayer.scala
+++ b/modules/fide/src/main/FidePlayer.scala
@@ -1,5 +1,6 @@
package lila.fide
+import scala.util.chaining.*
import chess.{ FideId, PlayerName, PlayerTitle }
import reactivemongo.api.bson.Macros.Annotations.Key
@@ -52,10 +53,15 @@ object FidePlayer:
.toList
.map(_.trim)
.filter(_.nonEmpty)
+ .pipe(trimTitle)
.distinct
.sorted
.mkString(" ")
+ private def trimTitle(name: List[String]): List[String] = name match
+ case title :: rest if PlayerTitle.get(title).isDefined => rest
+ case _ => name
+
val slugify: PlayerName => String =
val splitAccentRegex = "[\u0300-\u036f]".r
val multiSpaceRegex = """\s+""".r
diff --git a/modules/fide/src/main/ui/FideUi.scala b/modules/fide/src/main/ui/FideUi.scala
index f56dd7d6c271f..43089bd9c4e55 100644
--- a/modules/fide/src/main/ui/FideUi.scala
+++ b/modules/fide/src/main/ui/FideUi.scala
@@ -33,15 +33,15 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
td(if stats.top10Rating > 0 then stats.top10Rating else "-")
page("FIDE federations", "federations")(
cls := "fide-federations",
- boxTop(h1("FIDE federations")),
+ boxTop(h1(trans.broadcast.fideFederations())),
table(cls := "slist slist-pad")(
thead:
tr(
- th("Name"),
- th("Players"),
- th("Classic"),
- th("Rapid"),
- th("Blitz")
+ th(trans.site.name()),
+ th(trans.site.players()),
+ th(trans.site.classical()),
+ th(trans.site.rapid()),
+ th(trans.site.blitz())
)
,
tbody(cls := "infinite-scroll")(
@@ -72,9 +72,9 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
card(
name(),
frag(
- p("Rank", strong(stats.get.rank)),
- p("Top 10 rating", strong(stats.get.top10Rating)),
- p("Players", strong(stats.get.nbPlayers.localize))
+ p(trans.site.rank(), strong(stats.get.rank)),
+ p(trans.broadcast.top10Rating(), strong(stats.get.top10Rating)),
+ p(trans.site.players(), strong(stats.get.nbPlayers.localize))
)
)
),
@@ -104,7 +104,7 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
page("FIDE players", "players")(
cls := "fide-players",
boxTop(
- h1("FIDE players"),
+ h1(trans.broadcast.fidePlayers()),
div(cls := "box__top__actions"):
searchForm(query)
),
@@ -115,7 +115,7 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
page("FIDE player not found", "players")(
cls := "fide-players",
boxTop(
- h1("FIDE player not found"),
+ h1(trans.broadcast.fidePlayerNotFound()),
div(cls := "box__top__actions"):
searchForm("")
),
@@ -158,12 +158,12 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
table(cls := "slist slist-pad")(
thead:
tr(
- th(title),
+ th(trans.site.name()),
withFlag.option(th(iconTag(Icon.FlagOutline))),
- th("Classic"),
- th("Rapid"),
- th("Blitz"),
- th("Age this year")
+ th(trans.site.classical()),
+ th(trans.site.rapid()),
+ th(trans.site.blitz()),
+ th(trans.broadcast.ageThisYear())
)
,
tbody(cls := "infinite-scroll")(
@@ -194,7 +194,7 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
div(cls := "fide-cards fide-player__cards")(
player.fed.map: fed =>
card(
- "Federation",
+ trans.broadcast.federation(),
if fed == Federation.idNone then "None"
else
a(cls := "fide-player__federation", href := routes.Fide.federation(Federation.idToSlug(fed)))(
@@ -203,16 +203,16 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
)
),
card(
- "FIDE profile",
+ trans.broadcast.fideProfile(),
a(href := s"https://ratings.fide.com/profile/${player.id}")(player.id)
),
card(
- "Age this year",
+ trans.broadcast.ageThisYear(),
player.age
),
tcTrans.map: (tc, name) =>
- card(name(), player.ratingOf(tc).fold("Unrated")(_.toString)),
+ card(name(), player.ratingOf(tc).fold(trans.broadcast.unrated())(_.toString)),
),
tours.map: tours =>
- div(cls := "fide-player__tours")(h2("Recent tournaments"), tours)
+ div(cls := "fide-player__tours")(h2(trans.broadcast.recentTournaments()), tours)
)
diff --git a/modules/forum/src/main/ForumForm.scala b/modules/forum/src/main/ForumForm.scala
index e6e014dd0fe8e..3b35386e3977d 100644
--- a/modules/forum/src/main/ForumForm.scala
+++ b/modules/forum/src/main/ForumForm.scala
@@ -3,7 +3,7 @@ package lila.forum
import play.api.data.*
import play.api.data.Forms.*
-import lila.common.Form.cleanText
+import lila.common.Form.{ cleanText, into }
import lila.common.Form.given
final private[forum] class ForumForm(
@@ -42,14 +42,17 @@ final private[forum] class ForumForm(
val deleteWithReason = Form:
single("reason" -> optional(nonEmptyText))
+ val relocateTo = Form:
+ single("categ" -> nonEmptyText.into[ForumCategId])
+
private def userTextMapping(inOwnTeam: Boolean, previousText: Option[String] = None)(using me: Me) =
- cleanText(minLength = 3)
+ cleanText(minLength = 3, 20_000)
.verifying(
"You have reached the daily maximum for links in forum posts.",
t => inOwnTeam || promotion.test(me, t, previousText)
)
- val diagnostic = Form(single("text" -> nonEmptyText(maxLength = 100000)))
+ val diagnostic = Form(single("text" -> nonEmptyText(maxLength = 100_000)))
object ForumForm:
diff --git a/modules/forum/src/main/ForumPaginator.scala b/modules/forum/src/main/ForumPaginator.scala
index 4165fb7666ae3..c960b73357db2 100644
--- a/modules/forum/src/main/ForumPaginator.scala
+++ b/modules/forum/src/main/ForumPaginator.scala
@@ -15,6 +15,18 @@ final class ForumPaginator(
import BSONHandlers.given
+ def recent(categ: ForumCateg, page: Int): Fu[Paginator[ForumPost]] =
+ Paginator(
+ Adapter[ForumPost](
+ collection = postRepo.coll,
+ selector = postRepo.selectCateg(categ.id),
+ projection = none,
+ sort = $sort.createdDesc
+ ).withLotsOfResults,
+ currentPage = page,
+ maxPerPage = MaxPerPage(30)
+ )
+
def topicPosts(topic: ForumTopic, page: Int)(using me: Option[Me])(using
netDomain: NetDomain
): Fu[Paginator[ForumPost.WithFrag]] =
@@ -23,7 +35,7 @@ final class ForumPaginator(
collection = postRepo.coll,
selector = postRepo.forUser(me).selectTopic(topic.id),
projection = none,
- sort = postRepo.sortQuery
+ sort = $sort.createdAsc
).mapFutureList(textExpand.manyPosts),
currentPage = page,
maxPerPage = config.postMaxPerPage
diff --git a/modules/forum/src/main/ForumPostApi.scala b/modules/forum/src/main/ForumPostApi.scala
index 77dae8e497674..6a30f8a235d1a 100644
--- a/modules/forum/src/main/ForumPostApi.scala
+++ b/modules/forum/src/main/ForumPostApi.scala
@@ -132,11 +132,11 @@ final class ForumPostApi(
react(categId, postId, reaction.key, false)
}
- def views(posts: List[ForumPost]): Fu[List[PostView]] =
+ def views(posts: Seq[ForumPost]): Fu[List[PostView]] =
for
topics <- topicRepo.coll.byIds[ForumTopic, ForumTopicId](posts.map(_.topicId).distinct)
categs <- categRepo.coll.byIds[ForumCateg, ForumCategId](topics.map(_.categId).distinct)
- yield posts.flatMap: post =>
+ yield posts.toList.flatMap: post =>
for
topic <- topics.find(_.id == post.topicId)
categ <- categs.find(_.id == topic.categId)
diff --git a/modules/forum/src/main/ForumPostRepo.scala b/modules/forum/src/main/ForumPostRepo.scala
index e2e253e0d4a28..8317234e71ffc 100644
--- a/modules/forum/src/main/ForumPostRepo.scala
+++ b/modules/forum/src/main/ForumPostRepo.scala
@@ -102,8 +102,6 @@ final class ForumPostRepo(val coll: Coll, filter: Filter = Safe)(using Executor)
)
)
- def sortQuery = $sort.createdAsc
-
def idsByTopicId(topicId: ForumTopicId): Fu[List[ForumPostId]] =
coll.distinctEasy[ForumPostId, List]("_id", $doc("topicId" -> topicId), _.sec)
diff --git a/modules/forum/src/main/ForumTopicApi.scala b/modules/forum/src/main/ForumTopicApi.scala
index 70721331e6915..5fe7245bcecb0 100644
--- a/modules/forum/src/main/ForumTopicApi.scala
+++ b/modules/forum/src/main/ForumTopicApi.scala
@@ -39,11 +39,7 @@ final private class ForumTopicApi(
.flatMapz: topic =>
show(categId, slug, topic.lastPage(config.postMaxPerPage))
- def show(
- categId: ForumCategId,
- slug: String,
- page: Int
- )(using
+ def show(categId: ForumCategId, slug: String, page: Int)(using
NetDomain
)(using me: Option[Me]): Fu[Option[(ForumCateg, ForumTopic, Paginator[ForumPost.WithFrag])]] =
for
@@ -107,9 +103,9 @@ final private class ForumTopicApi(
case Some(dup) => fuccess(dup)
case None =>
for
- _ <- postRepo.coll.insert.one(post)
_ <- topicRepo.coll.insert.one(topic.withPost(post))
_ <- categRepo.coll.update.one($id(categ.id), categ.withPost(topic, post))
+ _ <- postRepo.coll.insert.one(post)
yield
promotion.save(me, post.text)
val text = s"${topic.name} ${post.text}"
@@ -155,9 +151,9 @@ final private class ForumTopicApi(
}
private def makeNewTopic(categ: ForumCateg, topic: ForumTopic, post: ForumPost) = for
- _ <- postRepo.coll.insert.one(post)
_ <- topicRepo.coll.insert.one(topic.withPost(post))
_ <- categRepo.coll.update.one($id(categ.id), categ.withPost(topic, post))
+ _ <- postRepo.coll.insert.one(post)
yield Bus.pub(CreatePost(post.mini))
def getSticky(categ: ForumCateg, forUser: Option[User]): Fu[List[TopicView]] =
@@ -219,3 +215,9 @@ final private class ForumTopicApi(
_ <- categRepo.coll.update
.one($id(cat.id), cat.withoutTopic(topic, lastPostId, lastPostIdTroll))
yield ()
+
+ def relocate(topic: ForumTopicId, to: ForumCategId)(using Me): Funit =
+ for
+ _ <- topicRepo.coll.update.one($id(topic), $set("categId" -> to))
+ _ <- postRepo.coll.update.one($doc("topicId" -> topic), $set("categId" -> to))
+ yield ()
diff --git a/modules/forum/src/main/model.scala b/modules/forum/src/main/model.scala
index 5f83951c19812..e97097d7cf0b8 100644
--- a/modules/forum/src/main/model.scala
+++ b/modules/forum/src/main/model.scala
@@ -31,11 +31,7 @@ case class TopicView(
def name = topic.name
def createdAt = topic.createdAt
-case class PostView(
- post: ForumPost,
- topic: ForumTopic,
- categ: ForumCateg
-):
+case class PostView(post: ForumPost, topic: ForumTopic, categ: ForumCateg):
def show = post.showUserIdOrAuthor + " @ " + topic.name + " - " + post.text.take(80)
def logFormatted = "%s / %s#%s / %s".format(categ.name, topic.name, post.number, post.text)
diff --git a/modules/forum/src/main/ui/CategUi.scala b/modules/forum/src/main/ui/CategUi.scala
index 0e7ab0d3095bb..2e5f8d65e37f3 100644
--- a/modules/forum/src/main/ui/CategUi.scala
+++ b/modules/forum/src/main/ui/CategUi.scala
@@ -40,15 +40,6 @@ final class CategUi(helpers: Helpers, bits: ForumBits):
stickyPosts: List[TopicView]
)(using Context) =
- val newTopicButton = canWrite.option(
- a(
- href := routes.ForumTopic.form(categ.id),
- cls := "button button-empty button-green text",
- dataIcon := Icon.Pencil
- ):
- trans.site.createANewTopic()
- )
-
def showTopic(sticky: Boolean)(topic: TopicView) =
tr(cls := List("sticky" -> sticky))(
td(cls := "subject")(
@@ -86,8 +77,23 @@ final class CategUi(helpers: Helpers, bits: ForumBits):
),
categ.team.fold(frag(categ.name))(teamLink(_, true))
),
- div(cls := "box__top__actions"):
- newTopicButton
+ div(cls := "box__top__actions")(
+ Granter
+ .opt(_.ModerateForum)
+ .option(
+ a(
+ href := routes.ForumCateg.modFeed(categ.id),
+ cls := "button button-empty text"
+ )("Mod feed")
+ ),
+ canWrite.option(
+ a(
+ href := routes.ForumTopic.form(categ.id),
+ cls := "button button-empty button-green text",
+ dataIcon := Icon.Pencil
+ )(trans.site.createANewTopic())
+ )
+ )
),
table(cls := "topics slist slist-pad")(
thead(
@@ -131,3 +137,38 @@ final class CategUi(helpers: Helpers, bits: ForumBits):
td(a(href := postUrl)(momentFromNow(post.createdAt)), br, trans.site.by(bits.authorLink(post)))
)
)
+
+ def modFeed(
+ categ: lila.forum.ForumCateg,
+ posts: Paginator[PostView]
+ )(using Context) =
+ val pager = paginationByQuery(routes.ForumCateg.modFeed(categ.id, 1), posts, showPost = true)
+ Page(categ.name)
+ .css("bits.forum")
+ .csp(_.withInlineIconFont)
+ .js(infiniteScrollEsmInit):
+ main(cls := "forum forum-mod-feed box")(
+ boxTop(
+ h1(
+ a(
+ href := routes.ForumCateg.show(categ.id),
+ dataIcon := Icon.LessThan,
+ cls := "text"
+ )(categ.name),
+ " mod feed"
+ )
+ ),
+ table(cls := "slist slist-pad")(
+ thead(tr(th("User"), th("Topic"), th("Post"), th("Date"))),
+ tbody(cls := "infinite-scroll")(
+ posts.currentPageResults.map: p =>
+ tr(cls := "paginated")(
+ td(userIdLink(p.post.userId)),
+ td(a(href := routes.ForumTopic.show(p.categ.id, p.topic.slug))(p.topic.name)),
+ td(shorten(p.post.text, 400)),
+ td(a(href := routes.ForumPost.redirect(p.post.id))(momentFromNow(p.post.createdAt)))
+ ),
+ pagerNextTable(posts, np => routes.ForumCateg.modFeed(categ.id, np).url)
+ )
+ )
+ )
diff --git a/modules/forum/src/main/ui/PostUi.scala b/modules/forum/src/main/ui/PostUi.scala
index 907ba30f38667..2de81c2424e93 100644
--- a/modules/forum/src/main/ui/PostUi.scala
+++ b/modules/forum/src/main/ui/PostUi.scala
@@ -55,6 +55,14 @@ final class PostUi(helpers: Helpers, bits: ForumBits):
).some
else
frag(
+ (canModCateg && post.number == 1).option:
+ a(
+ cls := "mod mod-relocate button button-empty",
+ href := routes.ForumPost.relocate(post.id),
+ dataIcon := Icon.Forward,
+ title := "Relocate"
+ )
+ ,
if canModCateg || topic.isUblogAuthor(me) then
a(
cls := "mod delete button button-empty",
diff --git a/modules/forum/src/main/ui/TopicUi.scala b/modules/forum/src/main/ui/TopicUi.scala
index 782832e9be1d5..fac7ecad7833c 100644
--- a/modules/forum/src/main/ui/TopicUi.scala
+++ b/modules/forum/src/main/ui/TopicUi.scala
@@ -167,7 +167,8 @@ final class TopicUi(helpers: Helpers, bits: ForumBits, postUi: PostUi)(
)
)
),
- (canModCateg || ctx.me.exists(topic.isAuthor)).option(deleteModal)
+ (canModCateg || ctx.me.exists(topic.isAuthor)).option(deleteModal),
+ canModCateg.option(relocateModal(categ))
)
),
formWithCaptcha.map: (form, captcha) =>
@@ -253,3 +254,28 @@ final class TopicUi(helpers: Helpers, bits: ForumBits, postUi: PostUi)(
)
)
)
+
+ private val relocateTo = List(
+ "general-chess-discussion" -> "General Chess Discussion",
+ "lichess-feedback" -> "Lichess Feedback",
+ "game-analysis" -> "Game Analysis",
+ "off-topic-discussion" -> "Off-Topic Discussion"
+ )
+
+ private def relocateModal(from: lila.forum.ForumCateg) =
+ div(cls := "forum-relocate-modal none")(
+ p("Move the entire thread to another forum"),
+ st.form(method := "post", cls := "form3")(
+ st.select(
+ name := "categ",
+ cls := "form-control"
+ )(
+ relocateTo.collect:
+ case (slug, name) if slug != from.id.value => st.option(value := slug)(name)
+ ),
+ form3.actions(
+ button(cls := "cancel button button-empty", tpe := "button")("Cancel"),
+ form3.submit(frag("Relocate the thread"))(cls := "button-red")
+ )
+ )
+ )
diff --git a/modules/forumSearch/src/main/Env.scala b/modules/forumSearch/src/main/Env.scala
index d9b08fa2af131..9cf51e151072a 100644
--- a/modules/forumSearch/src/main/Env.scala
+++ b/modules/forumSearch/src/main/Env.scala
@@ -13,11 +13,7 @@ import lila.search.spec.Query
@Module
private class ForumSearchConfig(@ConfigName("paginator.max_per_page") val maxPerPage: MaxPerPage)
-final class Env(
- appConfig: Configuration,
- postApi: lila.core.forum.ForumPostApi,
- client: SearchClient
-)(using Executor):
+final class Env(appConfig: Configuration, client: SearchClient)(using Executor):
private val config = appConfig.get[ForumSearchConfig]("forumSearch")(AutoConfig.loader)
diff --git a/modules/forumSearch/src/main/package.scala b/modules/forumSearch/src/main/package.scala
index 3604898cd0680..d4301e043437d 100644
--- a/modules/forumSearch/src/main/package.scala
+++ b/modules/forumSearch/src/main/package.scala
@@ -1,7 +1,6 @@
package lila.forumSearch
export lila.core.lilaism.Lilaism.{ *, given }
-export lila.common.extensions.*
private val logger = lila.log("forumSearch")
diff --git a/modules/mailer/src/main/AutomaticEmail.scala b/modules/mailer/src/main/AutomaticEmail.scala
index ac87b0259fa05..43219ce0e3893 100644
--- a/modules/mailer/src/main/AutomaticEmail.scala
+++ b/modules/mailer/src/main/AutomaticEmail.scala
@@ -46,16 +46,15 @@ The Lichess team"""
import lila.core.i18n.I18nKey
s"""${I18nKey.onboarding.welcome.txt()}\n${I18nKey.site.lichessPatronInfo.txt()}"""
- def onTitleSet(username: UserStr, title: chess.PlayerTitle, public: Boolean): Funit = {
+ def onTitleSet(username: UserStr, title: chess.PlayerTitle): Funit = {
for
user <- userApi.byId(username).orFail(s"No such user $username")
emailOption <- userApi.email(user.id)
body = alsoSendAsPrivateMessage(user): _ =>
- val visible = public.so(s"""It is now visible on your profile page: $baseUrl/@/${user.username}.""")
s"""Hello,
Thank you for confirming your $title title on Lichess.
-$visible
+It is now visible on your profile page: $baseUrl/@/${user.username}.
$regards
"""
diff --git a/modules/msg/src/main/MsgContact.scala b/modules/msg/src/main/MsgContact.scala
index f81d3151d12dd..56dea3465fa51 100644
--- a/modules/msg/src/main/MsgContact.scala
+++ b/modules/msg/src/main/MsgContact.scala
@@ -5,6 +5,8 @@ import reactivemongo.api.bson.*
import lila.core.user.UserMarks
import lila.db.dsl.{ *, given }
+import lila.core.perm.Permission
+import lila.core.perm.Granter
private case class Contact(
@Key("_id") id: UserId,
@@ -13,13 +15,14 @@ private case class Contact(
roles: Option[List[String]],
createdAt: Instant
):
- def isKid = ~kid
- def isTroll = marks.exists(_.troll)
- def isVerified = roles.exists(_ contains "ROLE_VERIFIED")
- def isApiHog = roles.exists(_ contains "ROLE_API_HOG")
- def isDaysOld(days: Int) = createdAt.isBefore(nowInstant.minusDays(days))
- def isHoursOld(hours: Int) = createdAt.isBefore(nowInstant.minusHours(hours))
- def isLichess = id.is(UserId.lichess)
+ def isKid = ~kid
+ def isTroll = marks.exists(_.troll)
+ def isVerified = roles.exists(_ contains "ROLE_VERIFIED")
+ def isApiHog = roles.exists(_ contains "ROLE_API_HOG")
+ def isDaysOld(days: Int) = createdAt.isBefore(nowInstant.minusDays(days))
+ def isHoursOld(hours: Int) = createdAt.isBefore(nowInstant.minusHours(hours))
+ def isLichess = id.is(UserId.lichess)
+ def isGranted(perm: Permission.Selector) = Granter.ofDbKeys(perm, ~roles)
private case class Contacts(orig: Contact, dest: Contact):
def hasKid = orig.isKid || dest.isKid
diff --git a/modules/msg/src/main/MsgPreset.scala b/modules/msg/src/main/MsgPreset.scala
index bf87020b5595a..7a412df27a9dc 100644
--- a/modules/msg/src/main/MsgPreset.scala
+++ b/modules/msg/src/main/MsgPreset.scala
@@ -9,15 +9,20 @@ object MsgPreset:
import lila.core.msg.{ MsgPreset as Msg }
+ private val baseUrl = "https://lichess.org"
+
def maxFollow(username: UserName, max: Int) =
Msg(
name = "Follow limit reached!",
text = s"""Sorry, you can't follow more than $max players on Lichess.
-To follow new players, you must first unfollow some on https://lichess.org/@/$username/following.
+To follow new players, you must first unfollow some on $baseUrl/@/$username/following.
Thank you for your understanding."""
)
+ def forumRelocation(title: String, newUrl: String) =
+ s"""A moderator has moved your post "$title" to a different subforum. You can find it here: $baseUrl$newUrl."""
+
object forumDeletion:
val presets = List(
@@ -30,12 +35,12 @@ Thank you for your understanding."""
def byModerator = compose("A moderator")
- def byTeamLeader(forumId: ForumCategId) = compose(s"A team leader of https://lichess.org/forum/$forumId")
+ def byTeamLeader(forumId: ForumCategId) = compose(s"A team leader of $baseUrl/forum/$forumId")
def byBlogAuthor(user: UserName) = compose(by = s"The community blog author $user")
private def compose(by: String)(reason: String, forumPost: String) =
- s"""$by deleted the following of your posts for this reason: $reason. Please read Lichess' Forum-Etiquette: https://lichess.org/page/forum-etiquette
+ s"""$by deleted the following of your posts for this reason: $reason. Please read Lichess' Forum-Etiquette: $baseUrl/page/forum-etiquette
----
$forumPost
"""
diff --git a/modules/msg/src/main/MsgSecurity.scala b/modules/msg/src/main/MsgSecurity.scala
index 3b166ac368271..e28ee1a2ff6bc 100644
--- a/modules/msg/src/main/MsgSecurity.scala
+++ b/modules/msg/src/main/MsgSecurity.scala
@@ -78,7 +78,8 @@ final private class MsgSecurity(
.getOrElse(fuccess(Ok))
.flatMap:
case Troll =>
- destFollowsOrig(contacts).dmap:
+ (fuccess(contacts.any(_.isGranted(_.PublicMod))) >>|
+ destFollowsOrig(contacts)).dmap:
if _ then TrollFriend else Troll
case mute: Mute =>
destFollowsOrig(contacts).dmap:
@@ -141,15 +142,17 @@ final private class MsgSecurity(
contactApi.contacts(orig, dest).flatMapz { post(_, isNew) }
def post(contacts: Contacts, isNew: Boolean): Fu[Boolean] =
- fuccess(!contacts.dest.isLichess && !contacts.any(_.marks.exists(_.isolate))) >>& {
- fuccess(Granter.ofDbKeys(_.PublicMod, ~contacts.orig.roles)) >>| {
+ (
+ !contacts.dest.isLichess &&
+ (!contacts.any(_.marks.exists(_.isolate)) || contacts.any(_.isGranted(_.Shadowban)))
+ ).so:
+ fuccess(contacts.orig.isGranted(_.PublicMod)) >>| {
relationApi.fetchBlocks(contacts.dest.id, contacts.orig.id).not >>&
(create(contacts) >>| reply(contacts)) >>&
chatPanicAllowed(contacts.orig.id)(userApi.byId) >>&
kidCheck(contacts, isNew) >>&
userCache.getBotIds.map { botIds => !contacts.userIds.exists(botIds.contains) }
}
- }
private def create(contacts: Contacts): Fu[Boolean] =
prefApi.getMessage(contacts.dest.id).flatMap {
diff --git a/modules/opening/src/main/OpeningTree.scala b/modules/opening/src/main/OpeningTree.scala
index 914289bafb358..98371cac20909 100644
--- a/modules/opening/src/main/OpeningTree.scala
+++ b/modules/opening/src/main/OpeningTree.scala
@@ -27,7 +27,7 @@ object OpeningTree:
lazy val compute: OpeningTree =
OpeningDb.shortestLines.values
- .map { op =>
+ .map: op =>
val sections = NameSection.sectionsOf(op.name)
sections.toList.mapWithIndex: (name, i) =>
(
@@ -36,7 +36,6 @@ object OpeningTree:
OpeningKey.fromName(OpeningName(sections.take(i + 1).mkString("_")))
)
)
- }
.toList
.foldLeft(emptyNode)(_.update(_))
.toTree
diff --git a/modules/plan/src/main/ui/PlanUi.scala b/modules/plan/src/main/ui/PlanUi.scala
index ee745b61324b6..5dcb2afb87cb8 100644
--- a/modules/plan/src/main/ui/PlanUi.scala
+++ b/modules/plan/src/main/ui/PlanUi.scala
@@ -32,18 +32,19 @@ final class PlanUi(helpers: Helpers)(contactEmail: EmailAddress):
ctx.isAuth.option(
frag(
stripeScript,
- frag(
- // gotta load the paypal SDK twice, for onetime and subscription :facepalm:
- // https://stackoverflow.com/questions/69024268/how-can-i-show-a-paypal-smart-subscription-button-and-a-paypal-smart-capture-but/69024269
- script(
- src := s"https://www.paypal.com/sdk/js?client-id=${payPalPublicKey}¤cy=${pricing.currency}$localeParam",
- namespaceAttr := "paypalOrder"
- ),
- script(
- src := s"https://www.paypal.com/sdk/js?client-id=${payPalPublicKey}&vault=true&intent=subscription¤cy=${pricing.currency}$localeParam",
- namespaceAttr := "paypalSubscription"
+ pricing.payPalSupportsCurrency.option:
+ frag(
+ // gotta load the paypal SDK twice, for onetime and subscription :facepalm:
+ // https://stackoverflow.com/questions/69024268/how-can-i-show-a-paypal-smart-subscription-button-and-a-paypal-smart-capture-but/69024269
+ script(
+ src := s"https://www.paypal.com/sdk/js?client-id=${payPalPublicKey}¤cy=${pricing.currency}$localeParam",
+ namespaceAttr := "paypalOrder"
+ ),
+ script(
+ src := s"https://www.paypal.com/sdk/js?client-id=${payPalPublicKey}&vault=true&intent=subscription¤cy=${pricing.currency}$localeParam",
+ namespaceAttr := "paypalSubscription"
+ )
)
- )
)
)
.js(ctx.isAuth.option(embedJsUnsafeLoadThen(s"""checkoutStart("$stripePublicKey", $pricingJson)""")))
diff --git a/modules/playban/src/main/PlaybanApi.scala b/modules/playban/src/main/PlaybanApi.scala
index 1c160d825b0ca..4535da9676ced 100644
--- a/modules/playban/src/main/PlaybanApi.scala
+++ b/modules/playban/src/main/PlaybanApi.scala
@@ -2,10 +2,10 @@ package lila.playban
import chess.{ Centis, Color, Status }
import reactivemongo.api.bson.*
+import scalalib.model.Days
import lila.common.{ Bus, Uptime }
import lila.db.dsl.{ *, given }
-
import lila.core.msg.{ MsgApi, MsgPreset }
import lila.core.game.Source
import lila.core.playban.RageSit as RageSitCounter
@@ -89,21 +89,18 @@ final class PlaybanApi(
game
.player(flaggerColor)
.userId
- .ifTrue {
+ .ifTrue:
~(for
movetimes <- gameApi.computeMoveTimes(game, flaggerColor)
lastMovetime <- movetimes.lastOption
limit <- unreasonableTime
yield lastMovetime.toSeconds >= limit)
- }
- .map { userId =>
+ .map: userId =>
(save(Outcome.SitMoving, userId, RageSit.imbalanceInc(game, flaggerColor), game.source) >>
propagateSitting(game, userId)).andDo(feedback.sitting(Pov(game, flaggerColor)))
- }
- IfBlameable(game) {
+ IfBlameable(game):
sitting.orElse(sitMoving).getOrElse(good(game, flaggerColor))
- }
private def propagateSitting(game: Game, userId: UserId): Funit =
game.tournamentId.so: tourId =>
@@ -140,9 +137,23 @@ final class PlaybanApi(
}
private def good(game: Game, loserColor: Color): Funit =
- game.player(loserColor).userId.so {
- save(Outcome.Good, _, RageSit.redeem(game), game.source)
- }
+ import chess.variant.*
+ val quickResign = game.status == Status.Resign &&
+ game.durationSeconds.exists(_ < 60) &&
+ game.playedTurns >= game.variant.match
+ case Standard | Chess960 | Horde => 20
+ case Antichess | Crazyhouse | KingOfTheHill => 15
+ case ThreeCheck | Atomic | RacingKings => 10
+
+ if quickResign then
+ game.userIds.parallelVoid: userId =>
+ save(Outcome.Sandbag, userId, RageSit.Update.Noop, game.source)
+ else
+ game
+ .player(loserColor)
+ .userId
+ .so: userId =>
+ save(Outcome.Good, userId, RageSit.redeem(game), game.source)
// memorize users without any ban to save DB reads
private val cleanUserIds = scalalib.cache.ExpireSetMemo[UserId](30 minutes)
@@ -222,16 +233,16 @@ final class PlaybanApi(
if outcome == Outcome.Good then fuccess(withOutcome)
else
for
- createdAt <- userApi.createdAtById(userId).orFail(s"Missing user creation date $userId")
- withBan <- legiferate(withOutcome, createdAt, source)
+ age <- userApi.accountAge(userId)
+ withBan <- legiferate(withOutcome, age, source)
yield withBan
_ <- registerRageSit(withBan, rsUpdate)
yield ()
}.void.logFailure(lila.log("playban"))
- private def legiferate(record: UserRecord, accCreatedAt: Instant, source: Option[Source]): Fu[UserRecord] =
+ private def legiferate(record: UserRecord, age: Days, source: Option[Source]): Fu[UserRecord] =
record
- .bannable(accCreatedAt)
+ .bannable(age)
.ifFalse(record.banInEffect)
.so: ban =>
lila.mon.playban.ban.count.increment()
diff --git a/modules/playban/src/main/model.scala b/modules/playban/src/main/model.scala
index 879c9fecbbb1e..80087d7a1e900 100644
--- a/modules/playban/src/main/model.scala
+++ b/modules/playban/src/main/model.scala
@@ -4,6 +4,7 @@ import play.api.libs.json.*
import lila.common.Json.given
import lila.core.playban.RageSit as RageSitCounter
+import scalalib.model.Days
case class UserRecord(
_id: UserId,
@@ -19,41 +20,52 @@ case class UserRecord(
def banInEffect = bans.lastOption.exists(_.inEffect)
def banMinutes = bans.lastOption.map(_.remainingMinutes)
+ def bansThisWeek =
+ val since = nowInstant.minusDays(7)
+ bans.count(_.date.isAfter(since))
def nbOutcomes = outcomes.size
def badOutcomeScore: Float =
outcomes.collect {
- case Outcome.NoPlay | Outcome.Abort => .7f
+ case Outcome.Sandbag => .7f
+ case Outcome.NoPlay | Outcome.Abort => .8f
case o if o != Outcome.Good => 1
} sum
- def badOutcomeRatio: Float = if bans.sizeIs < 3 then 0.4f else 0.3f
+ def badOutcomeTolerance(age: Days): Float =
+ if age <= 1 then 0.3f
+ else if bans.sizeIs < 3 then 0.4f
+ else 0.3f
def minBadOutcomes: Int =
- bans.size match
+ bansThisWeek match
case 0 | 1 => 4
case 2 | 3 => 3
case _ => 2
- def badOutcomesStreakSize: Int =
- bans.size match
- case 0 => 6
- case 1 | 2 => 5
- case _ => 4
+ def badOutcomesStreakSize(age: Days): Int =
+ if age <= 1
+ then 3
+ else if bans.size == 0 then 6
+ else if bans.size < 3 then 5
+ else if bans.size < 10 then 4
+ else 3
- def bannable(accountCreationDate: Instant): Option[TempBan] = {
+ def bannable(age: Days): Option[TempBan] = {
rageSitRecidive || {
outcomes.lastOption.exists(_ != Outcome.Good) && {
// too many bad overall
- badOutcomeScore >= ((badOutcomeRatio * nbOutcomes).atLeast(minBadOutcomes.toFloat)) || {
+ val toleranceRatio = badOutcomeTolerance(age)
+ badOutcomeScore >= ((toleranceRatio * nbOutcomes).atLeast(minBadOutcomes.toFloat)) || {
// bad result streak
- outcomes.sizeIs >= badOutcomesStreakSize &&
- outcomes.takeRight(badOutcomesStreakSize).forall(Outcome.Good !=)
+ val streakSize = badOutcomesStreakSize(age)
+ outcomes.sizeIs >= streakSize &&
+ outcomes.takeRight(streakSize).forall(Outcome.Good !=)
}
}
}
- }.option(TempBan.make(bans, accountCreationDate))
+ }.option(TempBan.make(bans, age))
def rageSitRecidive =
outcomes.lastOption.exists(Outcome.rageSitLike.contains) && {
@@ -91,7 +103,7 @@ object TempBan:
* - 0 - 3 days: linear scale from 3x to 1x
* - >3 days quick drop off Account less than 3 days old --> 2x the usual time
*/
- def make(bans: Vector[TempBan], accountCreationDate: Instant): TempBan =
+ def make(bans: Vector[TempBan], age: Days): TempBan =
make {
(bans.lastOption
.so { prev =>
@@ -99,7 +111,7 @@ object TempBan:
case h if h < 72 => prev.mins * (132 - h) / 60
case h => (55.6 * prev.mins / (Math.pow(5.56 * prev.mins - 54.6, h / 720) + 54.6)).toInt
}
- .atLeast(baseMinutes)) * (if accountCreationDate.plusDays(3).isAfterNow then 2 else 1)
+ .atLeast(baseMinutes)) * (if age <= 3 then 2 else 1)
}
enum Outcome(val id: Int, val name: String):
diff --git a/modules/playban/src/test/PlaybanTest.scala b/modules/playban/src/test/PlaybanTest.scala
new file mode 100644
index 0000000000000..025b64f76126b
--- /dev/null
+++ b/modules/playban/src/test/PlaybanTest.scala
@@ -0,0 +1,36 @@
+package lila.playban
+
+import scalalib.model.Days
+
+class PlaybanTest extends munit.FunSuite:
+
+ val userId = UserId("user")
+ val brandNew = Days(0)
+
+ test("empty"):
+ val rec = UserRecord(userId, none, none, none)
+ assertEquals(rec.bannable(brandNew), None)
+
+ test("new one abort"):
+ val rec = UserRecord(userId, Vector(Outcome.Abort).some, none, none)
+ assertEquals(rec.bannable(brandNew), None)
+
+ test("new 2 aborts"):
+ val rec = UserRecord(userId, Vector.fill(2)(Outcome.Abort).some, none, none)
+ assertEquals(rec.bannable(brandNew), None)
+
+ test("new 3 aborts"):
+ val rec = UserRecord(userId, Vector.fill(3)(Outcome.Abort).some, none, none)
+ assert(rec.bannable(brandNew).isDefined)
+
+ test("good and aborts"):
+ import Outcome.*
+ val outcomes = Vector(Good, Abort, Good, Abort, Abort)
+ val rec = UserRecord(userId, outcomes.some, none, none)
+ assert(rec.bannable(brandNew).isEmpty)
+
+ test("sandbag and aborts"):
+ import Outcome.*
+ val outcomes = Vector(Sandbag, Sandbag, Abort, Sandbag, Abort, Abort)
+ val rec = UserRecord(userId, outcomes.some, none, none)
+ assert(rec.bannable(brandNew).isDefined)
diff --git a/modules/pref/src/main/Pref.scala b/modules/pref/src/main/Pref.scala
index 534c960e01ff4..aa17bec4cc1c0 100644
--- a/modules/pref/src/main/Pref.scala
+++ b/modules/pref/src/main/Pref.scala
@@ -329,17 +329,20 @@ object Pref:
val NONE = 0
val INSIDE = 1
val OUTSIDE = 2
+ val ALL = 3
val choices = Seq(
NONE -> "No",
INSIDE -> "Inside the board",
- OUTSIDE -> "Outside the board"
+ OUTSIDE -> "Outside the board",
+ ALL -> "Inside all squares of the board"
)
def classOf(v: Int) =
v match
case INSIDE => "in"
case OUTSIDE => "out"
+ case ALL => "all"
case _ => "no"
object Replay:
diff --git a/modules/pref/src/main/PrefForm.scala b/modules/pref/src/main/PrefForm.scala
index 0981760c569f6..d655c80980e35 100644
--- a/modules/pref/src/main/PrefForm.scala
+++ b/modules/pref/src/main/PrefForm.scala
@@ -47,6 +47,7 @@ object PrefForm:
val submitMove = "submitMove" -> bitCheckedNumber(Pref.SubmitMove.choices)
val confirmResign = "confirmResign" -> checkedNumber(Pref.ConfirmResign.choices)
val moretime = "moretime" -> checkedNumber(Pref.Moretime.choices)
+ val clockSound = "clockSound" -> booleanNumber
val ratings = "ratings" -> booleanNumber
val flairs = "flairs" -> boolean
val follow = "follow" -> booleanNumber
diff --git a/modules/pref/src/main/PrefSingleChange.scala b/modules/pref/src/main/PrefSingleChange.scala
index b35e163e0a073..e4c9a270b5b30 100644
--- a/modules/pref/src/main/PrefSingleChange.scala
+++ b/modules/pref/src/main/PrefSingleChange.scala
@@ -51,6 +51,8 @@ object PrefSingleChange:
_.copy(confirmResign = v),
changing(_.moretime): v =>
_.copy(moretime = v),
+ changing(_.clockSound): v =>
+ _.copy(clockSound = v == 1),
changing(_.ratings): v =>
_.copy(ratings = v),
changing(_.follow): v =>
diff --git a/modules/pref/src/main/ui/AccountPages.scala b/modules/pref/src/main/ui/AccountPages.scala
index 0ea4928445e7f..6be7b50d1b7b7 100644
--- a/modules/pref/src/main/ui/AccountPages.scala
+++ b/modules/pref/src/main/ui/AccountPages.scala
@@ -78,8 +78,7 @@ final class AccountPages(helpers: Helpers, ui: AccountUi, flagApi: lila.core.use
form3.group(form("location"), trans.site.location(), half = true)(form3.input(_))
),
form3.split(
- form3.group(form("firstName"), trans.site.firstName(), half = true)(form3.input(_)),
- form3.group(form("lastName"), trans.site.lastName(), half = true)(form3.input(_))
+ form3.group(form("realName"), trans.site.realName(), half = true)(form3.input(_))
),
form3.split(
List("fide", "uscf", "ecf", "rcf", "cfc", "dsb").map: rn =>
diff --git a/modules/pref/src/main/ui/PrefHelper.scala b/modules/pref/src/main/ui/PrefHelper.scala
index cec233b50b8b4..ed98f7a37e5b2 100644
--- a/modules/pref/src/main/ui/PrefHelper.scala
+++ b/modules/pref/src/main/ui/PrefHelper.scala
@@ -24,7 +24,8 @@ trait PrefHelper:
List(
(Pref.Coords.NONE, trans.site.no.txt()),
(Pref.Coords.INSIDE, trans.site.insideTheBoard.txt()),
- (Pref.Coords.OUTSIDE, trans.site.outsideTheBoard.txt())
+ (Pref.Coords.OUTSIDE, trans.site.outsideTheBoard.txt()),
+ (Pref.Coords.ALL, trans.site.allSquaresOfTheBoard.txt())
)
def translatedMoveListWhilePlayingChoices(using Translate) =
diff --git a/modules/puzzle/src/main/JsonView.scala b/modules/puzzle/src/main/JsonView.scala
index 6de4c4053895a..a5f75a3c29f1d 100644
--- a/modules/puzzle/src/main/JsonView.scala
+++ b/modules/puzzle/src/main/JsonView.scala
@@ -44,6 +44,10 @@ final class JsonView(
.add("chapter" -> a.asTheme.flatMap(PuzzleTheme.studyChapterIds.get))
.add("opening" -> a.opening.map: op =>
Json.obj("key" -> op.key, "name" -> op.name))
+ .add("openingAbstract" -> a.match
+ case op: PuzzleAngle.Opening => op.isAbstract
+ case _ => false
+ )
)
def userJson(using me: Option[Me], perf: Perf) = me.map: me =>
diff --git a/modules/puzzle/src/main/PuzzleAngle.scala b/modules/puzzle/src/main/PuzzleAngle.scala
index 52cc948e49d85..131f573d60dfa 100644
--- a/modules/puzzle/src/main/PuzzleAngle.scala
+++ b/modules/puzzle/src/main/PuzzleAngle.scala
@@ -29,6 +29,7 @@ object PuzzleAngle:
opKey => SimpleOpening(opKey).map(_.ref.key)
)
.flatMap(OpeningDb.shortestLines.get)
+ def isAbstract = opening.isEmpty
val name = I18nKey(openingName)
def description = I18nKey(s"From games with the opening: $openingName")
def asTheme = none
diff --git a/modules/relay/src/main/BSONHandlers.scala b/modules/relay/src/main/BSONHandlers.scala
index 4c6da447cce59..551ed360a03d8 100644
--- a/modules/relay/src/main/BSONHandlers.scala
+++ b/modules/relay/src/main/BSONHandlers.scala
@@ -2,6 +2,7 @@ package lila.relay
import reactivemongo.api.bson.*
+import lila.db.BSON
import lila.db.dsl.{ *, given }
object BSONHandlers:
@@ -10,36 +11,22 @@ object BSONHandlers:
given BSONHandler[RelayTeamsTextarea] = stringAnyValHandler(_.text, RelayTeamsTextarea(_))
import RelayRound.Sync
- import Sync.{ Upstream, UpstreamIds, UpstreamUrl, UpstreamLcc, UpstreamUrls, FetchableUpstream }
- given upstreamUrlHandler: BSONDocumentHandler[UpstreamUrl] = Macros.handler
- given upstreamLccHandler: BSONDocumentHandler[UpstreamLcc] = Macros.handler
- given BSONHandler[FetchableUpstream] = tryHandler(
- {
- case d: BSONDocument if d.contains("url") => upstreamUrlHandler.readTry(d)
- case d: BSONDocument if d.contains("lcc") => upstreamLccHandler.readTry(d)
- },
- {
- case url: UpstreamUrl => upstreamUrlHandler.writeTry(url).get
- case lcc: UpstreamLcc => upstreamLccHandler.writeTry(lcc).get
- }
- )
- given upstreamUrlsHandler: BSONDocumentHandler[UpstreamUrls] = Macros.handler
- given upstreamIdsHandler: BSONDocumentHandler[UpstreamIds] = Macros.handler
-
- given BSONHandler[Upstream] = tryHandler(
- {
- case d: BSONDocument if d.contains("url") => upstreamUrlHandler.readTry(d)
- case d: BSONDocument if d.contains("lcc") => upstreamLccHandler.readTry(d)
- case d: BSONDocument if d.contains("urls") => upstreamUrlsHandler.readTry(d)
- case d: BSONDocument if d.contains("ids") => upstreamIdsHandler.readTry(d)
- },
- {
- case url: UpstreamUrl => upstreamUrlHandler.writeTry(url).get
- case lcc: UpstreamLcc => upstreamLccHandler.writeTry(lcc).get
- case urls: UpstreamUrls => upstreamUrlsHandler.writeTry(urls).get
- case ids: UpstreamIds => upstreamIdsHandler.writeTry(ids).get
- }
- )
+ import Sync.Upstream
+ given upstreamUrlHandler: BSONDocumentHandler[Upstream.Url] = Macros.handler
+ given upstreamUrlsHandler: BSONDocumentHandler[Upstream.Urls] = Macros.handler
+ given upstreamIdsHandler: BSONDocumentHandler[Upstream.Ids] = Macros.handler
+
+ given BSONHandler[Upstream] = new BSON[Upstream]:
+ def reads(r: BSON.Reader): Upstream =
+ if r.contains("url") then upstreamUrlHandler.readTry(r.doc).get
+ else if r.contains("urls") then upstreamUrlsHandler.readTry(r.doc).get
+ else upstreamIdsHandler.readTry(r.doc).get
+ def writes(w: BSON.Writer, up: Upstream) =
+ val doc = up match
+ case url: Upstream.Url => upstreamUrlHandler.writeTry(url).get
+ case urls: Upstream.Urls => upstreamUrlsHandler.writeTry(urls).get
+ case ids: Upstream.Ids => upstreamIdsHandler.writeTry(ids).get
+ doc ++ up.roundIds.some.filter(_.nonEmpty).so(ids => $doc("roundIds" -> ids))
import SyncLog.Event
given BSONDocumentHandler[Event] = Macros.handler
@@ -53,8 +40,9 @@ object BSONHandlers:
given BSONDocumentHandler[RelayRound] = Macros.handler
- // private given BSONHandler[play.api.i18n.Lang] = langByCodeHandler
given BSONDocumentHandler[RelayTour.Spotlight] = Macros.handler
+ given BSONDocumentHandler[RelayTour.Info] = Macros.handler
+ given BSONDocumentHandler[RelayTour.Dates] = Macros.handler
given tourHandler: BSONDocumentHandler[RelayTour] = Macros.handler
given BSONDocumentHandler[RelayTour.IdName] = Macros.handler
diff --git a/modules/relay/src/main/JsonView.scala b/modules/relay/src/main/JsonView.scala
index 40110e054f143..a510328003003 100644
--- a/modules/relay/src/main/JsonView.scala
+++ b/modules/relay/src/main/JsonView.scala
@@ -24,20 +24,26 @@ final class JsonView(
given Writes[Option[RelayTour.Tier]] = Writes: t =>
JsString(t.flatMap(RelayTour.Tier.keys.get) | "user")
+ given OWrites[RelayTour.Info] = Json.writes
+
+ given Writes[RelayTour.Dates] = Writes: ds =>
+ JsArray(List(ds.start.some, ds.end).flatten.map(Json.toJson))
+
given OWrites[RelayTour] = OWrites: t =>
Json
.obj(
- "id" -> t.id,
- "name" -> t.name,
- "slug" -> t.slug,
- "description" -> t.description,
- "createdAt" -> t.createdAt,
- "url" -> s"$baseUrl${t.path}"
+ "id" -> t.id,
+ "name" -> t.name,
+ "slug" -> t.slug,
+ "info" -> t.info,
+ "createdAt" -> t.createdAt,
+ "url" -> s"$baseUrl${t.path}"
)
.add("tier" -> t.tier)
+ .add("dates" -> t.dates)
.add("image" -> t.image.map(id => RelayTour.thumbnail(picfitUrl, id, _.Size.Large)))
- given OWrites[RelayTour.IdName] = Json.writes[RelayTour.IdName]
+ given OWrites[RelayTour.IdName] = Json.writes
given OWrites[RelayGroup.WithTours] = OWrites: g =>
Json.obj(
@@ -66,15 +72,15 @@ final class JsonView(
case tr: WithLastRound =>
Json
.obj(
- "tour" -> fullTour(tr.tour),
- "lastRound" -> withUrl(tr.round.withTour(tr.tour), withTour = false)
+ "tour" -> fullTour(tr.tour),
+ "round" -> withUrl(tr.round.withTour(tr.tour), withTour = false)
)
.add("group" -> tr.group)
case tr: ActiveWithSomeRounds =>
Json
.obj(
- "tour" -> fullTour(tr.tour),
- "lastRound" -> withUrl(tr)
+ "tour" -> fullTour(tr.tour),
+ "round" -> withUrl(tr)
)
.add("group" -> tr.group)
@@ -92,9 +98,13 @@ final class JsonView(
def withUrlAndPreviews(
rt: RelayRound.WithTourAndStudy,
previews: ChapterPreview.AsJsons,
- group: Option[RelayGroup.WithTours]
+ group: Option[RelayGroup.WithTours],
+ targetRound: Option[RelayRound.WithTour]
)(using Option[Me]): JsObject =
- myRound(rt) ++ Json.obj("games" -> previews).add("group" -> group)
+ myRound(rt) ++ Json
+ .obj("games" -> previews)
+ .add("group" -> group)
+ .add("targetRound" -> targetRound.map(withUrl(_, true)))
def sync(round: RelayRound) = Json.toJsObject(round.sync)
@@ -120,6 +130,7 @@ final class JsonView(
JsonView.JsData(
relay = fullTourWithRounds(trs, group)
.add("sync" -> (canContribute.so(trs.rounds.find(_.id == currentRoundId).map(_.sync))))
+ .add("lcc", trs.rounds.find(_.id == currentRoundId).map(_.sync.upstream.exists(_.hasLcc)))
.add("isSubscribed" -> isSubscribed)
.add("videoUrls" -> videoUrls)
.add("pinned" -> pinned.map: (id, name, image) =>
@@ -165,7 +176,6 @@ object JsonView:
given OWrites[RelayStats.RoundStats] = OWrites: r =>
Json.obj(
- "round" -> r.round,
"viewers" -> r.viewers.map: (minute, crowd) =>
Json.arr(minute * 60, crowd)
)
@@ -179,7 +189,6 @@ object JsonView:
)
.add("delay" -> s.delay) ++
s.upstream.so:
- case Sync.UpstreamUrl(url) => Json.obj("url" -> url)
- case Sync.UpstreamLcc(url, round) => Json.obj("url" -> url, "round" -> round)
- case Sync.UpstreamUrls(urls) => Json.obj("urls" -> urls.map(_.formUrl))
- case Sync.UpstreamIds(ids) => Json.obj("ids" -> ids)
+ case Sync.Upstream.Url(url) => Json.obj("url" -> url)
+ case Sync.Upstream.Urls(urls) => Json.obj("urls" -> urls)
+ case Sync.Upstream.Ids(ids) => Json.obj("ids" -> ids)
diff --git a/modules/relay/src/main/RelayApi.scala b/modules/relay/src/main/RelayApi.scala
index ca32574e5ab97..a695190b17655 100644
--- a/modules/relay/src/main/RelayApi.scala
+++ b/modules/relay/src/main/RelayApi.scala
@@ -12,7 +12,17 @@ import lila.memo.{ CacheApi, PicfitApi }
import lila.relay.RelayRound.{ WithTour, Sync }
import lila.core.perm.Granter
import lila.core.study.data.StudyName
-import lila.study.{ Settings, Study, StudyApi, StudyId, StudyMaker, StudyRepo, StudyTopic }
+import lila.study.{
+ Settings,
+ Study,
+ StudyApi,
+ StudyId,
+ StudyMaker,
+ StudyRepo,
+ StudyTopic,
+ StudyMember,
+ StudyMembers
+}
final class RelayApi(
roundRepo: RelayRoundRepo,
@@ -53,8 +63,14 @@ final class RelayApi(
byIdWithTour(id).flatMapz(rt => formNavigation(rt).dmap(some))
def formNavigation(rt: RelayRound.WithTour): Fu[(RelayRound, ui.FormNavigation)] =
- formNavigation(rt.tour).map: nav =>
- (rt.round, nav.copy(round = rt.round.id.some))
+ for
+ nav <- formNavigation(rt.tour)
+ sourceRound <- rt.round.sync.upstream.flatMap(_.roundId).so(byIdWithTour)
+ targetRound <- officialTarget(rt.round)
+ yield (
+ rt.round,
+ nav.copy(roundId = rt.round.id.some, sourceRound = sourceRound, targetRound = targetRound)
+ )
def formNavigation(tour: RelayTour): Fu[ui.FormNavigation] = for
group <- withTours.get(tour.id)
@@ -88,14 +104,34 @@ final class RelayApi(
def withRounds(tour: RelayTour) = roundRepo.byTourOrdered(tour.id).dmap(tour.withRounds)
- def denormalizeTourActive(tourId: RelayTourId): Funit =
+ def denormalizeTour(tourId: RelayTourId): Funit =
val unfinished = RelayRoundRepo.selectors.tour(tourId) ++ $doc("finished" -> false)
for
active <- roundRepo.coll.exists(unfinished)
live <- active.so(roundRepo.coll.exists(unfinished ++ $doc("startedAt".$exists(true))))
- _ <- tourRepo.setActive(tourId, active, live)
+ dates <- computeDates(tourId)
+ _ <- tourRepo.denormalize(tourId, active, live, dates)
yield ()
+ private def computeDates(tourId: RelayTourId): Fu[Option[RelayTour.Dates]] =
+ roundRepo.coll
+ .aggregateOne(): framework =>
+ import framework.*
+ Match($doc("tourId" -> tourId)) -> List(
+ Project($doc("at" -> $doc("$ifNull" -> $arr("$startsAt", "$startedAt")))),
+ Sort(Ascending("at")),
+ Group(BSONNull)("at" -> PushField("at")),
+ Project($doc("start" -> $doc("$first" -> "$at"), "end" -> $doc("$last" -> "$at")))
+ )
+ .map:
+ _.flatMap: doc =>
+ for
+ start <- doc.getAsOpt[Instant]("start")
+ end <- doc.getAsOpt[Instant]("end")
+ singleDay = end.isBefore(start.plusDays(1))
+ endMaybe = Option.when(!singleDay)(end)
+ yield RelayTour.Dates(start, endMaybe)
+
object countOwnedByUser:
private val cache = cacheApi[UserId, Int](16_384, "relay.nb.owned"):
_.expireAfterWrite(5.minutes).buildAsyncFuture(tourRepo.countByOwner(_, false))
@@ -182,7 +218,7 @@ final class RelayApi(
$id(tour.id),
$setsAndUnsets(
"name" -> tour.name.some,
- "description" -> tour.description.some,
+ "info" -> tour.info.some,
"markup" -> tour.markup,
"tier" -> tour.tier,
"autoLeaderboard" -> tour.autoLeaderboard.some,
@@ -204,48 +240,54 @@ final class RelayApi(
val canGroup = fuccess(Granter(_.StudyAdmin)) >>| tourRepo.isOwnerOfAll(me.userId, data.tourIds)
canGroup.flatMapz(groupRepo.update(tour.id, data))
- def create(data: RelayRoundForm.Data, tour: RelayTour)(using me: Me): Fu[RelayRound.WithTourAndStudy] =
- roundRepo
- .lastByTour(tour)
- .flatMapz: last =>
- studyRepo.byId(last.studyId)
- .flatMap: lastStudy =>
- import lila.study.{ StudyMember, StudyMembers }
- val relay = data.make(me, tour)
- for
- study <- studyApi
- .create(
- StudyMaker.ImportGame(
- id = relay.studyId.some,
- name = relay.name.into(StudyName).some,
- settings = lastStudy
- .fold(
- Settings.init
- .copy(
- chat = Settings.UserSelection.Everyone,
- sticky = false
- )
- )(_.settings)
- .some,
- from = Study.From.Relay(none).some
- ),
- me,
- withRatings = true,
- _.copy(
- members =
- lastStudy.fold(StudyMembers.empty)(_.members) + StudyMember(me, StudyMember.Role.Write)
- )
+ def create(data: RelayRoundForm.Data, tour: RelayTour)(using me: Me): Fu[RelayRound.WithTourAndStudy] = for
+ last <- roundRepo.lastByTour(tour)
+ lastStudy <- last.so(r => studyRepo.byId(r.studyId))
+ relay <- copyRoundSourceSettings(data.make(me, tour))
+ importGame = StudyMaker.ImportGame(
+ id = relay.studyId.some,
+ name = relay.name.into(StudyName).some,
+ settings = lastStudy
+ .fold(
+ Settings.init
+ .copy(
+ chat = Settings.UserSelection.Everyone,
+ sticky = false
)
- .orFail(s"Can't create study for relay $relay")
- _ <- roundRepo.coll.insert.one(relay)
- _ <- tourRepo.setActive(tour.id, true, relay.hasStarted)
- _ <- studyApi.addTopics(relay.studyId, List(StudyTopic.broadcast.value))
- yield relay.withTour(tour).withStudy(study.study)
+ )(_.settings)
+ .some,
+ from = Study.From.Relay(none).some
+ )
+ study <- studyApi
+ .create(
+ importGame,
+ me,
+ withRatings = true,
+ _.copy(
+ members = lastStudy.fold(StudyMembers.empty)(_.members) + StudyMember(me, StudyMember.Role.Write)
+ )
+ )
+ .orFail(s"Can't create study for relay $relay")
+ _ <- roundRepo.coll.insert.one(relay)
+ dates <- computeDates(tour.id)
+ _ <- tourRepo.denormalize(tour.id, true, relay.hasStarted, dates)
+ _ <- studyApi.addTopics(relay.studyId, List(StudyTopic.broadcast.value))
+ yield relay.withTour(tour).withStudy(study.study)
+
+ private def copyRoundSourceSettings(relay: RelayRound): Fu[RelayRound] =
+ relay.sync.upstream
+ .flatMap(_.roundId)
+ .ifTrue(relay.startsAt.isEmpty)
+ .so(byId)
+ .map:
+ _.fold(relay): sourceRound =>
+ relay.copy(startsAt = sourceRound.startsAt)
def requestPlay(id: RelayRoundId, v: Boolean): Funit =
WithRelay(id): relay =>
relay.sync.upstream.collect:
- case f: Sync.FetchableUpstream => formatApi.refresh(f)
+ case Sync.Upstream.Url(url) => formatApi.refresh(url)
+ case Sync.Upstream.Urls(urls) => urls.foreach(formatApi.refresh)
isOfficial(relay.id).flatMap: official =>
update(relay): r =>
if v
@@ -257,16 +299,17 @@ final class RelayApi(
byId(round.id).orFail(s"Relay round ${round.id} not found").flatMap(update(_)(f))
def update(from: RelayRound)(f: Update[RelayRound]): Fu[RelayRound] =
- val round = f(from).pipe: r =>
+ val updated = f(from).pipe: r =>
if r.sync.upstream != from.sync.upstream then r.withSync(_.clearLog) else r
- if round == from then fuccess(round)
+ if updated == from then fuccess(from)
else
for
- _ <- (from.name != round.name).so(studyApi.rename(round.studyId, round.name.into(StudyName)))
- _ <- roundRepo.coll.update.one($id(round.id), round).void
+ round <- copyRoundSourceSettings(updated)
+ _ <- (from.name != round.name).so(studyApi.rename(round.studyId, round.name.into(StudyName)))
+ _ <- roundRepo.coll.update.one($id(round.id), round).void
_ <- (round.sync.playing != from.sync.playing)
.so(sendToContributors(round.id, "relaySync", jsonView.sync(round)))
- _ <- (round.stateHash != from.stateHash).so(denormalizeTourActive(round.tourId))
+ _ <- denormalizeTour(round.tourId)
yield
round.sync.log.events.lastOption
.ifTrue(round.sync.log != from.sync.log)
@@ -274,12 +317,31 @@ final class RelayApi(
sendToContributors(round.id, "relayLog", Json.toJsObject(event))
round
+ def syncTargetsOfSource(source: RelayRound): Funit =
+ (!source.sync.upstream.exists(_.isRound)).so: // prevent chaining (and circular!) round updates
+ roundRepo.syncTargetsOfSource(source.id)
+
+ def officialTarget(source: RelayRound): Fu[Option[WithTour]] =
+ source.sync.isPush.so:
+ roundRepo.coll
+ .aggregateOne(): framework =>
+ import framework.*
+ Match($doc("sync.upstream.roundIds" -> source.id)) -> List(
+ PipelineOperator(tourRepo.lookup("tourId")),
+ UnwindField("tour"),
+ Match($doc("tour.tier".$exists(true))),
+ Sort(Descending("tour.tier"), Descending("tour.createdAt")),
+ Limit(1)
+ )
+ .map(_.flatMap(readRoundWithTour))
+
def reset(old: RelayRound)(using me: Me): Funit =
WithRelay(old.id) { relay =>
for
_ <- studyApi.deleteAllChapters(relay.studyId, me)
+ _ <- roundRepo.coll.updateField($id(relay.id), "finished", false)
_ <- old.hasStartedEarly.so:
- roundRepo.coll.update.one($id(relay.id), $set("finished" -> false) ++ $unset("startedAt")).void
+ roundRepo.coll.unsetField($id(relay.id), "startedAt").void
_ <- roundRepo.coll.update.one($id(relay.id), $set("sync.log" -> $arr()))
yield leaderboard.invalidate(relay.tourId)
} >> requestPlay(old.id, v = true)
@@ -288,7 +350,7 @@ final class RelayApi(
byIdWithTour(roundId).flatMapz: rt =>
for
_ <- roundRepo.coll.delete.one($id(rt.round.id))
- _ <- denormalizeTourActive(rt.tour.id)
+ _ <- denormalizeTour(rt.tour.id)
yield rt.tour.some
def deleteTourIfOwner(tour: RelayTour)(using me: Me): Fu[Boolean] =
@@ -397,8 +459,8 @@ final class RelayApi(
.$lt(nowInstant.plusSeconds(RelayDelay.maxSeconds.value))
.$gt(nowInstant.minusDays(1)), // bit late now
"startedAt".$exists(false),
- "sync.until".$exists(false),
- "sync.upstream".$exists(true)
+ "sync.upstream".$exists(true),
+ $or("sync.until".$exists(false), "sync.until".$lt(nowInstant))
)
)
.flatMap:
diff --git a/modules/relay/src/main/RelayDelay.scala b/modules/relay/src/main/RelayDelay.scala
index 2666e314861bb..ce89a2c0495eb 100644
--- a/modules/relay/src/main/RelayDelay.scala
+++ b/modules/relay/src/main/RelayDelay.scala
@@ -1,12 +1,11 @@
package lila.relay
import chess.format.pgn.PgnStr
-
+import io.mola.galimatias.URL
import scalalib.model.Seconds
import lila.db.dsl.{ *, given }
import lila.memo.CacheApi
-import lila.relay.RelayRound.Sync.FetchableUpstream
import lila.study.MultiPgn
final private class RelayDelay(colls: RelayColls)(using Executor):
@@ -14,11 +13,11 @@ final private class RelayDelay(colls: RelayColls)(using Executor):
import RelayDelay.*
def apply(
- url: FetchableUpstream,
+ url: URL,
round: RelayRound,
- doFetchUrl: (FetchableUpstream, Max) => Fu[RelayGames]
+ doFetchUrl: URL => Fu[RelayGames]
): Fu[RelayGames] =
- dedupCache(url, round, () => doFetchUrl(url, RelayFetch.maxChapters))
+ dedupCache(url, round, () => doFetchUrl(url))
.flatMap: latest =>
round.sync.delay match
case Some(delay) if delay > 0 => store.get(url, delay).map(_ | latest.map(_.resetToSetup))
@@ -31,16 +30,17 @@ final private class RelayDelay(colls: RelayColls)(using Executor):
private val cache = CacheApi.scaffeineNoScheduler
.initialCapacity(8)
.maximumSize(128)
- .build[FetchableUpstream, GamesSeenBy]()
+ .build[String, GamesSeenBy]()
.underlying
- def apply(url: FetchableUpstream, round: RelayRound, doFetch: () => Fu[RelayGames]) =
+ def apply(url: URL, round: RelayRound, doFetch: () => Fu[RelayGames]) =
cache.asMap
.compute(
- url,
+ url.toString,
(_, v) =>
Option(v) match
case Some(GamesSeenBy(games, seenBy)) if !seenBy(round.id) =>
+ lila.mon.relay.dedup.increment()
GamesSeenBy(games, seenBy + round.id)
case _ =>
val futureGames = doFetch().addEffect: games =>
@@ -51,31 +51,31 @@ final private class RelayDelay(colls: RelayColls)(using Executor):
private object store:
- private def idOf(upstream: FetchableUpstream, at: Instant) = s"${upstream.formUrl} ${at.toSeconds}"
- private val longPast = java.time.Instant.ofEpochMilli(0)
+ private def idOf(url: URL, at: Instant) = s"$url ${at.toSeconds}"
+ private val longPast = java.time.Instant.ofEpochMilli(0)
- def putIfNew(upstream: FetchableUpstream, games: RelayGames): Funit =
+ def putIfNew(url: URL, games: RelayGames): Funit =
val newPgn = RelayGame.iso.from(games).toPgnStr
- getLatestPgn(upstream).flatMap:
+ getLatestPgn(url).flatMap:
case Some(latestPgn) if latestPgn == newPgn => funit
case _ =>
val now = nowInstant
- val doc = $doc("_id" -> idOf(upstream, now), "at" -> now, "pgn" -> newPgn)
+ val doc = $doc("_id" -> idOf(url, now), "at" -> now, "pgn" -> newPgn)
colls.delay:
_.insert.one(doc).void
- def get(upstream: FetchableUpstream, delay: Seconds): Fu[Option[RelayGames]] =
- getPgn(upstream, delay).map2: pgn =>
+ def get(url: URL, delay: Seconds): Fu[Option[RelayGames]] =
+ getPgn(url, delay).map2: pgn =>
RelayGame.iso.to(MultiPgn.split(pgn, Max(999)))
- private def getLatestPgn(upstream: FetchableUpstream): Fu[Option[PgnStr]] =
- getPgn(upstream, Seconds(0))
+ private def getLatestPgn(url: URL): Fu[Option[PgnStr]] =
+ getPgn(url, Seconds(0))
- private def getPgn(upstream: FetchableUpstream, delay: Seconds): Fu[Option[PgnStr]] =
+ private def getPgn(url: URL, delay: Seconds): Fu[Option[PgnStr]] =
colls.delay:
_.find(
$doc(
- "_id".$gt(idOf(upstream, longPast)).$lte(idOf(upstream, nowInstant.minusSeconds(delay.value)))
+ "_id".$gt(idOf(url, longPast)).$lte(idOf(url, nowInstant.minusSeconds(delay.value)))
),
$doc("pgn" -> true).some
).sort($sort.desc("_id"))
diff --git a/modules/relay/src/main/RelayFetch.scala b/modules/relay/src/main/RelayFetch.scala
index 0271e303e391b..0302a4c849a83 100644
--- a/modules/relay/src/main/RelayFetch.scala
+++ b/modules/relay/src/main/RelayFetch.scala
@@ -25,8 +25,10 @@ final private class RelayFetch(
delayer: RelayDelay,
fidePlayers: RelayFidePlayerApi,
gameRepo: GameRepo,
+ studyChapterRepo: lila.study.ChapterRepo,
pgnDump: PgnDump,
gameProxy: lila.core.game.GameProxy,
+ cacheApi: CacheApi,
onlyIds: Option[List[RelayTourId]] = None
)(using Executor, Scheduler, lila.core.i18n.Translator)(using mode: play.api.Mode):
@@ -42,7 +44,7 @@ final private class RelayFetch(
LilaScheduler(
"RelayFetch.user",
- _.Every(if mode.isDev then 2.seconds else 750 millis),
+ _.Every(if mode.isDev then 2.seconds else 879 millis),
_.AtMost(10 seconds),
_.Delay(if mode.isDev then 2.second else 33 seconds)
):
@@ -50,27 +52,28 @@ final private class RelayFetch(
private val maxRelaysToSync = Max(50)
- private def syncRelays(official: Boolean): Funit =
- val relays =
+ private def syncRelays(official: Boolean): Funit = for
+ relays <-
if official then api.toSyncOfficial(maxRelaysToSync, onlyIds)
else api.toSyncUser(maxRelaysToSync, onlyIds)
- relays
- .flatMap: relays =>
- lila.mon.relay.ongoing(official).update(relays.size)
- relays
- .parallelVoid: rt =>
- if rt.round.sync.ongoing then
- processRelay(rt).flatMap: updating =>
- api.reFetchAndUpdate(rt.round)(updating.reRun)
- else if rt.round.hasStarted then
- logger.info(s"Finish by lack of activity ${rt.round}")
- api.update(rt.round)(_.finish)
- else if rt.round.shouldGiveUp then
- val msg = "Finish for lack of start"
- logger.info(s"$msg ${rt.round}")
- if rt.tour.official then irc.broadcastError(rt.round.id, rt.fullName, msg)
- api.update(rt.round)(_.finish)
- else funit
+ _ <- relays.parallelVoid(syncRelay)
+ yield lila.mon.relay.ongoing(official).update(relays.size)
+
+ private def syncRelay(rt: RelayRound.WithTour): Funit =
+ if rt.round.sync.ongoing then
+ processRelay(rt).flatMap: updating =>
+ api.reFetchAndUpdate(rt.round)(updating.reRun).void
+ else if rt.round.hasStarted then
+ logger.info(s"Finish by lack of activity ${rt.round}")
+ api.update(rt.round)(_.finish).void
+ else if rt.round.shouldGiveUp then
+ val msg = "Finish for lack of start"
+ logger.info(s"$msg ${rt.round}")
+ if rt.tour.official then irc.broadcastError(rt.round.id, rt.fullName, msg)
+ api.update(rt.round)(_.finish).void
+ else
+ logger.info(s"Pause sync until round starts ${rt.round}")
+ api.update(rt.round)(_.withSync(_.pause)).void
// no writing the relay; only reading!
// this can take a long time if the source is slow
@@ -84,17 +87,17 @@ final private class RelayFetch(
.map(games => rt.tour.players.fold(games)(_.update(games)))
.flatMap(fidePlayers.enrichGames(rt.tour))
.map(games => rt.tour.teams.fold(games)(_.update(games)))
- .mon(_.relay.fetchTime(rt.tour.official, rt.round.slug))
- .addEffect(gs => lila.mon.relay.games(rt.tour.official, rt.round.slug).update(gs.size))
+ .mon(_.relay.fetchTime(rt.tour.official, rt.tour.id, rt.tour.slug))
+ .addEffect(gs => lila.mon.relay.games(rt.tour.official, rt.tour.id, rt.round.slug).update(gs.size))
.flatMap: games =>
sync
.updateStudyChapters(rt, games)
.withTimeoutError(7 seconds, SyncResult.Timeout)
- .mon(_.relay.syncTime(rt.tour.official, rt.round.slug))
+ .mon(_.relay.syncTime(rt.tour.official, rt.tour.id, rt.tour.slug))
.map: res =>
res -> updating:
_.withSync(_.addLog(SyncLog.event(res.nbMoves, none)))
- .copy(finished = games.nonEmpty && games.forall(_.ending.isDefined))
+ .copy(finished = games.nonEmpty && games.forall(_.outcome.isDefined))
.recover:
case e: Exception =>
val result = e.match
@@ -119,11 +122,14 @@ final private class RelayFetch(
): Updating[RelayRound] =
val round = updating.current
result match
- case result: SyncResult.Ok if result.nbMoves > 0 =>
- lila.mon.relay.moves(tour.official, round.slug).increment(result.nbMoves)
- if !round.hasStarted && !tour.official then
- irc.broadcastStart(round.id, round.withTour(tour).fullName)
- continueRelay(tour, updating(_.ensureStarted.resume(tour.official)))
+ case result: SyncResult.Ok if result.hasMovesOrTags =>
+ api.syncTargetsOfSource(round)
+ if result.nbMoves > 0 then
+ lila.mon.relay.moves(tour.official, tour.id, tour.slug).increment(result.nbMoves)
+ if !round.hasStarted && !tour.official then
+ irc.broadcastStart(round.id, round.withTour(tour).fullName)
+ continueRelay(tour, updating(_.ensureStarted.resume(tour.official)))
+ else continueRelay(tour, updating)
case _ => continueRelay(tour, updating)
private def continueRelay(tour: RelayTour, updating: Updating[RelayRound]): Updating[RelayRound] =
@@ -139,10 +145,7 @@ final private class RelayFetch(
.filterNot(_.contains("Found an empty PGN"))
.foreach { irc.broadcastError(round.id, round.withTour(tour).fullName, _) }
Seconds(60)
- else
- round.sync.period | Seconds:
- if upstream.isLcc && !tour.official then 12
- else 5
+ else round.sync.period | dynamicPeriod(tour, round, upstream)
updating:
_.withSync:
_.copy(
@@ -153,6 +156,21 @@ final private class RelayFetch(
} some
)
+ private def dynamicPeriod(tour: RelayTour, round: RelayRound, upstream: Sync.Upstream) = Seconds:
+ val base =
+ if upstream.hasLcc then 6
+ else if upstream.isRound then 10 // uses push so no need to pull oftenrelayfetch
+ else 2
+ base * {
+ if tour.tier.exists(_ > RelayTour.Tier.NORMAL) then 1
+ else if tour.official then 2
+ else 3
+ } * {
+ if upstream.hasLcc && round.crowd.exists(_ < 10) then 2 else 1
+ } * {
+ if round.hasStarted then 1 else 2
+ }
+
private val gameIdsUpstreamPgnFlags = PgnDump.WithFlags(
clocks = true,
moves = true,
@@ -167,22 +185,21 @@ final private class RelayFetch(
private def fetchGames(rt: RelayRound.WithTour): Fu[RelayGames] =
given CanProxy = CanProxy(rt.tour.official)
rt.round.sync.upstream.so:
- case Sync.UpstreamIds(ids) => fetchFromGameIds(rt.tour, ids)
- case lcc: Sync.UpstreamLcc => fetchFromUpstream(lcc, RelayFetch.maxChapters)
- case url: Sync.UpstreamUrl => delayer(url, rt.round, fetchFromUpstream)
- case Sync.UpstreamUrls(urls) =>
- urls
- .traverse: url =>
- delayer(url, rt.round, fetchFromUpstream(using CanProxy(rt.tour.official)))
- .map(_.flatten.toVector)
+ case Sync.Upstream.Ids(ids) => fetchFromGameIds(rt.tour, ids)
+ case Sync.Upstream.Url(url) => delayer(url, rt.round, fetchFromUpstream(rt))
+ case Sync.Upstream.Urls(urls) =>
+ urls.toVector
+ .parallel: url =>
+ delayer(url, rt.round, fetchFromUpstreamWithRecover(rt))
+ .map(_.flatten)
private def fetchFromGameIds(tour: RelayTour, ids: List[GameId]): Fu[RelayGames] =
gameRepo
.gamesFromSecondary(ids)
.flatMap(gameProxy.upgradeIfPresent)
.flatMap(gameRepo.withInitialFens)
- .flatMap { games =>
- if games.size == ids.size then
+ .flatMap: games =>
+ if games.sizeIs == ids.size then
val pgnFlags = gameIdsUpstreamPgnFlags.copy(delayMoves = !tour.official)
given play.api.i18n.Lang = lila.core.i18n.defaultLang
games
@@ -192,52 +209,93 @@ final private class RelayFetch(
else
throw LilaInvalid:
s"Invalid game IDs: ${ids.filter(id => !games.exists(_._1.id == id)).mkString(", ")}"
- }
- .flatMap(multiPgnToGames(_).toFuture)
+ .flatMap(multiPgnToGames.future)
- private def fetchFromUpstream(using
- canProxy: CanProxy
- )(upstream: Sync.FetchableUpstream, max: Max): Fu[RelayGames] =
+ private object lccCache:
+ import DgtJson.GameJson
+ type LccGameKey = String
+ // cache finished games so they're not requested again for a while
+ private val finishedGames =
+ cacheApi.notLoadingSync[LccGameKey, GameJson](512, "relay.fetch.finishedLccGames"):
+ _.expireAfterWrite(8 minutes).build()
+ // cache created (non-started) games until they start
+ private val createdGames =
+ cacheApi.notLoadingSync[LccGameKey, GameJson](256, "relay.fetch.createdLccGames"):
+ _.expireAfter[LccGameKey, GameJson](
+ create = (key, _) => (if key.startsWith("started ") then 1 minute else 5 minutes),
+ update = (_, _, current) => current,
+ read = (_, _, current) => current
+ ).build()
+ // cache games with number > 12 to reduce load on big tournaments
+ val tailAt = 12
+ private val tailGames =
+ cacheApi.notLoadingSync[LccGameKey, GameJson](256, "relay.fetch.tailLccGames"):
+ _.expireAfterWrite(1 minutes).build()
+
+ def apply(lcc: RelayRound.Sync.Lcc, index: Int, roundTags: Tags, started: Boolean)(
+ fetch: () => Fu[GameJson]
+ ): Fu[GameJson] =
+ val key = s"${started.so("started ")}${lcc.id} ${lcc.round} $index"
+ finishedGames
+ .getIfPresent(key)
+ .orElse(createdGames.getIfPresent(key))
+ .orElse((index >= lccCache.tailAt).so(tailGames.getIfPresent(key)))
+ .match
+ case Some(game) => fuccess(game)
+ case None =>
+ fetch().addEffect: game =>
+ if game.moves.isEmpty then createdGames.put(key, game)
+ else if game.mergeRoundTags(roundTags).outcome.isDefined then finishedGames.put(key, game)
+ else if index >= lccCache.tailAt then tailGames.put(key, game)
+
+ private def fetchFromUpstreamWithRecover(rt: RelayRound.WithTour)(url: URL)(using
+ CanProxy
+ ): Fu[RelayGames] =
+ fetchFromUpstream(rt)(url).recover:
+ case e: Exception =>
+ logger.info(s"Fetch error in multi-url ${rt.round.id} $url ${e.getMessage.take(80)}", e)
+ Vector.empty
+
+ private def fetchFromUpstream(rt: RelayRound.WithTour)(url: URL)(using CanProxy): Fu[RelayGames] =
import DgtJson.*
formatApi
- .get(upstream)
+ .get(url)
.flatMap {
- case RelayFormat.SingleFile(doc) =>
- doc.format match
- // all games in a single PGN file
- case RelayFormat.DocFormat.Pgn => httpGetPgn(doc.url).map { MultiPgn.split(_, max) }
- // maybe a single JSON game? Why not
- case RelayFormat.DocFormat.Json =>
- httpGetJson[GameJson](doc.url).map: game =>
- MultiPgn(List(game.toPgn()))
- case RelayFormat.ManyFiles(indexUrl, makeGameDoc) =>
- httpGetJson[RoundJson](indexUrl).flatMap: round =>
- round.pairings.zipWithIndex
- .map: (pairing, i) =>
- val number = i + 1
- val gameDoc = makeGameDoc(number)
- gameDoc.format
- .match
- case RelayFormat.DocFormat.Pgn => httpGetPgn(gameDoc.url)
- case RelayFormat.DocFormat.Json =>
- httpGetJson[GameJson](gameDoc.url)
- .recover:
- case _: Exception => GameJson(moves = Nil, result = none)
- .map { _.toPgn(pairing.tags) }
+ case RelayFormat.Round(id) =>
+ studyChapterRepo
+ .orderedByStudyLoadingAllInMemory(id.into(StudyId))
+ .map(_.view.map(RelayGame.fromChapter).toVector)
+ case RelayFormat.SingleFile(url) =>
+ httpGetPgn(url).map { MultiPgn.split(_, RelayFetch.maxChapters) }.flatMap(multiPgnToGames.future)
+ case RelayFormat.LccWithGames(lcc) =>
+ httpGetJson[RoundJson](lcc.indexUrl).flatMap: round =>
+ val lookForStart: Boolean =
+ rt.round.startsAt
+ .map(_.minusSeconds(rt.round.sync.delay.so(_.value) + 5 * 60))
+ .forall(_.isBeforeNow)
+ round.pairings
+ .mapWithIndex: (pairing, i) =>
+ val game = i + 1
+ val tags = pairing.tags(lcc.round, game)
+ lccCache(lcc, game, tags, lookForStart): () =>
+ httpGetJson[GameJson](lcc.gameUrl(game)).recover:
+ case _: Exception => GameJson(moves = Nil, result = none)
+ .map { _.toPgn(tags) }
.recover: _ =>
- PgnStr(s"${pairing.tags}\n\n${pairing.result}")
- .map(number -> _)
+ PgnStr(s"${tags}\n\n${pairing.result}")
+ .map(game -> _)
.parallel
- .map: results =>
- MultiPgn(results.sortBy(_._1).map(_._2))
- case RelayFormat.ManyFilesLater(indexUrl) =>
- httpGetJson[RoundJson](indexUrl).map: round =>
- MultiPgn:
- round.pairings.map: pairing =>
- PgnStr(s"${pairing.tags}\n\n${pairing.result}")
-
+ .map: pgns =>
+ MultiPgn(pgns.sortBy(_._1).map(_._2))
+ .flatMap(multiPgnToGames.future)
+ case RelayFormat.LccWithoutGames(lcc) =>
+ httpGetJson[RoundJson](lcc.indexUrl)
+ .map: round =>
+ MultiPgn:
+ round.pairings.mapWithIndex: (pairing, i) =>
+ PgnStr(s"${pairing.tags(lcc.round, i + 1)}\n\n${pairing.result}")
+ .flatMap(multiPgnToGames.future)
}
- .flatMap { multiPgnToGames(_).toFuture }
private def httpGetPgn(url: URL)(using CanProxy): Fu[PgnStr] =
PgnStr.from(formatApi.httpGetAndGuessCharset(url))
@@ -269,7 +327,7 @@ private object RelayFetch:
result: Option[String]
):
import chess.format.pgn.*
- def tags = Tags:
+ def tags(round: Int, game: Int) = Tags:
List(
white.flatMap(_.fullName).map { Tag(_.White, _) },
white.flatMap(_.title).map { Tag(_.WhiteTitle, _) },
@@ -277,22 +335,27 @@ private object RelayFetch:
black.flatMap(_.fullName).map { Tag(_.Black, _) },
black.flatMap(_.title).map { Tag(_.BlackTitle, _) },
black.flatMap(_.fideid).map { Tag(_.BlackFideId, _) },
- result.map(Tag(_.Result, _))
+ result.map(Tag(_.Result, _)),
+ Tag(_.Round, s"$round.$game").some
).flatten
- case class RoundJson(pairings: List[RoundJsonPairing])
+ case class RoundJson(pairings: List[RoundJsonPairing]):
+ def finishedGameIndexes: List[Int] = pairings.zipWithIndex.collect:
+ case (pairing, i) if pairing.result.forall(_ != "*") => i
given Reads[PairingPlayer] = Json.reads
given Reads[RoundJsonPairing] = Json.reads
given Reads[RoundJson] = Json.reads
case class GameJson(moves: List[String], result: Option[String], chess960: Option[Int] = none):
def outcome = result.flatMap(Outcome.fromResult)
- def toPgn(extraTags: Tags = Tags.empty): PgnStr =
+ def mergeRoundTags(roundTags: Tags): Tags =
val fenTag = chess960
.filter(_ != 518) // LCC sends 518 for standard chess
.flatMap(chess.variant.Chess960.positionToFen)
.map(pos => Tag(_.FEN, pos.value))
val outcomeTag = outcome.map(o => Tag(_.Result, Outcome.showResult(o.some)))
- val tags = extraTags ++ Tags(List(fenTag, outcomeTag).flatten)
+ roundTags ++ Tags(List(fenTag, outcomeTag).flatten)
+ def toPgn(roundTags: Tags): PgnStr =
+ val mergedTags = mergeRoundTags(roundTags)
val strMoves = moves
.map(_.split(' '))
.mapWithIndex: (move, index) =>
@@ -304,7 +367,7 @@ private object RelayFetch:
)
.render
.mkString(" ")
- PgnStr(s"$tags\n\n$strMoves")
+ PgnStr(s"$mergedTags\n\n$strMoves")
given Reads[GameJson] = Json.reads
object multiPgnToGames:
@@ -320,11 +383,13 @@ private object RelayFetch:
else (acc :+ game, index + 1).asRight[LilaInvalid]
.map(_._1)
+ def future(multiPgn: MultiPgn): Fu[Vector[RelayGame]] = apply(multiPgn).toFuture
+
private val pgnCache: LoadingCache[PgnStr, Either[LilaInvalid, RelayGame]] =
CacheApi
.scaffeineNoScheduler(using scala.concurrent.ExecutionContextOpportunistic)
.expireAfterAccess(2 minutes)
- .maximumSize(512)
+ .maximumSize(1024)
.build(compute)
private def compute(pgn: PgnStr): Either[LilaInvalid, RelayGame] =
@@ -342,5 +407,5 @@ private object RelayFetch:
comments = Comments.empty,
children = res.root.children.updateMainline(_.copy(comments = Comments.empty))
),
- ending = res.end
+ outcome = res.end.map(_.outcome)
)
diff --git a/modules/relay/src/main/RelayFidePlayerApi.scala b/modules/relay/src/main/RelayFidePlayerApi.scala
index 97cf47af830a1..795182e43c12c 100644
--- a/modules/relay/src/main/RelayFidePlayerApi.scala
+++ b/modules/relay/src/main/RelayFidePlayerApi.scala
@@ -24,9 +24,7 @@ final private class RelayFidePlayerApi(guessPlayer: lila.core.fide.GuessPlayer)(
update(tags, tc, _)
private def guessTimeControl(tour: RelayTour): Option[FideTC] =
- tour.description
- .split('|')
- .lift(2)
+ tour.info.tc
.map(_.trim.toLowerCase.replace("classical", "standard"))
.so: tcStr =>
FideTC.values.find(tc => tcStr.contains(tc.toString))
diff --git a/modules/relay/src/main/RelayFormat.scala b/modules/relay/src/main/RelayFormat.scala
index 0270c7a0d8436..99717ca87af0d 100644
--- a/modules/relay/src/main/RelayFormat.scala
+++ b/modules/relay/src/main/RelayFormat.scala
@@ -21,6 +21,7 @@ import lila.memo.{ CacheApi, SettingStore }
import lila.study.MultiPgn
final private class RelayFormatApi(
+ roundRepo: RelayRoundRepo,
ws: StandaloneWSClient,
cacheApi: CacheApi,
proxyCredentials: SettingStore[Option[Credentials]] @@ ProxyCredentials,
@@ -29,68 +30,46 @@ final private class RelayFormatApi(
)(using Executor):
import RelayFormat.*
- import RelayRound.Sync.{ FetchableUpstream, UpstreamUrl, UpstreamLcc }
- private val cache = cacheApi[(FetchableUpstream, CanProxy), RelayFormat](64, "relay.format"):
+ private val cache = cacheApi[(URL, CanProxy), RelayFormat](64, "relay.format"):
_.expireAfterWrite(5 minutes)
.buildAsyncFuture: (url, proxy) =>
guessFormat(url)(using proxy)
- def get(upstream: FetchableUpstream)(using proxy: CanProxy): Fu[RelayFormat] =
- cache.get(upstream -> proxy)
+ def get(url: URL)(using proxy: CanProxy): Fu[RelayFormat] =
+ cache.get(url -> proxy)
- def refresh(upstream: FetchableUpstream): Unit =
+ def refresh(url: URL): Unit =
CanProxy
.from(List(false, true))
.foreach: proxy =>
- cache.invalidate(upstream -> proxy)
-
- private def guessFormat(upstream: FetchableUpstream)(using CanProxy): Fu[RelayFormat] = {
-
- def parsedUrl = URL.parse(upstream.fetchUrl)
-
- def guessLcc: Fu[Option[RelayFormat]] = upstream.isLcc.so(guessManyFiles(parsedUrl))
-
- def guessSingleFile(url: URL): Fu[Option[RelayFormat]] =
- List(
- url.some,
- (!url.pathSegments.contains(mostCommonSingleFileName)).option(
- addPart(url, mostCommonSingleFileName)
- )
- ).flatten.distinct
- .findM(looksLikePgn)
- .dmap2: (u: URL) =>
- SingleFile(pgnDoc(u))
-
- def guessManyFiles(url: URL): Fu[Option[RelayFormat]] =
- (List(url) ::: mostCommonIndexNames
- .filterNot(url.pathSegments.contains)
- .map(addPart(url, _)))
- .findM(looksLikeJson)
- .flatMapz: index =>
- val jsonUrl = (n: Int) => jsonDoc(replaceLastPart(index, s"game-$n.json"))
- val pgnUrl = (n: Int) => pgnDoc(replaceLastPart(index, s"game-$n.pgn"))
- looksLikeJson(jsonUrl(1).url)
- .recover:
- case NotFound(_) => false
- .map(_.option(jsonUrl))
- .orElse:
- looksLikePgn(pgnUrl(1).url)
- .recover:
- case NotFound(_) => false
- .map(_.option(pgnUrl))
- .dmap2:
- ManyFiles(index, _)
- .dmap(_.orElse(ManyFilesLater(index).some))
-
- guessLcc
- .orElse(guessSingleFile(parsedUrl))
- .orElse(guessManyFiles(parsedUrl))
- .orFailWith(LilaInvalid(s"No games found at $upstream"))
-
- }.addEffect { format =>
- logger.info(s"guessed format of $upstream: $format")
- }
+ cache.invalidate(url -> proxy)
+
+ private def guessFormat(url: URL)(using CanProxy): Fu[RelayFormat] =
+ RelayRound.Sync.Upstream
+ .Url(url)
+ .lcc
+ .match
+ case Some(lcc) =>
+ looksLikeJson(lcc.indexUrl).flatMapz:
+ looksLikeJson(lcc.gameUrl(1))
+ .recoverDefault(false)(_ => ())
+ .map:
+ if _ then LccWithGames(lcc).some
+ else LccWithoutGames(lcc).some
+ case None =>
+ guessRelayRound(url).orElse:
+ looksLikePgn(url).mapz(SingleFile(url).some)
+ .orFailWith(LilaInvalid(s"No games found at $url"))
+ .addEffect: format =>
+ logger.info(s"guessed format of $url: $format")
+
+ private def guessRelayRound(url: URL): Fu[Option[RelayFormat.Round]] =
+ RelayRound.Sync.Upstream
+ .Url(url)
+ .roundId
+ .so: id =>
+ roundRepo.exists(id).map(_.option(RelayFormat.Round(id)))
private[relay] def httpGet(url: URL)(using CanProxy): Fu[String] =
httpGetResponse(url).map(_.body)
@@ -115,7 +94,7 @@ final private class RelayFormatApi(
.get()
.flatMap: res =>
if res.status == 200 then fuccess(res)
- else if res.status == 404 then fufail(NotFound(url.toString))
+ else if res.status == 404 then fufail(NotFound(url))
else fufail(s"[${res.status}] $url")
.monSuccess(_.relay.httpGet(url.host.toString, proxy))
@@ -151,37 +130,18 @@ final private class RelayFormatApi(
catch case _: Exception => false
private def looksLikeJson(url: URL)(using CanProxy): Fu[Boolean] = httpGet(url).map(looksLikeJson)
-sealed private trait RelayFormat
+private enum RelayFormat:
+ case Round(id: RelayRoundId)
+ case SingleFile(url: URL)
+ case LccWithGames(lcc: RelayRound.Sync.Lcc)
+ // there will be game files with names like "game-1.json" or "game-1.pgn"
+ // but not at the moment. The index is still useful.
+ case LccWithoutGames(lcc: RelayRound.Sync.Lcc)
private object RelayFormat:
opaque type CanProxy = Boolean
object CanProxy extends YesNo[CanProxy]
- enum DocFormat:
- case Json, Pgn
-
- case class RemoteDoc(url: URL, format: DocFormat)
-
- def jsonDoc(url: URL) = RemoteDoc(url, DocFormat.Json)
- def pgnDoc(url: URL) = RemoteDoc(url, DocFormat.Pgn)
-
- case class SingleFile(doc: RemoteDoc) extends RelayFormat
-
- type GameNumberToDoc = Int => RemoteDoc
-
- case class ManyFiles(jsonIndex: URL, game: GameNumberToDoc) extends RelayFormat:
- override def toString = s"Manyfiles($jsonIndex, ${game(0)})"
-
- // there will be game files with names like "game-1.json" or "game-1.pgn"
- // but not at the moment. The index is still useful.
- case class ManyFilesLater(jsonIndex: URL) extends RelayFormat:
- override def toString = s"ManyfilesLater($jsonIndex)"
-
- def addPart(url: URL, part: String) = url.withPath(s"${url.path}/$part")
- def replaceLastPart(url: URL, withPart: String) = url.withPath(s"${url.path}/../$withPart")
-
- val mostCommonSingleFileName = "games.pgn"
- val mostCommonIndexNames = List("round.json", "index.json")
-
- case class NotFound(message: String) extends LilaException
+ case class NotFound(url: URL) extends LilaException:
+ override val message = s"404: $url"
diff --git a/modules/relay/src/main/RelayGame.scala b/modules/relay/src/main/RelayGame.scala
index dee3cc97ad08f..0a033b8e44edf 100644
--- a/modules/relay/src/main/RelayGame.scala
+++ b/modules/relay/src/main/RelayGame.scala
@@ -4,12 +4,13 @@ import chess.format.pgn.{ Tag, TagType, Tags }
import lila.study.{ MultiPgn, StudyPgnImport, PgnDump }
import lila.tree.Root
+import chess.Outcome
case class RelayGame(
tags: Tags,
variant: chess.variant.Variant,
root: Root,
- ending: Option[StudyPgnImport.End]
+ outcome: Option[Outcome]
):
// We don't use tags.boardNumber.
@@ -31,8 +32,8 @@ case class RelayGame(
def resetToSetup = copy(
root = root.withoutChildren,
- ending = None,
- tags = tags.copy(value = tags.value.filter(_.name != Tag.Result))
+ tags = tags.copy(value = tags.value.filter(_.name != Tag.Result)),
+ outcome = None
)
def fideIdsPair: Option[PairOf[Option[chess.FideId]]] =
@@ -42,6 +43,8 @@ case class RelayGame(
List(RelayGame.whiteTags, RelayGame.blackTags).exists:
_.forall(tag => tags(tag).isEmpty)
+ def showResult = Outcome.showResult(outcome)
+
private object RelayGame:
val lichessDomains = List("lichess.org", "lichess.dev")
@@ -53,6 +56,13 @@ private object RelayGame:
val whiteTags: TagNames = List(_.White, _.WhiteFideId)
val blackTags: TagNames = List(_.Black, _.BlackFideId)
+ def fromChapter(c: lila.study.Chapter) = RelayGame(
+ tags = c.tags,
+ variant = c.setup.variant,
+ root = c.root,
+ outcome = c.tags.outcome
+ )
+
import scalalib.Iso
import chess.format.pgn.{ InitialComments, Pgn }
val iso: Iso[RelayGames, MultiPgn] =
@@ -62,7 +72,8 @@ private object RelayGame:
variations = false,
clocks = true,
source = true,
- orientation = false
+ orientation = false,
+ site = none
)
Iso[RelayGames, MultiPgn](
gs =>
diff --git a/modules/relay/src/main/RelayListing.scala b/modules/relay/src/main/RelayListing.scala
index 49191e9c3f330..dfceff7f8ec77 100644
--- a/modules/relay/src/main/RelayListing.scala
+++ b/modules/relay/src/main/RelayListing.scala
@@ -26,10 +26,9 @@ final class RelayListing(
local = "_id",
foreign = "tourId",
pipe = List(
- $doc("$match" -> $doc("finished" -> false)),
- $doc("$addFields" -> $doc("sync.log" -> $arr())),
- $doc("$sort" -> RelayRoundRepo.sort.chrono),
- $doc("$limit" -> 1)
+ $doc("$match" -> $doc("finished" -> false)),
+ $doc("$sort" -> RelayRoundRepo.sort.chrono),
+ $doc("$limit" -> 1)
)
)
for
diff --git a/modules/relay/src/main/RelayPgnStream.scala b/modules/relay/src/main/RelayPgnStream.scala
index 895fa2a2fef77..84d06cbdd9d40 100644
--- a/modules/relay/src/main/RelayPgnStream.scala
+++ b/modules/relay/src/main/RelayPgnStream.scala
@@ -27,7 +27,8 @@ final class RelayPgnStream(
variations = false,
clocks = true,
source = false,
- orientation = false
+ orientation = false,
+ site = none
)
private val fileR = """[\s,]""".r
private val dateFormatter = java.time.format.DateTimeFormatter.ofPattern("yyyy.MM.dd")
diff --git a/modules/relay/src/main/RelayPush.scala b/modules/relay/src/main/RelayPush.scala
index 96b45d85c5b75..bdcdb12df6f74 100644
--- a/modules/relay/src/main/RelayPush.scala
+++ b/modules/relay/src/main/RelayPush.scala
@@ -7,17 +7,19 @@ import chess.{ ErrorStr, Game, Replay, Square }
import scala.concurrent.duration.*
import scalalib.actor.AsyncActorSequencers
-import lila.study.{ MultiPgn, StudyPgnImport }
+import lila.study.{ MultiPgn, StudyPgnImport, ChapterPreviewApi }
final class RelayPush(
sync: RelaySync,
api: RelayApi,
stats: RelayStatsApi,
+ chapterPreview: ChapterPreviewApi,
+ fidePlayers: RelayFidePlayerApi,
irc: lila.core.irc.IrcApi
)(using ActorSystem, Executor, Scheduler):
private val workQueue = AsyncActorSequencers[RelayRoundId](
- maxSize = Max(8),
+ maxSize = Max(32),
expiration = 1 minute,
timeout = 10 seconds,
name = "relay.push",
@@ -31,31 +33,40 @@ final class RelayPush(
if rt.round.sync.hasUpstream
then fuccess(List(Left(Failure(Tags.empty, "The relay has an upstream URL, and cannot be pushed to."))))
else
- val parsed = pgnToGames(pgn)
- val games = parsed.collect { case Right(g) => g }.toVector
- val response = parsed.map(_.map(g => Success(g.tags, g.root.mainline.size)))
+ val parsed = pgnToGames(pgn)
+ val games = parsed.collect { case Right(g) => g }.toVector
+ val response: List[Either[Failure, Success]] =
+ parsed.map(_.map(g => Success(g.tags, g.root.mainline.size)))
+ val andSyncTargets = response.exists(_.isRight)
- rt.round.sync.nonEmptyDelay.fold(push(rt, games).inject(response)): delay =>
- after(delay.value.seconds)(push(rt, games))
- fuccess(response)
+ rt.round.sync.nonEmptyDelay match
+ case None => push(rt, games, andSyncTargets).inject(response)
+ case Some(delay) =>
+ after(delay.value.seconds)(push(rt, games, andSyncTargets))
+ fuccess(response)
- private def push(rt: RelayRound.WithTour, games: Vector[RelayGame]) =
+ private def push(rt: RelayRound.WithTour, rawGames: Vector[RelayGame], andSyncTargets: Boolean) =
workQueue(rt.round.id):
- sync
- .updateStudyChapters(rt, rt.tour.players.fold(games)(_.update(games)))
- .map: res =>
- SyncLog.event(res.nbMoves, none)
- .recover:
- case e: Exception => SyncLog.event(0, e.some)
- .flatMap: event =>
- if !rt.round.hasStarted && !rt.tour.official && event.hasMoves then
- irc.broadcastStart(rt.round.id, rt.fullName)
- stats.setActive(rt.round.id)
- api
- .update(rt.round): r1 =>
- val r2 = r1.withSync(_.addLog(event))
- val r3 = if event.hasMoves then r2.ensureStarted.resume(rt.tour.official) else r2
- r3.copy(finished = games.nonEmpty && games.forall(_.ending.isDefined))
+ for
+ withPlayers <- fuccess(rt.tour.players.fold(rawGames)(_.update(rawGames)))
+ games <- fidePlayers.enrichGames(rt.tour)(withPlayers)
+ event <- sync
+ .updateStudyChapters(rt, rt.tour.players.fold(games)(_.update(games)))
+ .map: res =>
+ SyncLog.event(res.nbMoves, none)
+ .recover:
+ case e: Exception => SyncLog.event(0, e.some)
+ _ = if !rt.round.hasStarted && !rt.tour.official && event.hasMoves then
+ irc.broadcastStart(rt.round.id, rt.fullName)
+ _ = stats.setActive(rt.round.id)
+ allGamesFinished <- (games.nonEmpty && games.forall(_.outcome.isDefined)).so:
+ chapterPreview.dataList(rt.round.studyId).map(_.forall(_.finished))
+ round <- api.update(rt.round): r1 =>
+ val r2 = r1.withSync(_.addLog(event))
+ val r3 = if event.hasMoves then r2.ensureStarted.resume(rt.tour.official) else r2
+ r3.copy(finished = allGamesFinished)
+ _ <- andSyncTargets.so(api.syncTargetsOfSource(round))
+ yield ()
private def pgnToGames(pgnBody: PgnStr): List[Either[Failure, RelayGame]] =
MultiPgn
@@ -75,7 +86,7 @@ final class RelayPush(
children = game.root.children
.updateMainline(_.copy(comments = lila.tree.Node.Comments.empty))
),
- ending = game.end
+ outcome = game.end.map(_.outcome)
)
)
diff --git a/modules/relay/src/main/RelayRound.scala b/modules/relay/src/main/RelayRound.scala
index 6308fe4d0f26c..c655e1ae1798d 100644
--- a/modules/relay/src/main/RelayRound.scala
+++ b/modules/relay/src/main/RelayRound.scala
@@ -5,6 +5,7 @@ import reactivemongo.api.bson.Macros.Annotations.Key
import scalalib.model.Seconds
import lila.study.Study
+import io.mola.galimatias.URL
case class RelayRound(
/* Same as the Study id it refers to */
@@ -51,8 +52,6 @@ case class RelayRound(
case Some(at) => at.isBefore(nowInstant.minusHours(3))
case None => createdAt.isBefore(nowInstant.minusDays(1))
- def stateHash = (hasStarted, finished)
-
def withSync(f: RelayRound.Sync => RelayRound.Sync) = copy(sync = f(sync))
def withTour(tour: RelayTour) = RelayRound.WithTour(this, tour)
@@ -80,12 +79,13 @@ object RelayRound:
log: SyncLog
):
def hasUpstream = upstream.isDefined
+ def isPush = upstream.isEmpty
def renew(official: Boolean) =
if hasUpstream then copy(until = nowInstant.plusHours(if official then 3 else 1).some)
else pause
- def ongoing = until.so(nowInstant.isBefore)
+ def ongoing = until.so(_.isAfterNow)
def play(official: Boolean) =
if hasUpstream then renew(official).copy(nextAt = nextAt.orElse(nowInstant.plusSeconds(3).some))
@@ -114,30 +114,46 @@ object RelayRound:
override def toString = upstream.toString
object Sync:
- sealed trait Upstream:
- def isLcc = false
- sealed trait FetchableUpstream extends Upstream:
- def fetchUrl: String
- def formUrl: String
- case class UpstreamUrl(url: String) extends FetchableUpstream:
- def fetchUrl = url
- def formUrl = url
- case class UpstreamUrls(urls: List[FetchableUpstream]) extends Upstream
- case class UpstreamIds(ids: List[GameId]) extends Upstream
- case class UpstreamLcc(lcc: String, round: Int) extends FetchableUpstream:
- override def isLcc = true
- def id = lcc
- def fetchUrl = s"http://1.pool.livechesscloud.com/get/$id/round-$round/index.json"
- def viewUrl = s"https://view.livechesscloud.com/#$id"
- def formUrl = s"$viewUrl $round"
- object UpstreamLcc:
- private val idRegex = """.*view\.livechesscloud\.com/?#?([0-9a-f\-]+)""".r
- def findId(url: UpstreamUrl): Option[String] = url.url match
- case idRegex(id) => id.some
- case _ => none
- def find(url: String): Option[UpstreamLcc] = url.split(' ').map(_.trim).filter(_.nonEmpty) match
- case Array(idRegex(id), round) => round.toIntOption.map(UpstreamLcc(id, _))
- case _ => none
+ enum Upstream:
+ case Url(url: URL) extends Upstream
+ case Urls(urls: List[URL]) extends Upstream
+ case Ids(ids: List[GameId]) extends Upstream
+ def isUrl = this match
+ case Url(_) => true
+ case _ => false
+ def lcc: Option[Lcc] = this match
+ case Url(url) =>
+ url.toString match
+ case lccRegex(id, round) => round.toIntOption.map(Lcc(id, _))
+ case _ => none
+ case _ => none
+ def hasLcc = this match
+ case Url(url) => Sync.looksLikeLcc(url)
+ case Urls(urls) => urls.exists(Sync.looksLikeLcc)
+ case _ => false
+
+ def roundId: Option[RelayRoundId] = this match
+ case Url(url) =>
+ url.path.split("/") match
+ case Array("", "broadcast", _, _, id) =>
+ val cleanId = if id.endsWith(".pgn") then id.dropRight(4) else id
+ (cleanId.size == 8).option(RelayRoundId(cleanId))
+ case _ => none
+ case _ => none
+ def isRound = roundId.isDefined
+ def roundIds: List[RelayRoundId] = this match
+ case url: Url => url.roundId.toList
+ case Urls(urls) => urls.map(Url.apply).flatMap(_.roundId)
+ case _ => Nil
+
+ case class Lcc(id: String, round: Int):
+ def pageUrl = URL.parse(s"https://view.livechesscloud.com/#$id/$round")
+ def indexUrl = URL.parse(s"http://1.pool.livechesscloud.com/get/$id/round-$round/index.json")
+ def gameUrl(game: Int) =
+ URL.parse(s"http://1.pool.livechesscloud.com/get/$id/round-$round/game-$game.json")
+
+ private val lccRegex = """view\.livechesscloud\.com/?#?([0-9a-f\-]+)/(\d+)""".r.unanchored
+ private def looksLikeLcc(url: URL) = url.toString.contains(".livechesscloud.com/")
trait AndTour:
val tour: RelayTour
diff --git a/modules/relay/src/main/RelayRoundForm.scala b/modules/relay/src/main/RelayRoundForm.scala
index ec0a821b282e2..baf87aa94d621 100644
--- a/modules/relay/src/main/RelayRoundForm.scala
+++ b/modules/relay/src/main/RelayRoundForm.scala
@@ -12,24 +12,25 @@ import lila.common.Form.{ cleanText, into, stringIn, formatter }
import lila.core.perm.Granter
import lila.relay.RelayRound.Sync
-import lila.relay.RelayRound.Sync.UpstreamUrl
+import lila.relay.RelayRound.Sync.Upstream
final class RelayRoundForm(using mode: Mode):
import RelayRoundForm.*
import lila.common.Form.ISOInstantOrTimestamp
- private given Formatter[Sync.UpstreamUrl] = formatter.stringTryFormatter(validateUpstreamUrl, _.fetchUrl)
- private given Formatter[Sync.UpstreamUrls] = formatter.stringTryFormatter(
+ private given Formatter[Upstream.Url] =
+ formatter.stringTryFormatter(str => validateUpstreamUrl(str).map(Upstream.Url.apply), _.url.toString)
+ private given Formatter[Upstream.Urls] = formatter.stringTryFormatter(
_.linesIterator.toList
.map(_.trim)
.filter(_.nonEmpty)
- .traverse(validateUpstreamUrlOrLcc)
+ .traverse(validateUpstreamUrl)
.map(_.distinct)
- .map(Sync.UpstreamUrls.apply),
- _.urls.map(_.formUrl).mkString("\n")
+ .map(Upstream.Urls.apply),
+ _.urls.mkString("\n")
)
- private given Formatter[Sync.UpstreamIds] = formatter.stringTryFormatter(
+ private given Formatter[Upstream.Ids] = formatter.stringTryFormatter(
_.split(' ').toList
.map(_.trim)
.traverse: i =>
@@ -38,35 +39,39 @@ final class RelayRoundForm(using mode: Mode):
.map(_.mkString(", "))
.filterOrElse(_.sizeIs <= RelayFetch.maxChapters.value, s"Max games: ${RelayFetch.maxChapters}")
.map(_.distinct)
- .map(Sync.UpstreamIds.apply),
+ .map(Upstream.Ids.apply),
_.ids.mkString(" ")
)
- val lccMapping = mapping(
- "id" -> cleanText(minLength = 10, maxLength = 40),
- "round" -> number(min = 1, max = 999)
- )(Sync.UpstreamLcc.apply)(unapply)
+ private def lccIsComplete(url: Upstream.Url) =
+ url.lcc.isDefined || !url.url.host.toString.endsWith("livechesscloud.com")
- val roundMapping =
+ def roundMapping(using Me) =
mapping(
"name" -> cleanText(minLength = 3, maxLength = 80).into[RelayRound.Name],
"caption" -> optional(cleanText(minLength = 3, maxLength = 80).into[RelayRound.Caption]),
"syncSource" -> optional(stringIn(sourceTypes.map(_._1).toSet)),
- "syncUrl" -> optional(of[Sync.UpstreamUrl]),
- "syncUrls" -> optional(of[Sync.UpstreamUrls]),
- "syncLcc" -> optional(lccMapping),
- "syncIds" -> optional(of[Sync.UpstreamIds]),
- "startsAt" -> optional(ISOInstantOrTimestamp.mapping),
- "finished" -> optional(boolean),
- "period" -> optional(number(min = 2, max = 60).into[Seconds]),
- "delay" -> optional(number(min = 0, max = RelayDelay.maxSeconds.value).into[Seconds]),
- "onlyRound" -> optional(number(min = 1, max = 999)),
+ "syncUrl" -> optional(
+ of[Upstream.Url]
+ .verifying("LCC URLs must end with /{round-number}, e.g. /5 for round 5", lccIsComplete)
+ .verifying(
+ "Invalid source URL",
+ u => !u.url.host.toString.endsWith("lichess.org") || Granter(_.Relay)
+ )
+ ),
+ "syncUrls" -> optional(of[Upstream.Urls]),
+ "syncIds" -> optional(of[Upstream.Ids]),
+ "startsAt" -> optional(ISOInstantOrTimestamp.mapping),
+ "finished" -> optional(boolean),
+ "period" -> optional(number(min = 2, max = 60).into[Seconds]),
+ "delay" -> optional(number(min = 0, max = RelayDelay.maxSeconds.value).into[Seconds]),
+ "onlyRound" -> optional(number(min = 1, max = 999)),
"slices" -> optional:
nonEmptyText
.transform[List[RelayGame.Slice]](RelayGame.Slices.parse, RelayGame.Slices.show)
)(Data.apply)(unapply)
- def create(trs: RelayTour.WithRounds) = Form(
+ def create(trs: RelayTour.WithRounds)(using Me) = Form(
roundMapping
.verifying(
s"Maximum rounds per tournament: ${RelayTour.maxRelays}",
@@ -74,16 +79,21 @@ final class RelayRoundForm(using mode: Mode):
)
).fill(fillFromPrevRounds(trs.rounds))
- def edit(r: RelayRound) = Form(roundMapping).fill(Data.make(r))
+ def edit(r: RelayRound)(using Me) = Form(
+ roundMapping
+ .verifying(
+ "The round source cannot be itself",
+ d => d.syncSource.forall(_ != "url") || d.syncUrl.forall(_.roundId.forall(_ != r.id))
+ )
+ ).fill(Data.make(r))
object RelayRoundForm:
val sourceTypes = List(
+ "push" -> "Broadcaster App",
"url" -> "Single PGN URL",
"urls" -> "Combine several PGN URLs",
- "lcc" -> "LiveChessCloud page",
- "ids" -> "Lichess game IDs",
- "push" -> "Push local games"
+ "ids" -> "Lichess game IDs"
)
private val roundNumberRegex = """([^\d]*)(\d{1,2})([^\d]*)""".r
@@ -108,22 +118,23 @@ object RelayRoundForm:
roundNumberIn(old.name.value).contains(n - 1)
p <- prev
yield replaceRoundNumber(p.name.value, nextNumber)
- val nextLcc: Option[Sync.UpstreamLcc] = prev
- .flatMap(_.sync.upstream)
- .flatMap:
- case lcc: Sync.UpstreamLcc => lcc.copy(round = nextNumber).some
- case _ => none
val guessDate = for
(prev, old) <- prevs
prevDate <- prev.startsAt
oldDate <- old.startsAt
delta = prevDate.toEpochMilli - oldDate.toEpochMilli
yield prevDate.plusMillis(delta)
+ val nextUrl: Option[Upstream.Url] = for
+ p <- prev
+ up <- p.sync.upstream
+ lcc <- up.lcc
+ if prevNumber.contains(lcc.round)
+ yield Upstream.Url(lcc.copy(round = nextNumber).pageUrl)
Data(
name = RelayRound.Name(guessName | s"Round ${nextNumber}"),
caption = prev.flatMap(_.caption),
syncSource = prev.map(Data.make).flatMap(_.syncSource),
- syncLcc = nextLcc,
+ syncUrl = nextUrl,
startsAt = guessDate,
period = prev.flatMap(_.sync.period),
delay = prev.flatMap(_.sync.delay),
@@ -137,7 +148,7 @@ object RelayRoundForm:
val list = ids.split(' ').view.flatMap(i => GameId.from(i.trim)).toList
(list.sizeIs > 0 && list.sizeIs <= RelayFetch.maxChapters.value).option(GameIds(list))
- private def cleanUrl(source: String)(using mode: Mode): Option[String] =
+ private def cleanUrl(source: String)(using mode: Mode): Option[URL] =
for
url <- Try(URL.parse(source)).toOption
if url.scheme == "http" || url.scheme == "https"
@@ -145,26 +156,18 @@ object RelayRoundForm:
// prevent common mistakes (not for security)
if mode.notProd || !blocklist.exists(subdomain(host, _))
if !subdomain(host, "chess.com") || url.toString.startsWith("https://api.chess.com/pub")
- yield url.toString.stripSuffix("/")
-
- private def validateUpstreamUrlOrLcc(s: String)(using Mode): Either[String, Sync.FetchableUpstream] =
- Sync.UpstreamLcc.find(s) match
- case Some(lcc) => Right(lcc)
- case None => validateUpstreamUrl(s)
+ yield url
- private def validateUpstreamUrl(s: String)(using Mode): Either[String, Sync.UpstreamUrl] = for
+ private def validateUpstreamUrl(s: String)(using Mode): Either[String, URL] = for
url <- cleanUrl(s).toRight("Invalid source URL")
url <- if !validSourcePort(url) then Left("The source URL cannot specify a port") else Right(url)
- yield Sync.UpstreamUrl(url)
+ yield url
- private def cleanUrls(source: String)(using mode: Mode): Option[List[String]] =
+ private def cleanUrls(source: String)(using mode: Mode): Option[List[URL]] =
source.linesIterator.toList.flatMap(cleanUrl).some.filter(_.nonEmpty)
- private val validPorts = Set(-1, 80, 443, 8080, 8491)
- private def validSourcePort(source: String)(using mode: Mode): Boolean =
- mode.notProd ||
- Try(URL.parse(source)).toOption.forall: url =>
- validPorts(url.port)
+ private val validPorts = Set(-1, 80, 443, 8080, 8491)
+ private def validSourcePort(url: URL)(using mode: Mode): Boolean = mode.notProd || validPorts(url.port)
private def subdomain(host: String, domain: String) = s".$host".endsWith(s".$domain")
@@ -178,7 +181,6 @@ object RelayRoundForm:
"twitch.com",
"youtube.com",
"youtu.be",
- "lichess.org",
"google.com",
"vk.com",
"chess-results.com",
@@ -192,10 +194,9 @@ object RelayRoundForm:
name: RelayRound.Name,
caption: Option[RelayRound.Caption],
syncSource: Option[String],
- syncUrl: Option[Sync.UpstreamUrl] = None,
- syncUrls: Option[Sync.UpstreamUrls] = None,
- syncLcc: Option[Sync.UpstreamLcc] = None,
- syncIds: Option[Sync.UpstreamIds] = None,
+ syncUrl: Option[Upstream.Url] = None,
+ syncUrls: Option[Upstream.Urls] = None,
+ syncIds: Option[Upstream.Ids] = None,
startsAt: Option[Instant] = None,
finished: Option[Boolean] = None,
period: Option[Seconds] = None,
@@ -203,22 +204,12 @@ object RelayRoundForm:
onlyRound: Option[Int] = None,
slices: Option[List[RelayGame.Slice]] = None
):
- def upstream: Option[Sync.Upstream] = syncSource
- .match
- case None => syncUrl.orElse(syncUrls).orElse(syncIds)
- case Some("url") => syncUrl
- case Some("urls") => syncUrls
- case Some("lcc") => syncLcc
- case Some("ids") => syncIds
- case _ => None
- .map:
- case url: Sync.UpstreamUrl =>
- val foundLcc = for
- lccId <- Sync.UpstreamLcc.findId(url)
- round <- roundNumberIn(name.value)
- yield Sync.UpstreamLcc(lccId, round)
- foundLcc | url
- case up => up
+ def upstream: Option[Upstream] = syncSource.match
+ case None => syncUrl.orElse(syncUrls).orElse(syncIds)
+ case Some("url") => syncUrl
+ case Some("urls") => syncUrls
+ case Some("ids") => syncIds
+ case _ => None
def update(official: Boolean)(relay: RelayRound)(using me: Me)(using mode: Mode) =
val sync = makeSync(me)
@@ -264,20 +255,17 @@ object RelayRoundForm:
caption = relay.caption,
syncSource = relay.sync.upstream
.fold("push"):
- case _: Sync.UpstreamUrl => "url"
- case _: Sync.UpstreamUrls => "urls"
- case _: Sync.UpstreamLcc => "lcc"
- case _: Sync.UpstreamIds => "ids"
+ case _: Upstream.Url => "url"
+ case _: Upstream.Urls => "urls"
+ case _: Upstream.Ids => "ids"
.some,
syncUrl = relay.sync.upstream.collect:
- case url: Sync.UpstreamUrl => url,
+ case url: Upstream.Url => url,
syncUrls = relay.sync.upstream.collect:
- case url: Sync.UpstreamUrl => Sync.UpstreamUrls(List(url))
- case urls: Sync.UpstreamUrls => urls,
- syncLcc = relay.sync.upstream.collect:
- case lcc: Sync.UpstreamLcc => lcc,
+ case url: Upstream.Url => Upstream.Urls(List(url.url))
+ case urls: Upstream.Urls => urls,
syncIds = relay.sync.upstream.collect:
- case ids: Sync.UpstreamIds => ids,
+ case ids: Upstream.Ids => ids,
startsAt = relay.startsAt,
finished = relay.finished.option(true),
period = relay.sync.period,
diff --git a/modules/relay/src/main/RelayRoundRepo.scala b/modules/relay/src/main/RelayRoundRepo.scala
index eedde0a66ac91..74b267e162c40 100644
--- a/modules/relay/src/main/RelayRoundRepo.scala
+++ b/modules/relay/src/main/RelayRoundRepo.scala
@@ -10,6 +10,8 @@ final private class RelayRoundRepo(val coll: Coll)(using Executor):
import RelayRoundRepo.*
import BSONHandlers.given
+ def exists(id: RelayRoundId): Fu[Boolean] = coll.exists($id(id))
+
def byTourOrderedCursor(tourId: RelayTourId) =
coll
.find(selectors.tour(tourId))
@@ -49,6 +51,14 @@ final private class RelayRoundRepo(val coll: Coll)(using Executor):
def studyIdsOf(tourId: RelayTourId): Fu[List[StudyId]] =
coll.distinctEasy[StudyId, List]("_id", selectors.tour(tourId))
+ def syncTargetsOfSource(source: RelayRoundId): Funit =
+ coll.update
+ .one(
+ $doc("sync.until".$exists(true), "sync.upstream.roundIds" -> source),
+ $set("sync.nextAt" -> nowInstant)
+ )
+ .void
+
private object RelayRoundRepo:
object sort:
diff --git a/modules/relay/src/main/RelayStatsApi.scala b/modules/relay/src/main/RelayStatsApi.scala
index 42fdd86a7eaef..ea963452496c8 100644
--- a/modules/relay/src/main/RelayStatsApi.scala
+++ b/modules/relay/src/main/RelayStatsApi.scala
@@ -8,7 +8,7 @@ object RelayStats:
type Minute = Int
type Crowd = Int
type Graph = List[(Minute, Crowd)]
- case class RoundStats(round: RelayRound, viewers: Graph)
+ case class RoundStats(viewers: Graph)
final class RelayStatsApi(roundRepo: RelayRoundRepo, colls: RelayColls)(using scheduler: Scheduler)(using
Executor
@@ -17,39 +17,22 @@ final class RelayStatsApi(roundRepo: RelayRoundRepo, colls: RelayColls)(using sc
import BSONHandlers.given
// on measurement by minute at most; the storage depends on it.
- scheduler.scheduleWithFixedDelay(1 minute, 1 minute)(() => record())
+ scheduler.scheduleWithFixedDelay(2 minutes, 2 minutes)(() => record())
- def get(id: RelayTourId): Fu[List[RoundStats]] =
- colls.round
- .aggregateList(RelayTour.maxRelays): framework =>
- import framework.*
- Match($doc("tourId" -> id)) -> List(
- Sort(Ascending("createdAt")),
- AddFields($doc("sync.log" -> $arr())),
- PipelineOperator(
- $lookup.simple(colls.stats, "stats", "_id", "_id")
- ),
- AddFields($doc("stats" -> $doc("$first" -> "$stats")))
- )
- .map: docs =>
- for
- doc <- docs
- round <- doc.asOpt[RelayRound]
- data = for
- doc <- doc.getAsOpt[Bdoc]("stats")
- data <- doc.getAsOpt[List[Int]]("d")
- yield data
- stats = data.so:
- _.grouped(2)
- .collect:
- case List(minute, crowd) => (minute, crowd)
- .toList
- yield RoundStats(round, stats)
+ def get(id: RelayRoundId): Fu[RoundStats] =
+ colls.stats
+ .primitiveOne[List[Int]]($id(id), "d")
+ .mapz:
+ _.grouped(2)
+ .collect:
+ case List(minute, crowd) => (minute, crowd)
+ .toList
+ .map(RoundStats.apply)
def setActive(id: RelayRoundId) = activeRounds.put(id)
- // keep monitoring rounds for 30m after they stopped syncing
- private val activeRounds = ExpireSetMemo[RelayRoundId](30 minutes)
+ // keep monitoring rounds for some time after they stopped syncing
+ private val activeRounds = ExpireSetMemo[RelayRoundId](2 hours)
private def record(): Funit = for
crowds <- fetchRoundCrowds
diff --git a/modules/relay/src/main/RelaySync.scala b/modules/relay/src/main/RelaySync.scala
index 50b8ee4b7cc9f..8a5dffc9188b7 100644
--- a/modules/relay/src/main/RelaySync.scala
+++ b/modules/relay/src/main/RelaySync.scala
@@ -23,7 +23,7 @@ final private class RelaySync(
plan = RelayUpdatePlan(chapters, games)
_ <- plan.reorder.so(studyApi.sortChapters(study.id, _)(who(study.ownerId)))
updates <- plan.update.sequentially: (chapter, game) =>
- updateChapter(rt.tour, study, game, chapter)
+ updateChapter(rt, study, game, chapter)
appends <- plan.append.toList.sequentially: game =>
createChapter(rt, study, game)
result = SyncResult.Ok(updates ::: appends.flatten, games)
@@ -32,14 +32,15 @@ final private class RelaySync(
yield result
private def updateChapter(
- tour: RelayTour,
+ rt: RelayRound.WithTour,
study: Study,
game: RelayGame,
chapter: Chapter
): Fu[SyncResult.ChapterResult] = for
chapter <- updateInitialPosition(study.id, chapter, game)
- tagUpdate <- updateChapterTags(tour, study, chapter, game)
- nbMoves <- updateChapterTree(study, chapter, game)(using tour)
+ tagUpdate <- updateChapterTags(rt.tour, study, chapter, game)
+ nbMoves <- updateChapterTree(study, chapter, game)(using rt.tour)
+ _ <- (nbMoves > 0).so(notifier.roundBegin(rt))
yield SyncResult.ChapterResult(chapter.id, tagUpdate, nbMoves)
private def createChapter(
@@ -53,8 +54,6 @@ final private class RelaySync(
(RelayFetch.maxChapters > nb).so:
createChapter(study, game)(using rt.tour).map: chapter =>
SyncResult.ChapterResult(chapter.id, true, chapter.root.mainline.size).some
- .flatMapz: result =>
- ((result.newMoves > 0).so(notifier.roundBegin(rt))).inject(result.some)
private def updateInitialPosition(studyId: StudyId, chapter: Chapter, game: RelayGame): Fu[Chapter] =
if game.root.mainline.sizeIs > 1 || game.root.fen == chapter.root.fen
@@ -124,10 +123,11 @@ final private class RelaySync(
val gameTags = game.tags.value.foldLeft(Tags(Nil)): (newTags, tag) =>
if !chapter.tags.value.has(tag) then newTags + tag
else newTags
- val newEndTag = game.ending
- .ifFalse(gameTags(_.Result).isDefined)
- .filterNot(end => chapter.tags(_.Result).has(end.resultText))
- .map(end => Tag(_.Result, end.resultText))
+ val newEndTag = (
+ game.outcome.isDefined &&
+ gameTags(_.Result).isEmpty &&
+ !chapter.tags(_.Result).has(game.showResult)
+ ).option(Tag(_.Result, game.showResult))
val tags = newEndTag.fold(gameTags)(gameTags + _)
val chapterNewTags = tags.value.foldLeft(chapter.tags): (chapterTags, tag) =>
PgnTags(chapterTags + tag)
@@ -215,8 +215,9 @@ sealed trait SyncResult:
val reportKey: String
object SyncResult:
case class Ok(chapters: List[ChapterResult], games: RelayGames) extends SyncResult:
- def nbMoves = chapters.foldLeft(0)(_ + _.newMoves)
- val reportKey = "ok"
+ def nbMoves = chapters.foldLeft(0)(_ + _.newMoves)
+ def hasMovesOrTags = chapters.exists(c => c.newMoves > 0 || c.tagUpdate)
+ val reportKey = "ok"
case object Timeout extends Exception with SyncResult with util.control.NoStackTrace:
val reportKey = "timeout"
override def getMessage = "In progress..."
diff --git a/modules/relay/src/main/RelayTeams.scala b/modules/relay/src/main/RelayTeams.scala
index 3d9f83e3e3df0..3eac1fb74b8b6 100644
--- a/modules/relay/src/main/RelayTeams.scala
+++ b/modules/relay/src/main/RelayTeams.scala
@@ -78,7 +78,9 @@ final class RelayTeamTable(
.dataList(studyId)
.map: chapters =>
import json.given
- JsonStr(Json.stringify(Json.obj("table" -> makeTable(chapters))))
+ val table = makeTable(chapters)
+ val ordered = ensureFirstPlayerHasWhite(table)
+ JsonStr(Json.stringify(Json.obj("table" -> ordered)))
case class TeamWithPoints(name: String, points: Float = 0):
def add(o: Option[Outcome], as: Color) =
@@ -93,7 +95,8 @@ final class RelayTeamTable(
def bimap[B](f: A => B, g: A => B) = Pair(f(a), g(b))
def reverse = Pair(b, a)
- case class TeamGame(id: StudyChapterId, pov: Color)
+ case class TeamGame(id: StudyChapterId, pov: Color):
+ def swap = copy(pov = !pov)
case class TeamMatch(teams: Pair[TeamWithPoints], games: List[TeamGame]):
def is(teamNames: Pair[TeamName]) = teams.map(_.name).is(teamNames)
@@ -108,6 +111,7 @@ final class RelayTeamTable(
games = TeamGame(chap.id, t0Color) :: games,
teams = teams.bimap(_.add(outcome, t0Color), _.add(outcome, !t0Color))
)
+ def swap = copy(teams = teams.reverse, games = games.map(_.swap))
def makeTable(chapters: List[ChapterPreview]): List[TeamMatch] =
chapters.reverse.foldLeft(List.empty[TeamMatch]): (table, chap) =>
@@ -120,6 +124,11 @@ final class RelayTeamTable(
newTable = m1 :: table.filterNot(_.is(teams))
yield newTable) | table
+ def ensureFirstPlayerHasWhite(table: List[TeamMatch]): List[TeamMatch] =
+ table.map: m =>
+ if m.games.headOption.forall(_.pov.white) then m
+ else m.swap
+
object json:
import lila.common.Json.given
given [A: Writes]: Writes[Pair[A]] = Writes: p =>
diff --git a/modules/relay/src/main/RelayTour.scala b/modules/relay/src/main/RelayTour.scala
index f0c106eed16e5..8a3be5508a83a 100644
--- a/modules/relay/src/main/RelayTour.scala
+++ b/modules/relay/src/main/RelayTour.scala
@@ -5,11 +5,12 @@ import reactivemongo.api.bson.Macros.Annotations.Key
import lila.core.i18n.Language
import lila.core.misc.PicfitUrl
import lila.core.id.ImageId
+import java.time.LocalDate
case class RelayTour(
@Key("_id") id: RelayTourId,
name: RelayTour.Name,
- description: String,
+ info: RelayTour.Info,
markup: Option[Markdown] = None,
ownerId: UserId,
createdAt: Instant,
@@ -23,6 +24,7 @@ case class RelayTour(
players: Option[RelayPlayersTextarea] = None,
teams: Option[RelayTeamsTextarea] = None,
image: Option[ImageId] = None,
+ dates: Option[RelayTour.Dates] = None, // denormalized from round dates
pinnedStreamer: Option[UserStr] = None,
pinnedStreamerImage: Option[ImageId] = None
):
@@ -74,6 +76,17 @@ object RelayTour:
)
type Selector = RelayTour.Tier.type => RelayTour.Tier
+ case class Info(
+ format: Option[String],
+ tc: Option[String],
+ players: Option[String]
+ ):
+ val all = List(format, tc, players).flatten
+ export all.nonEmpty
+ override def toString = all.mkString(" | ")
+
+ case class Dates(start: Instant, end: Option[Instant])
+
case class Spotlight(enabled: Boolean, language: Language, title: Option[String]):
def isEmpty = !enabled && specialLanguage.isEmpty && title.isEmpty
def specialLanguage: Option[Language] = (language != lila.core.i18n.defaultLanguage).option(language)
@@ -85,7 +98,14 @@ object RelayTour:
display: RelayRound, // which round to show on the tour link
link: RelayRound, // which round to actually link to
group: Option[RelayGroup.Name]
- ) extends RelayRound.AndTourAndGroup
+ ) extends RelayRound.AndTourAndGroup:
+ def errors: List[String] =
+ val round = display
+ ~round.sync.log.lastErrors.some
+ .filter(_.nonEmpty)
+ .orElse:
+ (round.hasStarted && round.sync.upstream.isDefined && !round.sync.ongoing)
+ .option(List("Not syncing!"))
case class WithLastRound(tour: RelayTour, round: RelayRound, group: Option[RelayGroup.Name])
extends RelayRound.AndTourAndGroup:
diff --git a/modules/relay/src/main/RelayTourForm.scala b/modules/relay/src/main/RelayTourForm.scala
index b5bbc133ed8b3..7a792c8fdba27 100644
--- a/modules/relay/src/main/RelayTourForm.scala
+++ b/modules/relay/src/main/RelayTourForm.scala
@@ -3,7 +3,7 @@ package lila.relay
import play.api.data.*
import play.api.data.Forms.*
-import lila.common.Form.{ cleanText, formatter, into, numberIn }
+import lila.common.Form.{ cleanText, formatter, into, numberIn, ISODate }
import lila.core.perm.Granter
import lila.core.i18n.I18nKey.streamer
@@ -17,10 +17,16 @@ final class RelayTourForm(langList: lila.core.i18n.LangList):
RelayTour.Spotlight.apply
)(unapply)
+ val infoMapping = mapping(
+ "format" -> optional(cleanText(maxLength = 80)),
+ "tc" -> optional(cleanText(maxLength = 80)),
+ "players" -> optional(cleanText(maxLength = 120))
+ )(RelayTour.Info.apply)(unapply)
+
val form = Form(
mapping(
"name" -> cleanText(minLength = 3, maxLength = 80).into[RelayTour.Name],
- "description" -> cleanText(minLength = 3, maxLength = 400),
+ "info" -> infoMapping,
"markdown" -> optional(cleanText(maxLength = 20_000).into[Markdown]),
"tier" -> optional(numberIn(RelayTour.Tier.keys.keySet)),
"autoLeaderboard" -> boolean,
@@ -45,7 +51,7 @@ object RelayTourForm:
case class Data(
name: RelayTour.Name,
- description: String,
+ info: RelayTour.Info,
markup: Option[Markdown],
tier: Option[RelayTour.Tier],
autoLeaderboard: Boolean,
@@ -61,9 +67,9 @@ object RelayTourForm:
tour
.copy(
name = name,
- description = description,
+ info = info,
markup = markup,
- tier = tier.ifTrue(Granter(_.Relay)),
+ tier = if Granter(_.Relay) then tier else tour.tier,
autoLeaderboard = autoLeaderboard,
teamTable = teamTable,
players = players,
@@ -77,7 +83,7 @@ object RelayTourForm:
RelayTour(
id = RelayTour.makeId,
name = name,
- description = description,
+ info = info,
markup = markup,
ownerId = me,
tier = tier.ifTrue(Granter(_.Relay)),
@@ -99,7 +105,7 @@ object RelayTourForm:
import tg.*
Data(
name = tour.name,
- description = tour.description,
+ info = tour.info,
markup = tour.markup,
tier = tour.tier,
autoLeaderboard = tour.autoLeaderboard,
diff --git a/modules/relay/src/main/RelayTourRepo.scala b/modules/relay/src/main/RelayTourRepo.scala
index fed24b208718d..6c285ea803f7c 100644
--- a/modules/relay/src/main/RelayTourRepo.scala
+++ b/modules/relay/src/main/RelayTourRepo.scala
@@ -11,8 +11,13 @@ final private class RelayTourRepo(val coll: Coll)(using Executor):
def setSyncedNow(tour: RelayTour): Funit =
coll.updateField($id(tour.id), "syncedAt", nowInstant).void
- def setActive(tourId: RelayTourId, active: Boolean, live: Boolean): Funit =
- coll.update.one($id(tourId), $set("active" -> active, "live" -> live)).void
+ def denormalize(
+ tourId: RelayTourId,
+ active: Boolean,
+ live: Boolean,
+ dates: Option[RelayTour.Dates]
+ ): Funit =
+ coll.update.one($id(tourId), $set("active" -> active, "live" -> live, "dates" -> dates)).void
def lookup(local: String) = $lookup.simple(coll, "tour", local, "_id")
diff --git a/modules/relay/src/main/SyncLog.scala b/modules/relay/src/main/SyncLog.scala
index 177098d87b2eb..e3e059884100b 100644
--- a/modules/relay/src/main/SyncLog.scala
+++ b/modules/relay/src/main/SyncLog.scala
@@ -10,6 +10,8 @@ case class SyncLog(events: Vector[SyncLog.Event]) extends AnyVal:
def updatedAt = events.lastOption.map(_.at)
+ def lastErrors: List[String] = events.reverse.takeWhile(_.isKo).flatMap(_.error).toList
+
def add(event: SyncLog.Event) =
copy(
events = {
diff --git a/modules/relay/src/main/ui/FormUi.scala b/modules/relay/src/main/ui/FormUi.scala
index f423b2fd6be4a..bdec0f8f73cb7 100644
--- a/modules/relay/src/main/ui/FormUi.scala
+++ b/modules/relay/src/main/ui/FormUi.scala
@@ -6,17 +6,23 @@ import scalalib.paginator.Paginator
import lila.ui.*
import ScalatagsTemplate.{ *, given }
import play.api.data.Form
-import lila.core.id.ImageId
case class FormNavigation(
group: Option[RelayGroup.WithTours],
tour: RelayTour,
rounds: List[RelayRound],
- round: Option[RelayRoundId],
+ roundId: Option[RelayRoundId],
+ sourceRound: Option[RelayRound.WithTour] = none,
+ targetRound: Option[RelayRound.WithTour] = none,
newRound: Boolean = false
):
def tourWithGroup = RelayTour.WithGroupTours(tour, group)
def tourWithRounds = RelayTour.WithRounds(tour, rounds)
+ def round = roundId.flatMap(id => rounds.find(_.id == id))
+ def featurableRound = round
+ .ifTrue(targetRound.isEmpty)
+ .filter: r =>
+ r.sync.upstream.forall(up => up.isUrl && !up.hasLcc)
final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
import helpers.{ *, given }
@@ -25,8 +31,10 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
private def navigationMenu(nav: FormNavigation)(using Context) =
def tourAndRounds(shortName: Option[RelayTour.Name]) = frag(
a(
- href := routes.RelayTour.edit(nav.tour.id),
+ href := routes.RelayTour.edit(nav.tour.id),
+ dataIcon := Icon.RadioTower,
cls := List(
+ "text" -> true,
"relay-form__subnav__tour-parent" -> shortName.isDefined,
"active" -> (nav.round.isEmpty && !nav.newRound)
)
@@ -37,7 +45,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
nav.rounds.map: r =>
a(
href := routes.RelayRound.edit(r.id),
- cls := List("subnav__subitem text" -> true, "active" -> nav.round.has(r.id)),
+ cls := List("subnav__subitem text" -> true, "active" -> nav.roundId.has(r.id)),
dataIcon := (
if r.finished then Icon.Checkmark
else if r.hasStarted then Icon.DiscBig
@@ -45,8 +53,12 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
)
)(r.name),
a(
- href := routes.RelayRound.create(nav.tour.id),
- cls := List("subnav__subitem text" -> true, "active" -> nav.newRound),
+ href := routes.RelayRound.create(nav.tour.id),
+ cls := List(
+ "subnav__subitem text" -> true,
+ "active" -> nav.newRound,
+ "button" -> (nav.rounds.isEmpty && !nav.newRound)
+ ),
dataIcon := Icon.PlusButton
)(trb.addRound())
)
@@ -99,16 +111,27 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
)
),
standardFlash,
- inner(form, routes.RelayRound.create(nav.tour.id), nav.tour, create = true)
+ inner(form, routes.RelayRound.create(nav.tour.id), nav)
)
- def edit(r: RelayRound, form: Form[RelayRoundForm.Data], nav: FormNavigation)(using Context) =
+ def edit(
+ r: RelayRound,
+ form: Form[RelayRoundForm.Data],
+ nav: FormNavigation
+ )(using Context) =
page(r.name.value, nav):
val rt = r.withTour(nav.tour)
frag(
boxTop(h1(a(href := rt.path)(rt.fullName))),
standardFlash,
- inner(form, routes.RelayRound.update(r.id), nav.tour, create = false),
+ nav.targetRound.map: tr =>
+ flashMessage("success")(
+ "Your tournament round is officially broadcasted by Lichess!",
+ br,
+ strong(a(href := tr.path, cls := "text", dataIcon := Icon.RadioTower)(tr.fullName)),
+ "."
+ ),
+ inner(form, routes.RelayRound.update(r.id), nav),
div(cls := "relay-form__actions")(
postForm(action := routes.RelayRound.reset(r.id))(
submitButton(
@@ -126,14 +149,38 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
)
)
- private def inner(form: Form[RelayRoundForm.Data], url: play.api.mvc.Call, t: RelayTour, create: Boolean)(
- using ctx: Context
- ) =
+ private def inner(
+ form: Form[RelayRoundForm.Data],
+ url: play.api.mvc.Call,
+ nav: FormNavigation
+ )(using ctx: Context) =
+ val lccWarning = nav.round
+ .flatMap(_.sync.upstream)
+ .exists(_.hasLcc)
+ .option:
+ flashMessage("box relay-form__lcc-deprecated")(
+ p(strong("Please use the ", a(href := broadcasterUrl)("Lichess Broadcaster App"))),
+ p(
+ "LiveChessCloud support is deprecated and will be removed soon.",
+ br,
+ "If you need help, please contact us at broadcast@lichess.org."
+ )
+ )
+ val contactUsForOfficial = nav.featurableRound.isDefined
+ .option:
+ flashMessage("box relay-form__contact-us")(
+ p(
+ "Is this a tournament you organize? Do you want Lichess to feature it on the ",
+ a(href := routes.RelayTour.index(1))("broadcast page"),
+ "?"
+ ),
+ p(trans.contact.sendEmailAt("broadcast@lichess.org"))
+ )
postForm(cls := "form3", action := url)(
(!Granter.opt(_.StudyAdmin)).option:
div(cls := "form-group")(
div(cls := "form-group")(ui.howToUse),
- (create && t.createdAt.isBefore(nowInstant.minusMinutes(1))).option:
+ (nav.round.isEmpty && nav.tour.createdAt.isBefore(nowInstant.minusMinutes(1))).option:
p(dataIcon := Icon.InfoCircle, cls := "text"):
trb.theNewRoundHelp()
)
@@ -141,71 +188,69 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
form3.globalError(form),
form3.split(
form3.group(form("name"), trb.roundName(), half = true)(form3.input(_)(autofocus)),
- Granter
- .opt(_.StudyAdmin)
- .option(
- form3.group(
- form("caption"),
- "Homepage spotlight custom round name",
- help = raw("Leave empty to use the round name").some,
- half = true
- ):
- form3.input(_)
- )
+ form3.group(
+ form("startsAt"),
+ trb.startDate(),
+ help = trb.startDateHelp().some,
+ half = true
+ )(form3.flatpickr(_, minDate = None))
),
- form3.fieldset("Source")(cls := "box-pad")(
+ form3.fieldset("Source", toggle = true.some)(cls := "box-pad")(
form3.group(
form("syncSource"),
"Where do the games come from?"
)(form3.select(_, RelayRoundForm.sourceTypes)),
- form3.group(
- form("syncUrl"),
- trb.sourceSingleUrl(),
- help = trb.sourceUrlHelp().some
- )(form3.input(_))(cls := "relay-form__sync relay-form__sync-url"),
- div(cls := "relay-form__sync relay-form__sync-lcc none")(
- (!Granter.opt(_.Relay)).option(
- flashMessage("box")(
- p(strong("Please use the ", a(href := broadcasterUrl)("Lichess Broadcaster App"))),
- p(
- "LiveChessCloud support is deprecated and will be removed soon.",
- br,
- "If you need help, please contact us at broadcast@lichess.org."
- )
+ div(cls := "relay-form__sync relay-form__sync-url")(
+ lccWarning.orElse(contactUsForOfficial),
+ form3.group(
+ form("syncUrl"),
+ trb.sourceSingleUrl(),
+ help = trb.sourceUrlHelp().some
+ )(form3.input(_)),
+ nav.sourceRound.map: source =>
+ flashMessage("round-push")(
+ "Getting real-time updates from ",
+ strong(a(href := source.path)(source.fullName)),
+ br,
+ "Owner: ",
+ userIdLink(source.tour.ownerId.some),
+ br,
+ "Delay: ",
+ source.round.sync.delay.fold("0")(_.toString),
+ "s",
+ br,
+ "Start: ",
+ source.round.startedAt.orElse(source.round.startsAt).fold(frag("unscheduled"))(momentFromNow),
+ br,
+ "Last sync: ",
+ source.round.sync.log.events.lastOption.map: event =>
+ frag(
+ momentFromNow(event.at),
+ br,
+ event.error match
+ case Some(err) => s"❌ $err"
+ case _ => s"✅ ${event.moves} moves"
+ )
)
- ),
- form3.split(
- form3.group(
- form("syncLcc.id"),
- "Tournament ID",
- help = frag(
- "From the LCC page URL. The ID looks like this: ",
- pre("f1943ec6-4992-45d9-969d-a0aff688b404")
- ).some,
- half = true
- )(form3.input(_)),
- form3.group(
- form("syncLcc.round"),
- trb.roundNumber(),
- half = true
- )(form3.input(_, typ = "number"))
- )
),
form3.group(
form("syncUrls"),
"Multiple source URLs, one per line.",
help = frag("The games will be combined in the order of the URLs.").some,
half = false
- )(form3.textarea(_)(rows := 5))(cls := "relay-form__sync relay-form__sync-urls none"),
+ )(field =>
+ frag(lccWarning, form3.textarea(field)(rows := 5, spellcheck := "false", cls := "monospace"))
+ )(cls := "relay-form__sync relay-form__sync-urls none"),
form3.group(
form("syncIds"),
trb.sourceGameIds(),
half = false
)(form3.input(_))(cls := "relay-form__sync relay-form__sync-ids none"),
div(cls := "form-group relay-form__sync relay-form__sync-push none")(
+ contactUsForOfficial,
p(
- "Send your local games to Lichess using ",
- a(href := "https://github.com/lichess-org/broadcaster")(lila.relay.broadcasterUrl),
+ "Send your local games to Lichess using the ",
+ a(href := broadcasterUrl)("Lichess Broadcaster App"),
"."
)
),
@@ -248,44 +293,50 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
)(form3.input(_))
)
),
- form3.split(
- form3.group(
- form("startsAt"),
- trb.startDate(),
- help = trb.startDateHelp().some,
- half = true
- )(form3.flatpickr(_, minDate = None)),
- form3.checkbox(
- form("finished"),
- trb.completed(),
- help = trb.completedHelp().some,
- half = true
+ form3.fieldset("Advanced", toggle = nav.round.exists(r => r.sync.delay.isDefined).some)(
+ form3.split(
+ form3.group(
+ form("delay"),
+ raw("Delay in seconds"),
+ help = frag(
+ "Optional, how long to delay moves coming from the source.",
+ br,
+ "Add this delay to the start date of the event. E.g. if a tournament starts at 20:00 with a delay of 15 minutes, set the start date to 20:15."
+ ).some,
+ half = true
+ )(form3.input(_, typ = "number")),
+ form3.checkbox(
+ form("finished"),
+ trb.completed(),
+ help = trb.completedHelp().some,
+ half = true
+ )
)
),
- form3.split(
- form3.group(
- form("delay"),
- raw("Delay in seconds"),
- help = frag(
- "Optional, how long to delay moves coming from the source.",
- br,
- "Add this delay to the start date of the event. E.g. if a tournament starts at 20:00 with a delay of 15 minutes, set the start date to 20:15."
- ).some,
- half = true
- )(form3.input(_, typ = "number")),
- Granter
- .opt(_.StudyAdmin)
- .option(
- form3.group(
- form("period"),
- trb.periodInSeconds(),
- help = trb.periodInSecondsHelp().some,
- half = true
- )(form3.input(_, typ = "number"))
+ Granter
+ .opt(_.StudyAdmin)
+ .option(
+ form3.fieldset("Broadcast admin", toggle = false.some)(
+ form3.split(
+ form3.group(
+ form("caption"),
+ "Homepage spotlight custom round name",
+ help = raw("Leave empty to use the round name").some,
+ half = true
+ ):
+ form3.input(_)
+ ,
+ form3.group(
+ form("period"),
+ trb.periodInSeconds(),
+ help = trb.periodInSecondsHelp().some,
+ half = true
+ )(form3.input(_, typ = "number"))
+ )
)
- ),
+ ),
form3.actions(
- a(href := routes.RelayTour.show(t.slug, t.id))(trans.site.cancel()),
+ a(href := routes.RelayTour.show(nav.tour.slug, nav.tour.id))(trans.site.cancel()),
form3.submit(trans.site.apply())
)
)
@@ -319,6 +370,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
page(nav.tour.name.value, menu = Right(nav)):
frag(
boxTop(h1(a(href := routes.RelayTour.show(nav.tour.slug, nav.tour.id))(nav.tour.name))),
+ standardFlash,
image(nav.tour),
postForm(cls := "form3", action := routes.RelayTour.update(nav.tour.id))(
inner(form, nav.tourWithGroup.some),
@@ -352,173 +404,208 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
frag(
(!Granter.opt(_.StudyAdmin)).option(div(cls := "form-group")(ui.howToUse)),
form3.globalError(form),
- form3.split(
- form3.group(form("name"), trb.tournamentName(), half = true)(form3.input(_)(autofocus)),
- Granter
- .opt(_.StudyAdmin)
- .option(
- form3.group(
- form("spotlight.title"),
- "Homepage spotlight custom tournament name",
- help = raw("Leave empty to use the tournament name").some,
- half = true
- )(form3.input(_))
- )
+ form3.group(form("name"), trb.tournamentName())(form3.input(_)(autofocus)),
+ form3.fieldset("Optional details", toggle = tg.exists(_.tour.info.nonEmpty).some)(
+ form3.split(
+ form3.group(
+ form("info.format"),
+ "Tournament format",
+ help = frag("""e.g. "8-player round-robin" or "5-round Swiss"""").some,
+ half = true
+ )(form3.input(_)),
+ form3.group(
+ form("info.tc"),
+ "Time control",
+ help = frag(""""Classical" or "Rapid" or "Rapid & Blitz"""").some,
+ half = true
+ )(form3.input(_))
+ ),
+ form3.group(
+ form("info.players"),
+ "Top players",
+ help = frag("Mention up to 4 of the best players participating").some
+ )(form3.input(_)),
+ form3.group(
+ form("markdown"),
+ trb.fullDescription(),
+ help = trb
+ .fullDescriptionHelp(
+ a(
+ href := "https://guides.github.com/features/mastering-markdown/",
+ targetBlank
+ )("Markdown"),
+ 20000.localize
+ )
+ .some
+ )(form3.textarea(_)(rows := 10))
),
- form3.group(form("description"), trb.tournamentDescription())(form3.textarea(_)(rows := 2)),
- form3.group(
- form("markdown"),
- trb.fullDescription(),
- help = trb
- .fullDescriptionHelp(
- a(
- href := "https://guides.github.com/features/mastering-markdown/",
- targetBlank
- )("Markdown"),
- 20000.localize
+ form3
+ .fieldset("Features", toggle = tg.map(_.tour).exists(t => t.autoLeaderboard || t.teamTable).some)(
+ form3.split(
+ form3.checkbox(
+ form("autoLeaderboard"),
+ trb.automaticLeaderboard(),
+ help = trb.automaticLeaderboardHelp().some
+ ),
+ form3.checkbox(
+ form("teamTable"),
+ "Team tournament",
+ help = frag("Show a team leaderboard. Requires WhiteTeam and BlackTeam PGN tags.").some
+ )
)
- .some
- )(form3.textarea(_)(rows := 10)),
- form3.split(
- form3.checkbox(
- form("autoLeaderboard"),
- trb.automaticLeaderboard(),
- help = trb.automaticLeaderboardHelp().some
),
- form3.checkbox(
- form("teamTable"),
- "Team tournament",
- help = frag("Show a team leaderboard. Requires WhiteTeam and BlackTeam PGN tags.").some
- )
- ),
- form3.split(
- form3.group(
- form("players"),
- trb.replacePlayerTags(),
- help = frag( // do not translate
- "One line per player, formatted as such:",
- pre("player name = FIDE ID"),
- "Example:",
- pre("""Magnus Carlsen = 1503014"""),
- "Player names ignore case and punctuation, and match all possible combinations of 2 words:",
- br,
- """"Jorge Rick Vito" will match "Jorge Rick", "jorge vito", "Rick, Vito", etc.""",
- br,
- "If the player is NM or WNM, you can:",
- pre("""Player Name = FIDE ID / Title"""),
- "Alternatively, you may set tags manually, like so:",
- pre("player name / rating / title / new name"),
- "All values are optional. Example:",
- pre("""Magnus Carlsen / 2863 / GM
+ form3.fieldset(
+ "Players & Teams",
+ toggle = List("players", "teams").exists(k => form(k).value.exists(_.nonEmpty)).some
+ )(
+ form3.split(
+ form3.group(
+ form("players"),
+ trb.replacePlayerTags(),
+ help = frag( // do not translate
+ "One line per player, formatted as such:",
+ pre("player name = FIDE ID"),
+ "Example:",
+ pre("""Magnus Carlsen = 1503014"""),
+ "Player names ignore case and punctuation, and match all possible combinations of 2 words:",
+ br,
+ """"Jorge Rick Vito" will match "Jorge Rick", "jorge vito", "Rick, Vito", etc.""",
+ br,
+ "If the player is NM or WNM, you can:",
+ pre("""Player Name = FIDE ID / Title"""),
+ "Alternatively, you may set tags manually, like so:",
+ pre("player name / rating / title / new name"),
+ "All values are optional. Example:",
+ pre("""Magnus Carlsen / 2863 / GM
YouGotLittUp / 1890 / / Louis Litt""")
- ).some,
- half = true
- )(form3.textarea(_)(rows := 3)),
- form3.group(
- form("teams"),
- "Optional: assign players to teams",
- help = frag( // do not translate
- "One line per player, formatted as such:",
- pre("Team name; Fide Id or Player name"),
- "Example:",
- pre("""Team Cats ; 3408230
+ ).some,
+ half = true
+ )(form3.textarea(_)(rows := 3, spellcheck := "false", cls := "monospace")),
+ form3.group(
+ form("teams"),
+ "Optional: assign players to teams",
+ help = frag( // do not translate
+ "One line per player, formatted as such:",
+ pre("Team name; Fide Id or Player name"),
+ "Example:",
+ pre("""Team Cats ; 3408230
Team Dogs ; Scooby Doo"""),
- "By default the PGN tags WhiteTeam and BlackTeam are used."
- ).some,
- half = true
- )(form3.textarea(_)(rows := 3))
+ "By default the PGN tags WhiteTeam and BlackTeam are used."
+ ).some,
+ half = true
+ )(form3.textarea(_)(rows := 3, spellcheck := "false", cls := "monospace"))
+ )
),
if Granter.opt(_.Relay) then
frag(
- tg.isDefined.option(grouping(form)),
- form3.split(
- form3.group(
- form("tier"),
- raw("Official Lichess broadcast tier"),
- help = raw("Feature on /broadcast - for admins only").some,
- half = true
- )(form3.select(_, RelayTour.Tier.options))
- )
- )
- else form3.hidden(form("tier")),
- Granter
- .opt(_.StudyAdmin)
- .option(
- frag(
+ form3.fieldset("Broadcast admin", toggle = true.some)(
+ tg.isDefined.option(grouping(form)),
form3.split(
- form3.checkbox(
- form("spotlight.enabled"),
- "Show a homepage spotlight",
- help = raw("As a Big Blue Button - for admins only").some,
- half = true
- ),
form3.group(
- form("spotlight.lang"),
- "Homepage spotlight language",
- help =
- raw("Only show to users who speak this language. English is shown to everyone.").some,
+ form("tier"),
+ raw("Official Lichess broadcast tier"),
+ help = raw("Feature on /broadcast - for admins only").some,
half = true
- ):
- form3.select(_, langList.popularLanguagesForm.choices)
+ )(form3.select(_, RelayTour.Tier.options)),
+ Granter
+ .opt(_.StudyAdmin)
+ .option(
+ form3.checkbox(
+ form("spotlight.enabled"),
+ "Show a homepage spotlight",
+ help = raw("As a Big Blue Button - for admins only").some,
+ half = true
+ )
+ )
),
- tg.map: t =>
- details(
- summary("Pinned streamer"),
- div(
- cls := "relay-pinned-streamer-edit",
- data("post-url") := routes.RelayTour.image(t.tour.id, "pinnedStreamerImage".some)
- )(
- div(
+ Granter
+ .opt(_.StudyAdmin)
+ .option(
+ frag(
+ form3.split(
form3.group(
- form("pinnedStreamer"),
- "Pinned streamer",
- help = frag(
- p("The pinned streamer is featured even when they're not watching the broadcast."),
- p("An optional placeholder image will embed their stream when clicked."),
- p(
- "To upload one, you must first submit this form with a pinned streamer. "
- + "Then return to this page and choose an image."
- )
- ).some
+ form("spotlight.title"),
+ "Homepage spotlight custom tournament name",
+ help = raw("Leave empty to use the tournament name").some,
+ half = true
)(form3.input(_)),
- span(
- button(tpe := "button", cls := "button streamer-select-image")("select image"),
- button(
- tpe := "button",
- cls := "button button-empty button-red streamer-delete-image",
+ form3.group(
+ form("spotlight.lang"),
+ "Homepage spotlight language",
+ help = raw(
+ "Only show to users who speak this language. English is shown to everyone."
+ ).some,
+ half = true
+ ):
+ form3.select(_, langList.popularLanguagesForm.choices)
+ ),
+ tg.map: t =>
+ form3.fieldset("Pinned streamer", toggle = form("pinnedStreamer").value.isDefined.some)(
+ div(
+ cls := "relay-pinned-streamer-edit",
data("post-url") := routes.RelayTour.image(t.tour.id, "pinnedStreamerImage".some)
- )("delete image")
+ )(
+ div(
+ form3.group(
+ form("pinnedStreamer"),
+ "Pinned streamer",
+ help = frag(
+ p(
+ "The pinned streamer is featured even when they're not watching the broadcast."
+ ),
+ p("An optional placeholder image will embed their stream when clicked."),
+ p(
+ "To upload one, you must first submit this form with a pinned streamer. "
+ + "Then return to this page and choose an image."
+ )
+ ).some
+ )(form3.input(_)),
+ span(
+ button(tpe := "button", cls := "button streamer-select-image")("select image"),
+ button(
+ tpe := "button",
+ cls := "button button-empty button-red streamer-delete-image",
+ data("post-url") := routes.RelayTour
+ .image(t.tour.id, "pinnedStreamerImage".some)
+ )("delete image")
+ )
+ ),
+ ui.thumbnail(t.tour.pinnedStreamerImage, _.Size.Small16x9)(
+ cls := List(
+ "streamer-drop-target" -> true,
+ "user-image" -> t.tour.pinnedStreamerImage.isDefined
+ ),
+ attr("draggable") := "true"
+ )
+ )
)
- ),
- ui.thumbnail(t.tour.pinnedStreamerImage, _.Size.Small16x9)(
- cls := List(
- "streamer-drop-target" -> true,
- "user-image" -> t.tour.pinnedStreamerImage.isDefined
- ),
- attr("draggable") := "true"
- )
)
)
)
)
+ else form3.hidden(form("tier"))
)
private def image(t: RelayTour)(using ctx: Context) =
- div(cls := "relay-image-edit", data("post-url") := routes.RelayTour.image(t.id))(
- ui.thumbnail(t.image, _.Size.Small)(
- cls := List("drop-target" -> true, "user-image" -> t.image.isDefined),
- attr("draggable") := "true"
- ),
+ form3.fieldset("Image", toggle = true.some):
div(
- p("Upload a beautiful image to represent your tournament."),
- p("The image must be twice as wide as it is tall. Recommended resolution: 1000x500."),
- p(
- "A picture of the city where the tournament takes place is a good idea, but feel free to design something different."
+ cls := "form-group relay-image-edit",
+ data("post-url") := routes.RelayTour.image(t.id)
+ )(
+ ui.thumbnail(t.image, _.Size.Small)(
+ cls := List("drop-target" -> true, "user-image" -> t.image.isDefined),
+ attr("draggable") := "true"
),
- p(trans.streamer.maxSize(s"${lila.memo.PicfitApi.uploadMaxMb}MB.")),
- form3.file.selectImage()
+ div(
+ p("Upload a beautiful image to represent your tournament."),
+ p("The image must be twice as wide as it is tall. Recommended resolution: 1000x500."),
+ p(
+ "A picture of the city where the tournament takes place is a good idea, but feel free to design something different."
+ ),
+ p(trans.streamer.maxSize(s"${lila.memo.PicfitApi.uploadMaxMb}MB.")),
+ form3.file.selectImage()
+ )
)
- )
private def grouping(form: Form[RelayTourForm.Data])(using Context) =
form3.split(cls := "relay-form__grouping")(
@@ -526,7 +613,7 @@ Team Dogs ; Scooby Doo"""),
form("grouping"),
"Optional: assign tournaments to a group",
half = true
- )(form3.textarea(_)(rows := 5)),
+ )(form3.textarea(_)(rows := 5, spellcheck := "false", cls := "monospace")),
div(cls := "form-group form-half form-help")( // do not translate
"First line is the group name. Subsequent lines are the tournament IDs and names in the group. Names are facultative and only used for display in this textarea.",
br,
diff --git a/modules/relay/src/main/ui/RelayTourUi.scala b/modules/relay/src/main/ui/RelayTourUi.scala
index 54defb524d4d6..92182daee011b 100644
--- a/modules/relay/src/main/ui/RelayTourUi.scala
+++ b/modules/relay/src/main/ui/RelayTourUi.scala
@@ -33,6 +33,7 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
pageMenu("index"),
div(cls := "page-menu__content box box-pad")(
boxTop(h1(trc.liveBroadcasts()), searchForm("")),
+ Granter.opt(_.StudyAdmin).option(adminIndex(active)),
nonEmptyTier(_.BEST, "best"),
nonEmptyTier(_.HIGH, "high"),
nonEmptyTier(_.NORMAL, "normal"),
@@ -49,6 +50,16 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
)
)
+ private def adminIndex(active: List[RelayTour.ActiveWithSomeRounds])(using Context) =
+ val errored = active.flatMap(a => a.errors.some.filter(_.nonEmpty).map(a -> _))
+ errored.nonEmpty.option:
+ div(cls := "relay-index__admin")(
+ h2("Ongoing broadcasts with errors"),
+ st.section(cls := "relay-cards"):
+ errored.map: (tr, errors) =>
+ card.render(tr.copy(link = tr.display), live = _.display.hasStarted, errors = errors.take(5))
+ )
+
private def listLayout(title: String, menu: Tag)(body: Modifier*)(using Context) =
Page(trc.liveBroadcasts.txt())
.css("bits.relay.index")
@@ -64,9 +75,20 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
renderPager(asRelayPager(pager), query)(cls := "relay-cards--search")
)
- def byOwner(pager: Paginator[RelayTour | WithLastRound], owner: LightUser)(using Context) =
+ def byOwner(pager: Paginator[RelayTour | WithLastRound], owner: LightUser)(using ctx: Context) =
listLayout(trc.liveBroadcasts.txt(), pageMenu("by", owner.some))(
- boxTop(h1(lightUserLink(owner), " ", trc.liveBroadcasts())),
+ boxTop(
+ h1(
+ if ctx.is(owner)
+ then trc.myBroadcasts()
+ else frag(lightUserLink(owner), " ", trc.liveBroadcasts())
+ ),
+ div(cls := "box__top__actions")(
+ a(href := routes.RelayTour.form, cls := "button button-green text", dataIcon := Icon.PlusButton)(
+ trc.newBroadcast()
+ )
+ )
+ ),
standardFlash,
renderPager(pager, owner = owner.some)
)
@@ -92,7 +114,7 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
boxTop:
ui.broadcastH1(t.name)
,
- h2(t.description),
+ h2(t.info.toString),
markup.map: html =>
frag(
hr,
@@ -102,16 +124,6 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
)
)
- def stats(t: RelayTour, stats: List[RelayStats.RoundStats])(using Context) =
- import JsonView.given
- Page(s"${t.name.value} - Stats")
- .css("bits.relay.index")
- .js(PageModule("bits.relayStats", Json.obj("rounds" -> stats))):
- main(cls := "relay-tour page box box-pad")(
- boxTop(h1(a(href := routes.RelayTour.show(t.slug, t.id).url)(t.name), " - Stats")),
- "Here, a graph shows the number of viewers over time."
- )
-
def page(title: String, pageBody: Frag, active: String)(using Context): Page =
Page(title)
.css("bits.page")
@@ -128,7 +140,10 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
lila.ui.bits.pageMenuSubnav(
a(href := routes.RelayTour.index(), cls := menu.activeO("index"))(trans.broadcast.broadcasts()),
ctx.me.map: me =>
- a(href := routes.RelayTour.by(me.username, 1), cls := by.exists(_.is(me)).option("active")):
+ a(
+ href := routes.RelayTour.by(me.username, 1),
+ cls := (menu == "new" || by.exists(_.is(me))).option("active")
+ ):
trans.broadcast.myBroadcasts()
,
by.filterNot(ctx.is)
@@ -148,12 +163,13 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
"Private Broadcasts"
)
),
- a(href := routes.RelayTour.form, cls := menu.activeO("new"))(trans.broadcast.newBroadcast()),
a(href := routes.RelayTour.calendar, cls := menu.activeO("calendar"))(trans.site.tournamentCalendar()),
a(href := routes.RelayTour.help, cls := menu.activeO("help"))(trans.broadcast.aboutBroadcasts()),
div(cls := "sep"),
- a(cls := menu.active("players"), href := routes.Fide.index(1))("FIDE players"),
- a(cls := menu.active("federations"), href := routes.Fide.federations(1))("FIDE federations")
+ a(cls := menu.active("players"), href := routes.Fide.index(1))(trans.broadcast.fidePlayers()),
+ a(cls := menu.active("federations"), href := routes.Fide.federations(1))(
+ trans.broadcast.fideFederations()
+ )
)
private object card:
@@ -168,7 +184,9 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
private def image(t: RelayTour) = t.image.fold(ui.thumbnail.fallback(cls := "relay-card__image")): id =>
img(cls := "relay-card__image", src := ui.thumbnail.url(id, _.Size.Small))
- def render[A <: RelayRound.AndTourAndGroup](tr: A, live: A => Boolean)(using Context) =
+ def render[A <: RelayRound.AndTourAndGroup](tr: A, live: A => Boolean, errors: List[String] = Nil)(using
+ Context
+ ) =
link(tr.tour, tr.path, live(tr))(
image(tr.tour),
span(cls := "relay-card__body")(
@@ -186,7 +204,9 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
else tr.display.startedAt.orElse(tr.display.startsAt).map(momentFromNow(_))
),
h3(cls := "relay-card__title")(tr.group.fold(tr.tour.name.value)(_.value)),
- span(cls := "relay-card__desc")(tr.tour.description)
+ if errors.nonEmpty
+ then ul(cls := "relay-card__errors")(errors.map(li(_)))
+ else tr.tour.info.players.map(span(cls := "relay-card__desc")(_))
)
)
@@ -195,7 +215,7 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
image(t),
span(cls := "relay-card__body")(
h3(cls := "relay-card__title")(t.name),
- span(cls := "relay-card__desc")(t.description)
+ span(cls := "relay-card__desc")(t.info.toString)
)
)
diff --git a/modules/relay/src/main/ui/RelayUi.scala b/modules/relay/src/main/ui/RelayUi.scala
index 7d551ed7ae657..6c87e56ad4947 100644
--- a/modules/relay/src/main/ui/RelayUi.scala
+++ b/modules/relay/src/main/ui/RelayUi.scala
@@ -50,7 +50,7 @@ final class RelayUi(helpers: Helpers)(
.graph(
title = rt.fullName,
url = s"$netBaseUrl${rt.path}",
- description = shorten(rt.tour.description, 152)
+ description = shorten(rt.tour.info.toString, 152)
):
main(cls := "analyse is-relay has-relay-tour")(
div(cls := "box relay-tour")(
@@ -119,8 +119,6 @@ final class RelayUi(helpers: Helpers)(
import trans.broadcast as trb
List(
trb.addRound,
- trb.broadcastUrl,
- trb.currentRoundUrl,
trb.currentGameUrl,
trb.downloadAllRounds,
trb.editRoundStudy
diff --git a/modules/relay/src/test/GameJsonTest.scala b/modules/relay/src/test/GameJsonTest.scala
index 2175da1c05393..a4da810901c28 100644
--- a/modules/relay/src/test/GameJsonTest.scala
+++ b/modules/relay/src/test/GameJsonTest.scala
@@ -1,5 +1,7 @@
package lila.relay
+import chess.format.pgn.Tags
+
class GameJsonTest extends munit.FunSuite:
test("toPgn"):
@@ -124,4 +126,4 @@ class GameJsonTest extends munit.FunSuite:
"""d4 { [%clk 0:30:52] } e6 { [%clk 0:30:18] } Nf3 { [%clk 0:31:02] } Nc6 { [%clk 0:30:21] } e4 { [%clk 0:30:51] } Bb4+ { [%clk 0:29:01] } Nc3 { [%clk 0:31:11] } Bd6 { [%clk 0:28:56] } Bc4 { [%clk 0:30:31] } Nf6 { [%clk 0:29:02] } e5 { [%clk 0:30:00] } Be7 { [%clk 0:27:42] } exf6 { [%clk 0:29:43] } Bxf6 { [%clk 0:27:57] } O-O { [%clk 0:29:23] } O-O { [%clk 0:28:22] } Qd3 { [%clk 0:28:50] } Nb4 { [%clk 0:28:25] } Qd2 { [%clk 0:28:47] } d6 { [%clk 0:28:16] } a3 { [%clk 0:28:58] } Nc6 Ng5 Bxg5 { [%clk 0:26:57] } Qxg5 { [%clk 0:29:06] } Qd7 { [%clk 0:26:54] } Bd3 { [%clk 0:29:05] } f6 { [%clk 0:26:47] } Qh4 { [%clk 0:24:44] } g5 { [%clk 0:25:47] } Qxh7+ { [%clk 0:25:09] } Qxh7 { [%clk 0:24:25] } Bxh7+ { [%clk 0:25:32] } Kxh7 { [%clk 0:23:45] } Nb5 { [%clk 0:25:51] } Rf7 { [%clk 0:23:30] } Rd1 { [%clk 0:25:30] } Rg7 { [%clk 0:23:39] } d5 { [%clk 0:24:41] } Ne5 { [%clk 0:23:46] } Nd4 { [%clk 0:24:29] } Rg6 { [%clk 0:23:50] } Nxe6 { [%clk 0:24:48] } Rh6 f4 { [%clk 0:24:55] } Nf3+ gxf3 { [%clk 0:22:47] } Bxe6 { [%clk 0:21:57] } dxe6 { [%clk 0:23:09] } Re8 { [%clk 0:22:07] } fxg5 { [%clk 0:22:45] } fxg5 { [%clk 0:21:57] } Bxg5 { [%clk 0:23:10] } Rg6 { [%clk 0:22:05] } h4 { [%clk 0:22:43] } Rexe6 { [%clk 0:22:27] } Re1 { [%clk 0:22:30] } Re5 { [%clk 0:20:54] } Rxe5 { [%clk 0:22:31] } dxe5 { [%clk 0:21:06] } Rd1 { [%clk 0:22:49] } Rc6 { [%clk 0:21:02] } c3 { [%clk 0:23:14] } Rb6 { [%clk 0:21:11] } Rd7+ { [%clk 0:23:36] } Kg6 { [%clk 0:21:23] } Bc1 { [%clk 0:23:33] } c5 { [%clk 0:21:29] } Rd5 { [%clk 0:23:58] } Kh5 { [%clk 0:21:27] } Rxe5+ { [%clk 0:24:15] } Kxh4 { [%clk 0:21:40] } Rxc5 { [%clk 0:24:34] } Rg6+ { [%clk 0:22:01] } Kf2 { [%clk 0:24:50] } Rg3 { [%clk 0:22:06] } Rh5+ { [%clk 0:24:52] } Kxh5 { [%clk 0:22:13] } Kxg3 { [%clk 0:25:21] } b5 { [%clk 0:22:28] } Kf4 { [%clk 0:25:49] } a5 { [%clk 0:22:26] } Ke5 { [%clk 0:26:11] } Kh4 { [%clk 0:22:34] } Kd5 { [%clk 0:26:34] } Kg3 { [%clk 0:22:34] } Kc5 { [%clk 0:26:56] } Kxf3 { [%clk 0:22:40] } Kxb5 { [%clk 0:27:18] } Ke2 { [%clk 0:22:54] } c4 { [%clk 0:27:47] } Kd1 a4 Kxc1 { [%clk 0:22:31] } c5 { [%clk 0:28:12] } Kxb2 { [%clk 0:22:29] } c6 Kc3 { [%clk 0:22:28] } c7 { [%clk 0:29:00] } Kd4 { [%clk 0:22:36] } c8=Q Kd5 Qe8 { [%clk 0:28:38] } Kd6 { [%clk 0:22:37] } Qe4 { [%clk 0:28:56] } Kc7 { [%clk 0:22:47] } Qe6 { [%clk 0:29:15] } Kb7 { [%clk 0:22:55] } Qd7+ { [%clk 0:29:29] } Kb8 Kb6 Ka8 { [%clk 0:22:45] } Qc8# { [%clk 0:29:56] }"""
val game = RelayFetch.DgtJson.GameJson(moves, None)
- assertEquals(game.toPgn().value.trim, expected)
+ assertEquals(game.toPgn(Tags.empty).value.trim, expected)
diff --git a/modules/report/src/main/Reason.scala b/modules/report/src/main/Reason.scala
index 53f23696ed8f2..c03bc9cafad8d 100644
--- a/modules/report/src/main/Reason.scala
+++ b/modules/report/src/main/Reason.scala
@@ -3,33 +3,34 @@ package lila.report
import scalalib.Iso
import lila.core.user.Me
-sealed trait Reason:
-
- def key = toString.toLowerCase
-
- def name = toString
-
- def isComm = this == Reason.Comm || this == Reason.Sexism
+enum Reason:
+ case Cheat
+ case Stall
+ case Boost
+ case Comm // BC
+ case Sexism // BC
+ case VerbalAbuse
+ case Violence
+ case Harass
+ case SelfHarm
+ case Hate
+ case Spam
+ case Username
+ case Other
+ // auto reports:
+ case Playbans
+ case AltPrint
+ def key = toString.toLowerCase
+ def name = if this == AltPrint then "Print" else toString
+ def isComm = Reason.comm(this)
object Reason:
-
- case object Cheat extends Reason
- case object CheatPrint extends Reason: // BC, replaced with AltPrint
- override def name = "Print"
- case object AltPrint extends Reason:
- override def name = "Print"
- case object Comm extends Reason:
- def flagText = "[FLAG]"
- case object Boost extends Reason
- case object Username extends Reason
- case object Sexism extends Reason
- case object Other extends Reason
- case object Playbans extends Reason
-
- val all = List(Cheat, AltPrint, Comm, Boost, Username, Sexism, Other, CheatPrint)
+ val all = values.toList
val keys = all.map(_.key)
val byKey = all.mapBy(_.key)
- val autoBlock = Set(Comm, Sexism)
+ val comm = Set(Comm, Sexism, VerbalAbuse, Violence, Harass, SelfHarm, Hate, Spam)
+ val autoBlock = comm
+ val flagText = "[FLAG]"
given Iso.StringIso[Reason] = Iso.string(k => byKey.getOrElse(k, Other), _.key)
@@ -41,14 +42,14 @@ object Reason:
def isComm = reason.isComm
def isCheat = reason == Cheat
def isOther = reason == Other
- def isPrint = reason == AltPrint || reason == CheatPrint
+ def isPrint = reason == AltPrint
def isBoost = reason == Boost
def is(reason: Reason.type => Reason) = this.reason == reason(Reason)
def isGranted(reason: Reason)(using Me) =
import lila.core.perm.Granter
reason match
- case Cheat => Granter(_.MarkEngine)
- case Comm | Sexism => Granter(_.Shadowban)
- case Boost => Granter(_.MarkBooster)
- case AltPrint | CheatPrint | Playbans | Username | Other => Granter(_.Admin)
+ case Cheat => Granter(_.MarkEngine)
+ case r if r.isComm => Granter(_.Shadowban)
+ case Boost => Granter(_.MarkBooster)
+ case _ => Granter(_.Admin)
diff --git a/modules/report/src/main/Report.scala b/modules/report/src/main/Report.scala
index 3f7fc35e646f6..4abc4537bea87 100644
--- a/modules/report/src/main/Report.scala
+++ b/modules/report/src/main/Report.scala
@@ -108,7 +108,7 @@ object Report:
def byLichess = by.is(ReporterId.lichess)
- def isFlag = text.startsWith(Reason.Comm.flagText)
+ def isFlag = text.startsWith(Reason.flagText)
case class Done(by: ModId, at: Instant)
diff --git a/modules/report/src/main/ReportApi.scala b/modules/report/src/main/ReportApi.scala
index 568a39e68b596..693d2946525e5 100644
--- a/modules/report/src/main/ReportApi.scala
+++ b/modules/report/src/main/ReportApi.scala
@@ -52,38 +52,33 @@ final class ReportApi(
val ignoreReport = c.reporter.user.marks.reportban && !c.reason.isComm
(!ignoreReport && !isAlreadySlain(c)).so {
scorer(c).map(_.withScore(score)).flatMap { case scored @ Candidate.Scored(candidate, _) =>
- coll
- .one[Report](
+ for
+ prev <- coll.one[Report]:
$doc(
"user" -> candidate.suspect.user.id,
"reason" -> candidate.reason,
"open" -> true
)
- )
- .flatMap { prev =>
- val report = Report.make(scored, prev)
- lila.mon.mod.report.create(report.reason.key, scored.score.value.toInt).increment()
- if report.isRecentComm &&
- report.score.value >= thresholds.discord() &&
- prev.exists(_.score.value < thresholds.discord())
- then ircApi.commReportBurst(c.suspect.user.light)
- coll.update.one($id(report.id), report, upsert = true).void >>
- autoAnalysis(candidate).andDo:
- if report.isCheat then
- Bus.publish(lila.core.report.CheatReportCreated(report.user), "cheatReport")
- }
- .andDo(maxScoreCache.invalidateUnit())
+ report = Report.make(scored, prev)
+ _ = lila.mon.mod.report.create(report.reason.key, scored.score.value.toInt).increment()
+ _ = if report.isRecentComm &&
+ report.score.value >= thresholds.discord() &&
+ prev.exists(_.score.value < thresholds.discord())
+ then ircApi.commReportBurst(c.suspect.user.light)
+ _ <- coll.update.one($id(report.id), report, upsert = true)
+ _ <- autoAnalysis(candidate)
+ yield
+ if report.isCheat then Bus.publish(lila.core.report.CheatReportCreated(report.user), "cheatReport")
+ maxScoreCache.invalidateUnit()
}
}
- def commFlag(reporter: Reporter, suspect: Suspect, resource: String, text: String) =
- create(
- Candidate(
- reporter,
- suspect,
- Reason.Comm,
- s"${Reason.Comm.flagText} $resource ${text.take(140)}"
- )
+ def commFlag(reporter: Reporter, suspect: Suspect, resource: String, text: String) = create:
+ Candidate(
+ reporter,
+ suspect,
+ Reason.Comm,
+ s"${Reason.flagText} $resource ${text.take(140)}"
)
def autoCommFlag(suspectId: SuspectId, resource: String, text: String, critical: Boolean = false) =
@@ -94,7 +89,7 @@ final class ReportApi(
reporter,
suspect,
Reason.Comm,
- s"${Reason.Comm.flagText} $resource ${text.take(140)}"
+ s"${Reason.flagText} $resource ${text.take(140)}"
),
score = (_: Report.Score).map(_ * (if critical then 2 else 1))
)
diff --git a/modules/report/src/main/ReportForm.scala b/modules/report/src/main/ReportForm.scala
index d511dcd7c3c49..11717e68b1d54 100644
--- a/modules/report/src/main/ReportForm.scala
+++ b/modules/report/src/main/ReportForm.scala
@@ -7,6 +7,7 @@ import play.api.data.validation.*
import lila.core.config.NetDomain
import lila.core.LightUser
import lila.core.report.SuspectId
+import lila.common.Form.cleanNonEmptyText
final private[report] class ReportForm(
lightUserAsync: LightUser.Getter,
@@ -30,7 +31,7 @@ final private[report] class ReportForm(
u => !UserId.isOfficial(u)
),
"reason" -> text.verifying("error.required", Reason.keys contains _),
- "text" -> text(minLength = 5, maxLength = 2000)
+ "text" -> cleanNonEmptyText(minLength = 5)
) { (username, reason, text) =>
ReportSetup(
user = blockingFetchUser(username).err("Unknown username " + username),
@@ -39,12 +40,13 @@ final private[report] class ReportForm(
)
}(_.values.some)
.verifying(cheatLinkConstraint)
+ .verifying(s"Maximum report length is 3000 characters", _.text.length <= 3000)
val flag = Form:
mapping(
"username" -> lila.common.Form.username.historicalField,
"resource" -> nonEmptyText,
- "text" -> text(minLength = 3, maxLength = 140)
+ "text" -> text(minLength = 1, maxLength = 140)
)(ReportFlag.apply)(unapply)
private def blockingFetchUser(username: UserStr) =
diff --git a/modules/report/src/main/ReportScore.scala b/modules/report/src/main/ReportScore.scala
index a318d10236bb3..807b270ce6e4f 100644
--- a/modules/report/src/main/ReportScore.scala
+++ b/modules/report/src/main/ReportScore.scala
@@ -39,7 +39,8 @@ final private class ReportScore(
else if c.isIrwinCheat then 45d
else if c.isKaladinCheat then 25d
else if c.isPrint || c.isCoachReview || c.is(_.Playbans) then baseScore * 2
- else if c.is(_.Username) || c.is(_.Sexism) then score + 30
+ else if c.is(_.Violence) || c.is(_.Harass) || c.is(_.SelfHarm) || c.is(_.Hate) then 50d
+ else if c.is(_.Username) then 50d
else score
private val gameRegex = ReportForm.gameLinkRegex(domain)
diff --git a/modules/report/src/main/Room.scala b/modules/report/src/main/Room.scala
index 381e18cff88ab..ff6f0b97fd925 100644
--- a/modules/report/src/main/Room.scala
+++ b/modules/report/src/main/Room.scala
@@ -24,11 +24,11 @@ object Room:
def apply(reason: Reason): Room =
import lila.report.{ Reason as R }
reason match
- case R.Cheat => Cheat
- case R.Boost => Boost
- case R.AltPrint | R.CheatPrint => Print
- case R.Comm | R.Sexism => Comm
- case R.Other | R.Playbans | R.Username => Other
+ case R.Cheat => Cheat
+ case R.Boost => Boost
+ case R.AltPrint => Print
+ case r if r.isComm => Comm
+ case _ => Other
case class Scores(value: Map[Room, Int]):
def get = value.get
diff --git a/modules/report/src/main/ui/ReportUi.scala b/modules/report/src/main/ui/ReportUi.scala
index cdda91268f2c5..c18d0e6b3c7ae 100644
--- a/modules/report/src/main/ui/ReportUi.scala
+++ b/modules/report/src/main/ui/ReportUi.scala
@@ -4,25 +4,118 @@ package ui
import lila.ui.*
import ScalatagsTemplate.{ *, given }
import lila.core.i18n.{ Translate, I18nKey as trans }
+import play.api.data.Form
object ReportUi:
- def translatedReasonChoices(using Translate) =
- List(
- (Reason.Cheat.key, trans.site.cheat.txt()),
- (Reason.Comm.key, trans.site.insult.txt()),
- (Reason.Boost.key, trans.site.ratingManipulation.txt()),
- (Reason.Comm.key, trans.site.troll.txt()),
- (Reason.Sexism.key, "Sexual harassment or Sexist remarks"),
- (Reason.Username.key, trans.site.username.txt()),
- (Reason.Other.key, trans.site.other.txt())
- )
-
def reportScore(score: Report.Score): Frag =
span(cls := s"score ${score.color}")(score.value.toInt)
final class ReportUi(helpers: Helpers):
import helpers.{ given, * }
+ import ReportUi.*
+
+ def form(form: Form[?], reqUser: Option[User] = None)(using ctx: Context) =
+ Page(trans.site.reportAUser.txt())
+ .css("bits.form3")
+ .js(
+ embedJsUnsafeLoadThen(
+ """$('#form3-reason').on('change', function() {
+ $('.report-reason').addClass('none').filter('.report-reason-' + this.value).removeClass('none');
+ })"""
+ )
+ ):
+ val defaultReason = form("reason").value.orElse(translatedReasonChoices.headOption.map(_._1.key))
+ main(cls := "page-small box box-pad report")(
+ h1(cls := "box__top")(trans.site.reportAUser()),
+ postForm(
+ cls := "form3",
+ action := s"${routes.Report.create}${reqUser.so(u => "?username=" + u.username)}"
+ )(
+ div(cls := "form-group")(
+ p(
+ a(
+ href := routes.Cms.lonePage(lila.core.id.CmsPageKey("report-faq")),
+ dataIcon := Icon.InfoCircle,
+ cls := "text"
+ ):
+ "Read more about Lichess reports"
+ ),
+ ctx.req.queryString
+ .contains("postUrl")
+ .option(
+ p(
+ "Here for DMCA or Intellectual Property Take Down Notice? ",
+ a(href := "/dmca")("Complete this form instead"),
+ "."
+ )
+ )
+ ),
+ form3.globalError(form),
+ form3.group(form("username"), trans.site.user(), klass = "field_to complete-parent"): f =>
+ reqUser
+ .map: user =>
+ frag(userLink(user), form3.hidden(f, user.id.value.some))
+ .getOrElse:
+ div(form3.input(f, klass = "user-autocomplete")(dataTag := "span", autofocus))
+ ,
+ if ctx.req.queryString contains "reason"
+ then form3.hidden(form("reason"))
+ else
+ form3.group(form("reason"), trans.site.reason()): f =>
+ form3.select(
+ f,
+ translatedReasonChoices.map((r, t) => (r.key, t)),
+ trans.site.whatIsIheMatter.txt().some
+ )
+ ,
+ form3.group(form("text"), trans.site.description(), help = descriptionHelp(~defaultReason).some):
+ form3.textarea(_)(rows := 8)
+ ,
+ form3.actions(
+ a(href := routes.Lobby.home)(trans.site.cancel()),
+ form3.submit(trans.site.send())
+ )
+ )
+ )
+
+ private def descriptionHelp(current: String)(using ctx: Context) = frag:
+ import Reason.*
+ val englishPlease = "Your report will be processed faster if written in English."
+ val maxLength = "Maximum 3000 characters."
+ translatedReasonChoices
+ .map(_._1)
+ .distinct
+ .map: reason =>
+ span(
+ cls := List(s"report-reason report-reason-${reason.key}" -> true, "none" -> (current != reason.key))
+ )(
+ if reason == Cheat || reason == Boost then trans.site.reportDescriptionHelp()
+ else if reason == Username then "Please explain briefly what about this username is offensive."
+ else
+ "Please provide as much information as possible, including relevant game links, posts, and messages."
+ ,
+ " ",
+ englishPlease,
+ " ",
+ maxLength
+ )
+
+ private def translatedReasonChoices(using Translate) =
+ import Reason.*
+ List(
+ (Cheat, trans.site.cheat.txt()),
+ (Stall, "Stalling / Leaving Games"),
+ (Boost, "Sandbagging / Boosting / Match fixing"),
+ (VerbalAbuse, "Verbal abuse / Cursing / Trolling"),
+ (Violence, "Violence / Threats"),
+ (Harass, "Harassment / Bullying / Stalking"),
+ (SelfHarm, "Suicide / Self-Injury"),
+ (Hate, "Hate Speech / Sexism"),
+ (Spam, "Spamming"),
+ (Username, trans.site.username.txt()),
+ (Other, trans.site.other.txt())
+ )
def thanks(userId: UserId, blocked: Boolean)(using ctx: Context) =
val title = "Thanks for the report"
diff --git a/modules/round/src/main/BotFarming.scala b/modules/round/src/main/BotFarming.scala
deleted file mode 100644
index 808a96891325e..0000000000000
--- a/modules/round/src/main/BotFarming.scala
+++ /dev/null
@@ -1,30 +0,0 @@
-package lila.round
-
-import lila.core.LightUser.IsBotSync
-import lila.game.{ CrosstableApi, Game, GameRepo }
-
-final private class BotFarming(
- gameRepo: GameRepo,
- crosstableApi: CrosstableApi,
- isBotSync: IsBotSync
-)(using Executor):
-
- val SAME_PLIES = 20
- val PREV_GAMES = 2
-
- /* true if
- * - at least one bot
- * - rated
- * - recent game in same matchup has same first SAME_PLIES and same winner
- */
- def apply(g: Game): Fu[Boolean] =
- g.twoUserIds match
- case Some((u1, u2)) if g.finished && g.rated && g.userIds.exists(isBotSync) =>
- crosstableApi(u1, u2).flatMap { ct =>
- gameRepo.gamesFromSecondary(ct.results.reverse.take(PREV_GAMES).map(_.gameId)).map {
- _.exists: prev =>
- g.winnerUserId === prev.winnerUserId &&
- g.sans.take(SAME_PLIES) === prev.sans.take(SAME_PLIES)
- }
- }
- case _ => fuccess(false)
diff --git a/modules/round/src/main/Env.scala b/modules/round/src/main/Env.scala
index d6dd2323425b3..9cc6e0f3697d5 100644
--- a/modules/round/src/main/Env.scala
+++ b/modules/round/src/main/Env.scala
@@ -166,7 +166,7 @@ final class Env(
lazy val recentTvGames = wire[RecentTvGames]
- private lazy val botFarming = wire[BotFarming]
+ private lazy val farmBoostDetection = wire[FarmBoostDetection]
lazy val perfsUpdater: PerfsUpdater = wire[PerfsUpdater]
diff --git a/modules/round/src/main/FarmBoostDetection.scala b/modules/round/src/main/FarmBoostDetection.scala
new file mode 100644
index 0000000000000..06e1f0e03c2ee
--- /dev/null
+++ b/modules/round/src/main/FarmBoostDetection.scala
@@ -0,0 +1,42 @@
+package lila.round
+
+import lila.core.LightUser.IsBotSync
+import lila.game.{ CrosstableApi, Game, GameRepo }
+import chess.ByColor
+import lila.core.perf.UserWithPerfs
+
+final private class FarmBoostDetection(
+ gameRepo: GameRepo,
+ crosstableApi: CrosstableApi,
+ isBotSync: IsBotSync
+)(using Executor):
+
+ val SAME_PLIES = 20
+ val PREV_GAMES = 2
+
+ /* true if
+ * - at least one bot
+ * - rated
+ * - recent game in same matchup has same first SAME_PLIES and same winner
+ */
+ def botFarming(g: Game): Fu[Boolean] =
+ g.twoUserIds match
+ case Some((u1, u2)) if g.finished && g.rated && g.userIds.exists(isBotSync) =>
+ crosstableApi(u1, u2).flatMap: ct =>
+ gameRepo
+ .gamesFromSecondary(ct.results.reverse.take(PREV_GAMES).map(_.gameId))
+ .map:
+ _.exists: prev =>
+ g.winnerUserId === prev.winnerUserId &&
+ g.sans.take(SAME_PLIES) === prev.sans.take(SAME_PLIES)
+ .addEffect:
+ if _ then lila.mon.round.farming.bot.increment()
+ case _ => fuccess(false)
+
+ def newAccountBoosting(g: Game, users: ByColor[UserWithPerfs]): Boolean =
+ val found = g.sourceIs(_.Friend) &&
+ g.playedTurns < 20 &&
+ g.durationSeconds.exists(_ < 60) &&
+ users.exists(_.perfs(g.perfKey).provisional.yes)
+ if found then lila.mon.round.farming.provisional.increment()
+ found
diff --git a/modules/round/src/main/PerfsUpdater.scala b/modules/round/src/main/PerfsUpdater.scala
index dc54253b36432..e8eb66b822dcb 100644
--- a/modules/round/src/main/PerfsUpdater.scala
+++ b/modules/round/src/main/PerfsUpdater.scala
@@ -14,7 +14,7 @@ final class PerfsUpdater(
gameRepo: lila.game.GameRepo,
userApi: UserApi,
rankingApi: RankingApi,
- botFarming: BotFarming,
+ farming: FarmBoostDetection,
ratingFactors: () => RatingFactors
)(using Executor):
@@ -22,8 +22,9 @@ final class PerfsUpdater(
// returns rating diffs
def save(game: Game, white: UserWithPerfs, black: UserWithPerfs): Fu[Option[ByColor[IntRatingDiff]]] =
- botFarming(game).flatMap {
+ farming.botFarming(game).flatMap {
if _ then fuccess(none)
+ else if farming.newAccountBoosting(game, ByColor(white, black)) then fuccess(none)
else
val ratingPerf: Option[PerfKey] =
if game.variant.fromPosition
diff --git a/modules/security/src/main/GeoIP.scala b/modules/security/src/main/GeoIP.scala
index ac37985eec7ca..2026c1421c80d 100644
--- a/modules/security/src/main/GeoIP.scala
+++ b/modules/security/src/main/GeoIP.scala
@@ -73,6 +73,7 @@ object Location:
def isSuspicious(loc: Location) =
loc == unknown ||
- loc.region.has("Kirov Oblast")
+ loc.region.has("Kirov Oblast") ||
+ loc.region.has("Samsun")
case class WithProxy(location: Location, proxy: IsProxy)
diff --git a/modules/security/src/main/Signup.scala b/modules/security/src/main/Signup.scala
index cb803b2306233..62ff30f89d6d4 100644
--- a/modules/security/src/main/Signup.scala
+++ b/modules/security/src/main/Signup.scala
@@ -71,25 +71,19 @@ final class Signup(
,
data =>
for
- suspIp <- ipTrust.isSuspicious(ip)
- ipData <- ipTrust.data(ip)
- result <- hcaptcha.verify().flatMap {
+ suspIp <- ipTrust.isSuspicious(ip)
+ ipData <- ipTrust.data(ip)
+ captcha <- hcaptcha.verify()
+ result <- captcha match
case Hcaptcha.Result.Fail => fuccess(Signup.Result.MissingCaptcha)
- case hcaptchaResult =>
+ case _ =>
signupRateLimit(
data.username.id,
suspIp = suspIp,
- captched = hcaptchaResult == Hcaptcha.Result.Valid
+ captched = captcha == Hcaptcha.Result.Valid
):
MustConfirmEmail(data.fingerPrint, data.email, suspIp = suspIp).flatMap { mustConfirm =>
- monitor(
- data,
- hcaptchaResult,
- mustConfirm,
- ipData,
- ipSusp = suspIp,
- api = none
- )
+ monitor(data, captcha, mustConfirm, ipData, ipSusp = suspIp, api = none)
lila.mon.user.register.mustConfirmEmail(mustConfirm.toString).increment()
val passwordHash = authenticator.passEnc(data.clearPassword)
userRepo
@@ -103,11 +97,10 @@ final class Signup(
)
.orFail(s"No user could be created for ${data.username}")
.addEffect:
- logSignup(req, _, data.email, data.fingerPrint, none, mustConfirm)
+ logSignup(req, _, data.email, data.fingerPrint, none, captcha, mustConfirm)
.flatMap:
confirmOrAllSet(data.email, mustConfirm, data.fingerPrint, none)
}
- }
yield result
)
}
@@ -167,7 +160,7 @@ final class Signup(
)
.orFail(s"No user could be created for ${data.username}")
.addEffect:
- logSignup(req, _, data.email, none, apiVersion.some, mustConfirm)
+ logSignup(req, _, data.email, none, apiVersion.some, Hcaptcha.Result.Mobile, mustConfirm)
.flatMap:
confirmOrAllSet(data.email, mustConfirm, none, apiVersion.some)
yield result
@@ -223,13 +216,14 @@ final class Signup(
email: EmailAddress,
fingerPrint: Option[FingerPrint],
apiVersion: Option[ApiVersion],
+ captcha: Hcaptcha.Result,
mustConfirm: MustConfirmEmail
) =
disposableEmailAttempt.onSuccess(user, email, HTTPRequest.ipAddress(req))
authLog(
user.username.into(UserStr),
email.value,
- s"fp: $fingerPrint mustConfirm: $mustConfirm fp: ${fingerPrint
+ s"fp: $fingerPrint mustConfirm: $mustConfirm captcha: $captcha fp: ${fingerPrint
.so(_.value)} ip: ${HTTPRequest.ipAddress(req)} api: $apiVersion"
)
diff --git a/modules/security/src/main/VerifyMail.scala b/modules/security/src/main/VerifyMail.scala
index 238c974b505f5..d40b3e42b458c 100644
--- a/modules/security/src/main/VerifyMail.scala
+++ b/modules/security/src/main/VerifyMail.scala
@@ -53,6 +53,31 @@ final private class VerifyMail(
export cache.invalidate
private def fetch(domain: Domain.Lower): Fu[Boolean] =
+ List(fetchFree(domain), fetchPaid(domain))
+ .map(_.logFailure(logger).recover(_ => true)) // fetch fail = domain ok
+ .parallel
+ .map(_.forall(identity)) // ok if both say the domain is ok
+
+ private def fetchFree(domain: Domain.Lower): Fu[Boolean] =
+ val url = s"https://api.mailcheck.ai/domain/$domain"
+ ws.url(url)
+ .get()
+ .withTimeout(8.seconds, "mailcheck.fetch")
+ .map: res =>
+ (for
+ js <- res.body[JsValue].asOpt[JsObject]
+ if res.status == 200
+ disposable <- js.boolean("disposable")
+ yield
+ val ok = !disposable
+ logger.info:
+ s"Mailcheck $domain = $ok {disposable:$disposable}"
+ ok
+ ).getOrElse:
+ throw lila.core.lilaism.LilaException(s"$url ${res.status} ${res.body[String].take(200)}")
+ .monTry(res => _.security.mailcheckApi.fetch(res.isSuccess, res.getOrElse(true)))
+
+ private def fetchPaid(domain: Domain.Lower): Fu[Boolean] =
val url = s"https://verifymail.io/api/$domain"
ws.url(url)
.withQueryStringParameters("key" -> config.key.value)
diff --git a/modules/setup/src/main/ApiConfig.scala b/modules/setup/src/main/ApiConfig.scala
index 9ae05303a8525..688f4dfac46e7 100644
--- a/modules/setup/src/main/ApiConfig.scala
+++ b/modules/setup/src/main/ApiConfig.scala
@@ -23,6 +23,7 @@ final case class ApiConfig(
):
def perfType: PerfType = lila.rating.PerfType(variant, chess.Speed(days.isEmpty.so(clock)))
+ def perfKey = perfType.key
def validFen = Variant.isValidInitialFen(variant, position)
diff --git a/modules/setup/src/main/Config.scala b/modules/setup/src/main/Config.scala
index 583e2be167797..e53f2dffb40b9 100644
--- a/modules/setup/src/main/Config.scala
+++ b/modules/setup/src/main/Config.scala
@@ -58,6 +58,7 @@ private[setup] trait Config:
def makeSpeed: Speed = chess.Speed(makeClock)
def perfType: PerfType = lila.rating.PerfType(variant, makeSpeed)
+ def perfKey = perfType.key
trait Positional:
self: Config =>
diff --git a/modules/simul/src/main/ui/SimulFormUi.scala b/modules/simul/src/main/ui/SimulFormUi.scala
index 75e1af99cd995..4f9b70330494a 100644
--- a/modules/simul/src/main/ui/SimulFormUi.scala
+++ b/modules/simul/src/main/ui/SimulFormUi.scala
@@ -147,11 +147,13 @@ final class SimulFormUi(helpers: Helpers)(
gatheringFormUi.maxRating(form("conditions.maxRating.rating"))
)
),
- form3.group(
- form("estimatedStartAt"),
- trans.site.estimatedStart(),
- half = true
- )(form3.flatpickr(_)),
+ form3.split(
+ form3.group(
+ form("estimatedStartAt"),
+ trans.site.estimatedStart(),
+ half = true
+ )(form3.flatpickr(_))
+ ),
form3.group(
form("text"),
trans.site.simulDescription(),
diff --git a/modules/study/src/main/BSONHandlers.scala b/modules/study/src/main/BSONHandlers.scala
index edcc7b54f735a..b627f7dbbaaec 100644
--- a/modules/study/src/main/BSONHandlers.scala
+++ b/modules/study/src/main/BSONHandlers.scala
@@ -327,15 +327,21 @@ object BSONHandlers:
private val clockPair: BSONHandler[PairOf[Option[Centis]]] = optionPairHandler
given BSONHandler[Chapter.BothClocks] = clockPair.as[Chapter.BothClocks](ByColor.fromPair, _.toPair)
+ given BSONHandler[Chapter.Check] = quickHandler[Chapter.Check](
+ { case BSONString(v) => if v == "#" then Chapter.Check.Mate else Chapter.Check.Check },
+ v => BSONString(if v == Chapter.Check.Mate then "#" else "+")
+ )
given BSON[Chapter.LastPosDenorm] with
def reads(r: Reader) = Chapter.LastPosDenorm(
fen = r.getO[Fen.Full]("fen") | Fen.initial,
uci = r.getO[Uci]("uci"),
+ check = r.getO[Chapter.Check]("check"),
clocks = ~r.getO[Chapter.BothClocks]("clocks")
)
def writes(w: Writer, l: Chapter.LastPosDenorm) = $doc(
"fen" -> l.fen.some.filterNot(Fen.Full.isInitial),
"uci" -> l.uci,
+ "check" -> l.check,
"clocks" -> l.clocks.some.filter(_.exists(_.isDefined))
)
diff --git a/modules/study/src/main/Chapter.scala b/modules/study/src/main/Chapter.scala
index 6f0a89152dffb..a872576631424 100644
--- a/modules/study/src/main/Chapter.scala
+++ b/modules/study/src/main/Chapter.scala
@@ -41,7 +41,13 @@ case class Chapter(
val parentNode = parentPath.flatMap(root.nodeAt)
val clockSwap = ByColor(node.clock, parentNode.flatMap(_.clock).orElse(node.clock))
if node.color.black then clockSwap else clockSwap.swap
- Chapter.LastPosDenorm(node.fen, node.moveOption.map(_.uci), clocks = clocks)
+ val uci = node.moveOption.map(_.uci)
+ val check = node.moveOption
+ .flatMap(_.san.value.lastOption)
+ .collect:
+ case '+' => Chapter.Check.Check
+ case '#' => Chapter.Check.Mate
+ Chapter.LastPosDenorm(node.fen, uci, check, clocks)
copy(denorm = newDenorm)
def updateRoot(f: Root => Option[Root]) =
@@ -104,6 +110,7 @@ case class Chapter(
fen = denorm.fold(Fen.initial)(_.fen),
lastMove = denorm.flatMap(_.uci),
lastMoveAt = relay.map(_.lastMoveAt),
+ check = denorm.flatMap(_.check),
result = tags.outcome.isDefined.option(tags.outcome)
)
@@ -149,9 +156,12 @@ object Chapter:
type BothClocks = ByColor[Option[Centis]]
+ enum Check:
+ case Check, Mate
+
/* Last position of the main line.
* Used for chapter previews. */
- case class LastPosDenorm(fen: Fen.Full, uci: Option[Uci], clocks: BothClocks)
+ case class LastPosDenorm(fen: Fen.Full, uci: Option[Uci], check: Option[Check], clocks: BothClocks)
case class IdName(@Key("_id") id: StudyChapterId, name: StudyChapterName)
diff --git a/modules/study/src/main/PgnDump.scala b/modules/study/src/main/PgnDump.scala
index 7cecad8234f5b..f06b214152928 100644
--- a/modules/study/src/main/PgnDump.scala
+++ b/modules/study/src/main/PgnDump.scala
@@ -71,7 +71,7 @@ final class PgnDump(
val opening = chapter.opening
val genTags = List(
Tag(_.Event, s"${study.name}: ${chapter.name}"),
- Tag(_.Site, chapterUrl(study.id, chapter.id)),
+ Tag(_.Site, flags.site | chapterUrl(study.id, chapter.id)),
Tag(_.Variant, chapter.setup.variant.name.capitalize),
Tag(_.ECO, opening.fold("?")(_.eco)),
Tag(_.Opening, opening.fold("?")(_.name)),
@@ -109,9 +109,10 @@ object PgnDump:
variations: Boolean,
clocks: Boolean,
source: Boolean,
- orientation: Boolean
+ orientation: Boolean,
+ site: Option[String]
)
- val fullFlags = WithFlags(true, true, true, true, true)
+ val fullFlags = WithFlags(true, true, true, true, true, none)
def rootToPgn(root: Root, tags: Tags, comments: InitialComments)(using WithFlags): Pgn =
rootToPgn(NewRoot(root), tags, comments)
diff --git a/modules/study/src/main/Study.scala b/modules/study/src/main/Study.scala
index 086d61735f53e..b2b779bca13db 100644
--- a/modules/study/src/main/Study.scala
+++ b/modules/study/src/main/Study.scala
@@ -58,7 +58,7 @@ case class Study(
def isOld = (nowSeconds - updatedAt.toSeconds) > 20 * 60
def isRelay = from match
- case From.Relay(_) => true
+ case _: From.Relay => true
case _ => false
def cloneFor(user: User): Study =
diff --git a/modules/study/src/main/StudyApi.scala b/modules/study/src/main/StudyApi.scala
index 2981e1385d6aa..9192f3041284a 100644
--- a/modules/study/src/main/StudyApi.scala
+++ b/modules/study/src/main/StudyApi.scala
@@ -632,8 +632,7 @@ final class StudyApi(
def doAddChapter(study: Study, chapter: Chapter, sticky: Boolean, who: Who): Funit = for
_ <- chapterRepo.insert(chapter)
newStudy = study.withChapter(chapter)
- _ <- sticky.so(studyRepo.updateSomeFields(newStudy))
- _ <- studyRepo.updateNow(study)
+ _ <- if sticky then studyRepo.updateSomeFields(newStudy) else studyRepo.updateNow(study)
yield
sendTo(study.id)(_.addChapter(newStudy.position, sticky, who))
indexStudy(study)
diff --git a/modules/study/src/main/StudyChapterPreview.scala b/modules/study/src/main/StudyChapterPreview.scala
index 55948613e399e..3661354a19a5a 100644
--- a/modules/study/src/main/StudyChapterPreview.scala
+++ b/modules/study/src/main/StudyChapterPreview.scala
@@ -17,6 +17,7 @@ case class ChapterPreview(
fen: Fen.Full,
lastMove: Option[Uci],
lastMoveAt: Option[Instant],
+ check: Option[Chapter.Check],
/* None = No Result PGN tag, the chapter may not be a game
* Some(None) = Result PGN tag is "*", the game is ongoing
* Some(Some(Outcome)) = Game is over with a result
@@ -51,9 +52,21 @@ final class ChapterPreviewApi(
def apply(studyId: StudyId): Fu[AsJsons] = cache.get(studyId)
+ def withoutInitialEmpty(studyId: StudyId): Fu[AsJsons] =
+ apply(studyId).map: json =>
+ val singleInitial = json
+ .asOpt[JsArray]
+ .map(_.value)
+ .filter(_.sizeIs == 1)
+ .flatMap(_.headOption)
+ .exists:
+ case single: JsObject => single.str("name").contains("Chapter 1")
+ case _ => false
+ if singleInitial then JsArray.empty else json
+
object dataList:
private[ChapterPreviewApi] val cache =
- cacheApi[StudyId, List[ChapterPreview]](256, "study.chapterPreview.data"):
+ cacheApi[StudyId, List[ChapterPreview]](512, "study.chapterPreview.data"):
_.expireAfterWrite(1 minute).buildAsyncFuture(listAll)
def apply(studyId: StudyId): Fu[List[ChapterPreview]] = cache.get(studyId)
@@ -122,6 +135,10 @@ object ChapterPreview:
.add("clock" -> p.clock)
.add("fed" -> p.fideId.flatMap(federations.get))
+ private given Writes[Chapter.Check] = Writes:
+ case Chapter.Check.Check => JsString("+")
+ case Chapter.Check.Mate => JsString("#")
+
private def writesWithFederations(using Federation.ByFideIds): OWrites[ChapterPreview] = c =>
Json
.obj(
@@ -132,6 +149,7 @@ object ChapterPreview:
.add("players", c.players.map(_.mapList(playerWithFederations)))
.add("orientation", c.orientation.some.filter(_.black))
.add("lastMove", c.lastMove)
+ .add("check", c.check)
.add("thinkTime", c.thinkTime)
.add("status", c.result.map(o => Outcome.showResult(o).replace("1/2", "½")))
@@ -163,5 +181,6 @@ object ChapterPreview:
fen = lastPos.map(_.fen).orElse(doc.getAsOpt[Fen.Full]("rootFen")).getOrElse(Fen.initial),
lastMove = lastPos.flatMap(_.uci),
lastMoveAt = lastMoveAt,
+ check = lastPos.flatMap(_.check),
result = tags.flatMap(_(_.Result)).map(Outcome.fromResult)
)
diff --git a/modules/study/src/main/package.scala b/modules/study/src/main/package.scala
index 93ddc484696c5..e874850eaeaed 100644
--- a/modules/study/src/main/package.scala
+++ b/modules/study/src/main/package.scala
@@ -5,5 +5,3 @@ export lila.common.extensions.*
export lila.core.study.data.{ StudyName, StudyChapterName }
private val logger = lila.log("study")
-
-private type ChapterMap = Map[lila.study.StudyChapterId, lila.study.Chapter]
diff --git a/modules/study/src/test/Helpers.scala b/modules/study/src/test/Helpers.scala
index 254236ec01aa0..c3725b687981a 100644
--- a/modules/study/src/test/Helpers.scala
+++ b/modules/study/src/test/Helpers.scala
@@ -12,11 +12,11 @@ object Helpers:
import lila.tree.NewTree.*
def rootToPgn(root: Root): PgnStr = PgnDump
- .rootToPgn(root, Tags.empty)(using PgnDump.WithFlags(true, true, true, true, false))
+ .rootToPgn(root, Tags.empty)(using PgnDump.WithFlags(true, true, true, true, false, none))
.render
def rootToPgn(root: NewRoot): PgnStr = PgnDump
- .rootToPgn(root, Tags.empty)(using PgnDump.WithFlags(true, true, true, true, false))
+ .rootToPgn(root, Tags.empty)(using PgnDump.WithFlags(true, true, true, true, false, none))
.render
extension (root: Root)
diff --git a/modules/swiss/src/main/SwissCondition.scala b/modules/swiss/src/main/SwissCondition.scala
index 5ba69a418bd1e..64a44ca3381b8 100644
--- a/modules/swiss/src/main/SwissCondition.scala
+++ b/modules/swiss/src/main/SwissCondition.scala
@@ -45,6 +45,8 @@ object SwissCondition:
def similar(other: All) = sameRatings(other) && titled == other.titled
+ def isDefault = this == All.empty
+
object All:
val empty = All(none, none, none, none, none, none, PlayYourGames.some)
given Zero[All] = Zero(empty)
diff --git a/modules/swiss/src/main/ui/SwissFormUi.scala b/modules/swiss/src/main/ui/SwissFormUi.scala
index 7268df6924bff..ff6fde274ab11 100644
--- a/modules/swiss/src/main/ui/SwissFormUi.scala
+++ b/modules/swiss/src/main/ui/SwissFormUi.scala
@@ -35,17 +35,11 @@ final class SwissFormUi(helpers: Helpers)(
trans.site.ourEventTips()
)
),
- form3.split(fields.name, fields.nbRounds),
- form3.split(fields.description, fields.rated),
- fields.clock,
- form3.split(fields.roundInterval, fields.startsAt),
- advancedSettings(
- form3.split(fields.variant, fields.position),
- form3.split(fields.chatFor, fields.entryCode),
- condition(form),
- form3.split(fields.playYourGames, fields.allowList),
- form3.split(fields.forbiddenPairings, fields.manualPairings)
- ),
+ fields.tournamentFields,
+ fields.gameFields,
+ fields.featuresFields,
+ fields.conditionFields,
+ fields.pairingsFields,
form3.globalError(form),
form3.actions(
a(href := routes.Team.show(teamId))(trans.site.cancel()),
@@ -60,23 +54,6 @@ final class SwissFormUi(helpers: Helpers)(
private val gatheringFormUi = GatheringFormUi(helpers)
- private def condition(form: Form[SwissForm.SwissData])(using ctx: Context) =
- frag(
- form3.split(
- gatheringFormUi.nbRatedGame(form("conditions.nbRatedGame.nb")),
- gatheringFormUi.accountAge(form("conditions.accountAge"))
- ),
- (ctx.me.exists(_.hasTitle) || Granter.opt(_.ManageTournament)).option {
- form3.split(
- gatheringFormUi.titled(form("conditions.titled"))
- )
- },
- form3.split(
- gatheringFormUi.minRating(form("conditions.minRating.rating")),
- gatheringFormUi.maxRating(form("conditions.maxRating.rating"))
- )
- )
-
def edit(swiss: Swiss, form: Form[SwissForm.SwissData])(using Context) =
Page(swiss.name)
.css("swiss.form")
@@ -86,17 +63,11 @@ final class SwissFormUi(helpers: Helpers)(
div(cls := "swiss__form box box-pad")(
h1(cls := "box__top")("Edit ", swiss.name),
postForm(cls := "form3", action := routes.Swiss.update(swiss.id))(
- form3.split(fields.name, fields.nbRounds),
- form3.split(fields.description, fields.rated),
- fields.clock,
- form3.split(fields.roundInterval, swiss.isCreated.option(fields.startsAt)),
- advancedSettings(
- form3.split(fields.variant, fields.position),
- form3.split(fields.chatFor, fields.entryCode),
- condition(form),
- form3.split(fields.playYourGames, fields.allowList),
- form3.split(fields.forbiddenPairings, fields.manualPairings)
- ),
+ fields.tournamentFields,
+ fields.gameFields,
+ fields.featuresFields,
+ fields.conditionFields,
+ fields.pairingsFields,
form3.globalError(form),
form3.actions(
a(href := routes.Swiss.show(swiss.id))(trans.site.cancel()),
@@ -115,6 +86,18 @@ final class SwissFormUi(helpers: Helpers)(
private def disabledAfterStart = swiss.exists(!_.isCreated)
+ def tournamentFields =
+ form3.fieldset("Tournament", toggle = true.some)(
+ form3.split(name, nbRounds),
+ form3.split(startsAt, description)
+ )
+
+ def gameFields =
+ form3.fieldset("Games", toggle = true.some)(
+ clock,
+ form3.split(variant, position)
+ )
+
def name =
form3.group(form("name"), trans.site.name()) { f =>
div(
@@ -137,17 +120,6 @@ final class SwissFormUi(helpers: Helpers)(
)(
form3.input(_, typ = "number")
)
-
- def rated =
- frag(
- form3.checkbox(
- form("rated"),
- trans.site.rated(),
- help = trans.site.ratedFormHelp().some,
- half = true
- ),
- form3.hidden(form("rated"), "false".some) // hack allow disabling rated
- )
def variant =
form3.group(form("variant"), trans.site.variant(), half = true)(
form3.select(
@@ -165,10 +137,6 @@ final class SwissFormUi(helpers: Helpers)(
form3.select(_, GatheringClock.incrementChoices, disabled = disabledAfterStart)
)
)
- def roundInterval =
- form3.group(form("roundInterval"), trans.swiss.roundInterval(), half = true)(
- form3.select(_, SwissForm.roundIntervalChoices)
- )
def description =
form3.group(
form("description"),
@@ -192,28 +160,67 @@ final class SwissFormUi(helpers: Helpers)(
trans.swiss.tournStartDate(),
help = trans.site.inYourLocalTimezone().some,
half = true
- )(form3.flatpickr(_))
+ )(form3.flatpickr(_)(swiss.exists(!_.isCreated).option(disabled)))
- def chatFor =
- form3.group(form("chatFor"), trans.site.tournChat(), half = true) { f =>
- form3.select(
- f,
- Seq(
- Swiss.ChatFor.NONE -> trans.site.noChat.txt(),
- Swiss.ChatFor.LEADERS -> trans.site.onlyTeamLeaders.txt(),
- Swiss.ChatFor.MEMBERS -> trans.site.onlyTeamMembers.txt(),
- Swiss.ChatFor.ALL -> trans.study.everyone.txt()
+ def conditionFields =
+ form3.fieldset("Entry conditions", toggle = swiss.exists(!_.settings.conditions.isDefault).some)(
+ form3.split(
+ gatheringFormUi.nbRatedGame(form("conditions.nbRatedGame.nb")),
+ gatheringFormUi.accountAge(form("conditions.accountAge"))
+ ),
+ form3.split(
+ gatheringFormUi.minRating(form("conditions.minRating.rating")),
+ gatheringFormUi.maxRating(form("conditions.maxRating.rating"))
+ ),
+ form3.split(
+ playYourGames,
+ (summon[Context].me.exists(_.hasTitle) || Granter.opt(_.ManageTournament)).option:
+ gatheringFormUi.titled(form("conditions.titled"))
+ ),
+ form3.split(
+ form3.group(
+ form("password"),
+ trans.site.tournamentEntryCode(),
+ help = trans.site.makePrivateTournament().some,
+ half = true
+ )(form3.input(_)(autocomplete := "off")),
+ allowList
+ )
+ )
+
+ def featuresFields =
+ form3.fieldset("Features", toggle = false.some)(
+ form3.split(
+ form3.group(form("chatFor"), trans.site.tournChat(), half = true) { f =>
+ form3.select(
+ f,
+ Seq(
+ Swiss.ChatFor.NONE -> trans.site.noChat.txt(),
+ Swiss.ChatFor.LEADERS -> trans.site.onlyTeamLeaders.txt(),
+ Swiss.ChatFor.MEMBERS -> trans.site.onlyTeamMembers.txt(),
+ Swiss.ChatFor.ALL -> trans.study.everyone.txt()
+ )
+ )
+ },
+ form3.group(form("roundInterval"), trans.swiss.roundInterval(), half = true)(
+ form3.select(_, SwissForm.roundIntervalChoices)
)
+ ),
+ form3.split(
+ form3.checkbox(
+ form("rated"),
+ trans.site.rated(),
+ help = trans.site.ratedFormHelp().some,
+ half = true
+ ),
+ form3.hidden(form("rated"), "false".some) // hack allow disabling rated
)
- }
+ )
- def entryCode =
- form3.group(
- form("password"),
- trans.site.tournamentEntryCode(),
- help = trans.site.makePrivateTournament().some,
- half = true
- )(form3.input(_)(autocomplete := "off"))
+ def pairingsFields =
+ form3.fieldset("Custom pairings", toggle = false.some)(
+ form3.split(forbiddenPairings, manualPairings)
+ )
def forbiddenPairings =
form3.group(
diff --git a/modules/team/src/main/TeamApi.scala b/modules/team/src/main/TeamApi.scala
index e8a1720cf72bc..68999a31ebfcf 100644
--- a/modules/team/src/main/TeamApi.scala
+++ b/modules/team/src/main/TeamApi.scala
@@ -326,7 +326,7 @@ final class TeamApi(
users <- memberRepo.userIdsByTeam(team.id)
_ = users.foreach(cached.invalidateTeamIds)
_ <- requestRepo.removeByTeam(team.id)
- yield publish(TeamDisable(team.id))
+ yield ()
else
teamRepo
.enable(team)
@@ -353,7 +353,6 @@ final class TeamApi(
(teamRepo.coll.delete.one($id(team.id)) >>
memberRepo.removeByTeam(team.id)).andDo {
logger.info(s"delete team ${team.id} by @${by.id}: $explain")
- publish(TeamDelete(team.id))
}
def syncBelongsTo(teamId: TeamId, userId: UserId): Boolean =
diff --git a/modules/team/src/main/TeamMemberStream.scala b/modules/team/src/main/TeamMemberStream.scala
index 6e465e95a510f..e573656a6427e 100644
--- a/modules/team/src/main/TeamMemberStream.scala
+++ b/modules/team/src/main/TeamMemberStream.scala
@@ -5,18 +5,23 @@ import reactivemongo.akkastream.cursorProducer
import lila.db.dsl.{ *, given }
import lila.core.perf.UserWithPerfs
+import lila.core.LightUser
final class TeamMemberStream(
memberRepo: TeamMemberRepo,
- userApi: lila.core.user.UserApi
+ userApi: lila.core.user.UserApi,
+ lightApi: lila.core.user.LightUserApi
)(using Executor, akka.stream.Materializer):
- def apply(team: Team, perSecond: MaxPerSecond): Source[(UserWithPerfs, Instant), ?] =
- idsBatches(team, perSecond)
+ def apply(team: Team, fullUser: Boolean): Source[(UserWithPerfs | LightUser, Instant), ?] =
+ idsBatches(team, MaxPerSecond(if fullUser then 20 else 50))
+ .limit(if fullUser then 1000 else 5000)
.mapAsync(1): members =>
- userApi
- .listWithPerfs(members.view.map(_._1).toList)
- .map(_.zip(members.map(_._2)))
+ val users =
+ if fullUser
+ then userApi.listWithPerfs(members.view.map(_._1).toList)
+ else lightApi.asyncManyFallback(members.view.map(_._1).toList)
+ users.map(_.zip(members.map(_._2)))
.mapConcat(identity)
def subscribedIds(team: Team, perSecond: MaxPerSecond): Source[UserId, ?] =
diff --git a/modules/team/src/main/ui/RequestUi.scala b/modules/team/src/main/ui/RequestUi.scala
index 1b511ca2c8dd5..28f00b11f4a62 100644
--- a/modules/team/src/main/ui/RequestUi.scala
+++ b/modules/team/src/main/ui/RequestUi.scala
@@ -27,7 +27,7 @@ final class RequestUi(helpers: Helpers, bits: TeamUi):
)
),
t.password.nonEmpty.so(
- form3.passwordModified(form("password"), trt.entryCode())(
+ form3.passwordModified(form("password"), trt.entryCode(), reveal = false)(
autocomplete := "new-password"
)
),
diff --git a/modules/teamSearch/src/main/Env.scala b/modules/teamSearch/src/main/Env.scala
index aded2a9415838..306435a7f4137 100644
--- a/modules/teamSearch/src/main/Env.scala
+++ b/modules/teamSearch/src/main/Env.scala
@@ -1,6 +1,5 @@
package lila.teamSearch
-import akka.actor.*
import com.softwaremill.macwire.*
import scalalib.paginator.Paginator
@@ -8,10 +7,7 @@ import lila.core.config.ConfigName
import lila.search.client.SearchClient
import lila.search.spec.Query
-final class Env(
- client: SearchClient,
- teamApi: lila.core.team.TeamApi
-)(using Executor, akka.stream.Materializer):
+final class Env(client: SearchClient)(using Executor):
private val maxPerPage = MaxPerPage(15)
@@ -20,14 +16,3 @@ final class Env(
lazy val api: TeamSearchApi = wire[TeamSearchApi]
def apply(text: String, page: Int): Fu[Paginator[TeamId]] = paginatorBuilder(Query.team(text), page)
-
- def cli: lila.common.Cli = new:
- def process = { case "team" :: "search" :: "reset" :: Nil =>
- api.reset.inject("done")
- }
-
- lila.common.Bus.subscribeFun("team"):
- case lila.core.team.TeamCreate(team) => api.store(team)
- case lila.core.team.TeamUpdate(team, _) => api.store(team)
- case lila.core.team.TeamDelete(id) => client.deleteById(index, id.value)
- case lila.core.team.TeamDisable(id) => client.deleteById(index, id.value)
diff --git a/modules/teamSearch/src/main/TeamSearchApi.scala b/modules/teamSearch/src/main/TeamSearchApi.scala
index bd7a7c95c14c0..a79ba1d6dc735 100644
--- a/modules/teamSearch/src/main/TeamSearchApi.scala
+++ b/modules/teamSearch/src/main/TeamSearchApi.scala
@@ -1,45 +1,14 @@
package lila.teamSearch
-import akka.stream.scaladsl.*
-
-import lila.core.team.TeamData
import lila.search.*
import lila.search.client.SearchClient
-import lila.search.spec.{ Query, TeamSource }
+import lila.search.spec.Query
-final class TeamSearchApi(
- client: SearchClient,
- teamApi: lila.core.team.TeamApi
-)(using Executor, akka.stream.Materializer)
- extends SearchReadApi[TeamId, Query.Team]:
+final class TeamSearchApi(client: SearchClient)(using Executor) extends SearchReadApi[TeamId, Query.Team]:
def search(query: Query.Team, from: From, size: Size) =
client
.search(query, from, size)
- .map: res =>
- res.hitIds.map(TeamId.apply)
+ .map(_.hitIds.map(TeamId.apply))
def count(query: Query.Team) = client.count(query).dmap(_.count)
-
- def store(team: TeamData) = client.storeTeam(team.id.value, toDoc(team))
-
- private def toDoc(team: TeamData) =
- TeamSource(
- name = team.name,
- description = team.description.value.take(10000),
- nbMembers = team.nbMembers
- )
-
- def reset =
- client.mapping(index) >> {
-
- logger.info(s"Index to ${index}")
-
- teamApi.cursor
- .documentSource()
- .via(lila.common.LilaStream.logRate[TeamData]("team index")(logger))
- .map(t => t.id.value -> toDoc(t))
- .grouped(200)
- .mapAsync(1)(xs => client.storeBulkTeam(xs.toList))
- .runWith(Sink.ignore)
- } >> client.refresh(index)
diff --git a/modules/teamSearch/src/main/package.scala b/modules/teamSearch/src/main/package.scala
index 9e3f5b1de4cfb..ac5f2552b6d3c 100644
--- a/modules/teamSearch/src/main/package.scala
+++ b/modules/teamSearch/src/main/package.scala
@@ -1,7 +1,6 @@
package lila.teamSearch
export lila.core.lilaism.Lilaism.{ *, given }
-export lila.common.extensions.*
private val logger = lila.log("teamSearch")
diff --git a/modules/title/src/main/TitleApi.scala b/modules/title/src/main/TitleApi.scala
index b23c6ed0e39b7..bf6ce36adb4f4 100644
--- a/modules/title/src/main/TitleApi.scala
+++ b/modules/title/src/main/TitleApi.scala
@@ -39,7 +39,10 @@ final class TitleApi(coll: Coll, picfitApi: PicfitApi)(using Executor, BaseUrl):
coll
.byId[TitleRequest](id)
.map:
- _.filter(_.userId.is(me) || Granter(_.SetTitle))
+ _.filter(_.userId.is(me) || Granter(_.TitleRequest))
+
+ def allOf(u: User): Fu[List[TitleRequest]] =
+ coll.list[TitleRequest]($doc("userId" -> u.id))
def findSimilar(req: TitleRequest): Fu[List[TitleRequest]] =
val search = List(
diff --git a/modules/title/src/main/ui/TitleUi.scala b/modules/title/src/main/ui/TitleUi.scala
index 8a87136c5479b..03dbb08483691 100644
--- a/modules/title/src/main/ui/TitleUi.scala
+++ b/modules/title/src/main/ui/TitleUi.scala
@@ -62,14 +62,20 @@ final class TitleUi(helpers: Helpers)(picfitUrl: lila.core.misc.PicfitUrl):
req,
"idDocument",
name = "Identity document",
- help = frag("ID card, passport or driver's license.")
+ help = div(
+ p("ID card, passport or driver's license."),
+ p(trans.streamer.maxSize(s"${lila.memo.PicfitApi.uploadMaxMb}MB."))
+ )
),
imageByTag(
req,
"selfie",
name = "Your picture",
- help = frag(
- """A picture of yourself holding up a piece of paper, with today's date and your Lichess username written on it."""
+ help = div(
+ p("""A picture of yourself holding up a piece of paper, with the required text:"""),
+ pre("""Official Lichess verification
+My Lichess account is [your username]
+Today's date is [current date]""")
)
)
),
@@ -154,9 +160,9 @@ final class TitleUi(helpers: Helpers)(picfitUrl: lila.core.misc.PicfitUrl):
if form("public").value.isDefined || form.hasErrors
then form("public")
else form("public").copy(value = "true".some),
- frag("Publish my title"),
+ frag("Public account"),
help = frag(
- "Recommended. Your title is visible on your profile page. Your real name is NOT published."
+ "Makes your real name public. Required for coaching, streaming, and prize tournaments."
).some,
half = true
),
@@ -187,10 +193,7 @@ final class TitleUi(helpers: Helpers)(picfitUrl: lila.core.misc.PicfitUrl):
cls := List("drop-target" -> true, "user-image" -> image.isDefined),
attr("draggable") := "true"
),
- div(
- help,
- p(trans.streamer.maxSize(s"${lila.memo.PicfitApi.uploadMaxMb}MB."))
- )
+ help
)
object thumbnail:
diff --git a/modules/tournament/src/main/ui/TournamentForm.scala b/modules/tournament/src/main/ui/TournamentForm.scala
index 538f9cae12940..cff2e2fe5f718 100644
--- a/modules/tournament/src/main/ui/TournamentForm.scala
+++ b/modules/tournament/src/main/ui/TournamentForm.scala
@@ -32,7 +32,7 @@ final class TournamentForm(val helpers: Helpers, showUi: TournamentShow)(
given prefix: FormPrefix = FormPrefix.empty
val fields = tourFields(form, none)
Page(trans.site.newTournament.txt())
- .css("tournament.form")
+ .css("tournament.form", "bits.page")
.js(EsmInit("bits.tourForm")):
main(cls := "page-small")(
div(cls := "tour__form box box-pad")(
@@ -55,7 +55,7 @@ final class TournamentForm(val helpers: Helpers, showUi: TournamentShow)(
)
)
),
- div(cls := "box box-pad tour__faq")(showUi.faq.pageContent)
+ div(cls := "box box-pad tour__faq page")(div(cls := "body")(showUi.faq()))
)
def edit(tour: Tournament, form: Form[?], myTeams: List[LightTeam])(using Context) =
@@ -89,40 +89,35 @@ final class TournamentForm(val helpers: Helpers, showUi: TournamentShow)(
val fields = tourFields(form, none)
frag(
form3.globalError(form),
- fields.name,
- form3.split(fields.rated, fields.variant),
- fields.clock,
- form3.split(fields.minutes, fields.waitMinutes),
- form3.split(fields.description(true), fields.startPosition),
- form3.fieldset(trans.site.advancedSettings())(cls := "conditions")(
- fields.advancedSettings,
- div(cls := "form")(
- conditionFields(form, fields, teams = leaderTeams, tour = none),
- fields.startDate
- )
+ form3.fieldset("Tournament", toggle = true.some)(
+ form3.split(fields.name, fields.minutes),
+ form3.split(fields.description)
),
+ form3.fieldset("Games", toggle = true.some)(
+ fields.clock,
+ form3.split(fields.variant, fields.startPosition)
+ ),
+ fields.waitStart,
+ conditionFields(form, fields, teams = leaderTeams, tour = none),
+ featuresFields(form),
fields.isTeamBattle.option(form3.hidden(form.prefix("teamBattleByTeam")))
)
def setupEdit(tour: Tournament, form: Form[?], myTeams: List[LightTeam])(using Context, FormPrefix) =
val fields = tourFields(form, tour.some)
frag(
- form3.split(fields.name, tour.isCreated.option(fields.startDate)),
- form3.split(fields.rated, fields.variant),
- fields.clock,
- form3.split(
- if lila.tournament.TournamentForm.minutes contains tour.minutes then form3.split(fields.minutes)
- else
- form3.group(form.prefix("minutes"), trans.site.duration(), half = true):
- form3.input(_)(tpe := "number")
- ),
- form3.split(fields.description(true), fields.startPosition),
form3.globalError(form),
- form3.fieldset(trans.site.advancedSettings())(cls := "conditions")(
- fields.advancedSettings,
- div(cls := "form"):
- conditionFields(form, fields, teams = myTeams, tour = tour.some)
- )
+ form3.fieldset("Tournament", toggle = true.some)(
+ form3.split(fields.name, fields.minutes),
+ form3.split(fields.description)
+ ),
+ form3.fieldset("Games", toggle = false.some)(
+ fields.clock,
+ form3.split(fields.variant, fields.startPosition)
+ ),
+ fields.waitStart,
+ conditionFields(form, fields, teams = myTeams, tour = tour.some),
+ featuresFields(form)
)
private val gatheringFormUi = GatheringFormUi(helpers)
@@ -133,7 +128,8 @@ final class TournamentForm(val helpers: Helpers, showUi: TournamentShow)(
teams: List[LightTeam],
tour: Option[Tournament]
)(using ctx: Context)(using FormPrefix) =
- frag(
+ form3.fieldset("Entry conditions", toggle = tour.exists(_.conditions.list.nonEmpty).some)(
+ errMsg(form.prefix("conditions")),
form3.split(
fields.entryCode,
(tour.isEmpty && teams.nonEmpty).option {
@@ -156,35 +152,45 @@ final class TournamentForm(val helpers: Helpers, showUi: TournamentShow)(
gatheringFormUi.maxRating(form.prefix("conditions.maxRating.rating"))
),
form3.split(
- gatheringFormUi.allowList(form.prefix("conditions.allowList"))
- ),
- form3.split(
+ gatheringFormUi.allowList(form.prefix("conditions.allowList")),
(ctx.me.exists(_.hasTitle) || Granter.opt(_.ManageTournament)).so {
gatheringFormUi.titled(form.prefix("conditions.titled"))
- },
+ }
+ )
+ )
+
+ def featuresFields(form: Form[?])(using ctx: Context)(using FormPrefix) =
+ form3.fieldset("Features", toggle = false.some)(
+ form3.split(
form3.checkbox(
form.prefix("berserkable"),
trans.arena.allowBerserk(),
help = trans.arena.allowBerserkHelp().some,
half = true
),
- form3.hiddenFalse(form.prefix("berserkable"))
+ form3.hiddenFalse(form.prefix("berserkable")),
+ form3.checkbox(
+ form.prefix("streakable"),
+ trans.arena.arenaStreaks(),
+ help = trans.arena.arenaStreaksHelp().some,
+ half = true
+ ),
+ form3.hiddenFalse(form.prefix("streakable"))
),
form3.split(
+ form3.checkbox(
+ form.prefix("rated"),
+ trans.site.rated(),
+ help = trans.site.ratedFormHelp().some
+ ),
+ form3.hiddenFalse(form.prefix("rated")),
form3.checkbox(
form.prefix("hasChat"),
trans.site.chatRoom(),
help = trans.arena.allowChatHelp().some,
half = true
),
- form3.hiddenFalse(form.prefix("hasChat")),
- form3.checkbox(
- form.prefix("streakable"),
- trans.arena.arenaStreaks(),
- help = trans.arena.arenaStreaksHelp().some,
- half = true
- ),
- form3.hiddenFalse(form.prefix("streakable"))
+ form3.hiddenFalse(form.prefix("hasChat"))
)
)
@@ -333,31 +339,24 @@ final class TourFields(tourForm: TournamentForm)(form: Form[?], tour: Option[Tou
private def disabledAfterStart = tour.exists(!_.isCreated)
def name =
- form3.group(form.prefix("name"), trans.site.name()) { f =>
+ form3.group(
+ form.prefix("name"),
+ trans.site.name(),
+ half = true,
+ help = frag(
+ trans.site.safeTournamentName(),
+ br,
+ trans.site.inappropriateNameWarning(),
+ br,
+ trans.site.emptyTournamentName()
+ ).some
+ ) { f =>
div(
form3.input(f),
- " ",
if isTeamBattle then trans.team.teamBattle() else trans.arena.arena(),
- br,
- small(cls := "form-help")(
- trans.site.safeTournamentName(),
- br,
- trans.site.inappropriateNameWarning(),
- br,
- trans.site.emptyTournamentName()
- )
+ br
)
- }
-
- def rated =
- frag(
- form3.checkbox(
- form.prefix("rated"),
- trans.site.rated(),
- help = trans.site.ratedFormHelp().some
- ),
- form3.hiddenFalse(form.prefix("rated"))
- )
+ }(cls := "tour-name")
def variant =
form3.group(form.prefix("variant"), trans.site.variant(), half = true)(
form3.select(
@@ -388,16 +387,22 @@ final class TourFields(tourForm: TournamentForm)(form: Form[?], tour: Option[Tou
)
def minutes =
form3.group(form.prefix("minutes"), trans.site.duration(), half = true):
- form3.select(_, TournamentForm.minuteChoicesKeepingCustom(tour))
+ if tour.forall(t => lila.tournament.TournamentForm.minutes contains t.minutes)
+ then form3.select(_, TournamentForm.minuteChoicesKeepingCustom(tour))
+ else form3.input(_)(tpe := "number")
def waitMinutes =
form3.group(form.prefix("waitMinutes"), trans.site.timeBeforeTournamentStarts(), half = true):
form3.select(_, TournamentForm.waitMinuteChoices)
- def description(half: Boolean) =
+ def waitStart =
+ form3.fieldset("Start date", toggle = tour.forall(_.isCreated).some)(
+ form3.split(waitMinutes, startDate)
+ )
+ def description =
form3.group(
form.prefix("description"),
trans.site.tournDescription(),
help = trans.site.tournDescriptionHelp().some,
- half = half
+ half = true
)(form3.textarea(_)(rows := 4))
def entryCode =
form3.group(
@@ -406,20 +411,16 @@ final class TourFields(tourForm: TournamentForm)(form: Form[?], tour: Option[Tou
help = trans.site.makePrivateTournament().some,
half = true
)(form3.input(_)(autocomplete := "off"))
- def startDate =
- form3.group(
- form.prefix("startDate"),
- trans.arena.customStartDate(),
- help = trans.arena.customStartDateHelp().some
- )(form3.flatpickr(_))
+ def startDate = tour
+ .forall(_.isCreated)
+ .option:
+ form3.group(
+ form.prefix("startDate"),
+ trans.arena.customStartDate(),
+ help = trans.arena.customStartDateHelp().some,
+ half = true
+ )(form3.flatpickr(_))
def advancedSettings =
frag(
- errMsg(form.prefix("conditions")),
- p(
- strong(dataIcon := Icon.CautionTriangle, cls := "text")(trans.site.recommendNotTouching()),
- " ",
- trans.site.fewerPlayers(),
- " ",
- a(cls := "show")(trans.site.showAdvancedSettings())
- )
+ errMsg(form.prefix("conditions"))
)
diff --git a/modules/ublog/src/main/UblogMarkup.scala b/modules/ublog/src/main/UblogMarkup.scala
index 8131cdaa348f7..2aa51ac2724dc 100644
--- a/modules/ublog/src/main/UblogMarkup.scala
+++ b/modules/ublog/src/main/UblogMarkup.scala
@@ -39,7 +39,7 @@ final class UblogMarkup(
private val cache = cacheApi[(UblogPostId, Markdown), Html](2048, "ublog.markup"):
_.maximumSize(2048)
- .expireAfterWrite(if mode.isProd then 15 minutes else 1 second)
+ .expireAfterWrite(if mode.isProd then 20 minutes else 1 second)
.buildAsyncFuture: (id, markdown) =>
Bus
.ask("lpv")(AllPgnsFromText(markdown.value, _))
diff --git a/modules/ublog/src/main/ui/UblogFormUi.scala b/modules/ublog/src/main/ui/UblogFormUi.scala
index 7cab4c929c97e..bd99c2d14c69f 100644
--- a/modules/ublog/src/main/ui/UblogFormUi.scala
+++ b/modules/ublog/src/main/ui/UblogFormUi.scala
@@ -18,7 +18,7 @@ final class UblogFormUi(helpers: Helpers, ui: UblogUi)(
def create(user: User, f: Form[UblogForm.UblogPostData], captcha: Captcha)(using Context) =
FormPage(s"${trans.ublog.xBlog.txt(user.username)} • ${trans.ublog.newPost.txt()}")
.js(captchaEsmInit):
- main(cls := "page-menu page-small")(
+ main(cls := "page-menu page")(
ui.menu(Left(user.id)),
div(cls := "page-menu__content box ublog-post-form")(
standardFlash,
@@ -30,7 +30,7 @@ final class UblogFormUi(helpers: Helpers, ui: UblogUi)(
def edit(post: UblogPost, f: Form[UblogForm.UblogPostData])(using ctx: Context) =
FormPage(s"${trans.ublog.xBlog.txt(titleNameOrId(post.created.by))} • ${post.title}"):
- main(cls := "page-menu page-small")(
+ main(cls := "page-menu page")(
ui.menu(Left(post.created.by)),
div(cls := "page-menu__content box ublog-post-form")(
standardFlash,
@@ -41,7 +41,6 @@ final class UblogFormUi(helpers: Helpers, ui: UblogUi)(
),
a(href := ui.urlOfPost(post), dataIcon := Icon.Eye, cls := "text", targetBlank)("Preview")
),
- image(post),
inner(f, Right(post), none),
postForm(
cls := "ublog-post-form__delete",
@@ -65,14 +64,7 @@ final class UblogFormUi(helpers: Helpers, ui: UblogUi)(
action := post.fold(u => routes.Ublog.create(u.username), p => routes.Ublog.update(p.id))
)(
form3.globalError(form),
- post.toOption.map { p =>
- frag(
- form3.split(
- form3.group(form("imageAlt"), trans.ublog.imageAlt(), half = true)(form3.input(_)),
- form3.group(form("imageCredit"), trans.ublog.imageCredit(), half = true)(form3.input(_))
- )(cls := s"ublog-post-form__image-text ${p.image.isDefined.so("visible")}")
- )
- },
+ post.toOption.map(image(_, form)),
form3.group(form("title"), trans.ublog.postTitle())(form3.input(_)(autofocus)),
form3.group(form("intro"), trans.ublog.postIntro())(form3.input(_)(autofocus)),
form3.group(
@@ -130,44 +122,51 @@ final class UblogFormUi(helpers: Helpers, ui: UblogUi)(
)
)
- private def image(post: UblogPost)(using ctx: Context) =
- div(cls := "ublog-image-edit", data("post-url") := routes.Ublog.image(post.id))(
- ui.thumbnail(post, _.Size.Small)(
- cls := "drop-target " + post.image.isDefined.so("user-image"),
- attr("draggable") := "true"
- ),
- div(
- if ctx.is(post.created.by) then
- frag(
- p(strong(trans.ublog.uploadAnImageForYourPost())),
- p(
- trans.ublog.safeToUseImages(),
- fragList(
- List(
- "unsplash.com" -> "https://unsplash.com",
- "commons.wikimedia.org" -> "https://commons.wikimedia.org",
- "pixabay.com" -> "https://pixabay.com",
- "pexels.com" -> "https://pexels.com",
- "piqsels.com" -> "https://piqsels.com",
- "freeimages.com" -> "https://freeimages.com"
- ).map: (name, url) =>
- a(href := url, targetBlank)(name)
+ private def image(post: UblogPost, form: Form[UblogForm.UblogPostData])(using ctx: Context) =
+ form3.fieldset("Image", toggle = true.some)(
+ div(cls := "form-group ublog-image-edit", data("post-url") := routes.Ublog.image(post.id))(
+ ui.thumbnail(post, _.Size.Small)(
+ cls := "drop-target " + post.image.isDefined.so("user-image"),
+ attr("draggable") := "true"
+ ),
+ div(
+ if ctx.is(post.created.by) then
+ frag(
+ p(strong(trans.ublog.uploadAnImageForYourPost())),
+ p(
+ trans.ublog.safeToUseImages(),
+ fragList(
+ List(
+ "unsplash.com" -> "https://unsplash.com",
+ "commons.wikimedia.org" -> "https://commons.wikimedia.org",
+ "pixabay.com" -> "https://pixabay.com",
+ "pexels.com" -> "https://pexels.com",
+ "piqsels.com" -> "https://piqsels.com",
+ "freeimages.com" -> "https://freeimages.com"
+ ).map: (name, url) =>
+ a(href := url, targetBlank)(name)
+ )
+ ),
+ p(trans.ublog.useImagesYouMadeYourself()),
+ p(strong(trans.streamer.maxSize(s"${lila.memo.PicfitApi.uploadMaxMb}MB."))),
+ form3.file.selectImage()
+ )
+ else
+ postForm(
+ action := routes.Ublog.image(post.id),
+ enctype := "multipart/form-data"
+ )(
+ post.image.isDefined.option(submitButton(cls := "button button-red confirm"):
+ trans.ublog.deleteImage()
)
- ),
- p(trans.ublog.useImagesYouMadeYourself()),
- p(strong(trans.streamer.maxSize(s"${lila.memo.PicfitApi.uploadMaxMb}MB."))),
- form3.file.selectImage()
- )
- else
- postForm(
- cls := "ublog-post-form__image",
- action := routes.Ublog.image(post.id),
- enctype := "multipart/form-data"
- )(
- post.image.isDefined.option(submitButton(cls := "button button-red confirm"):
- trans.ublog.deleteImage()
)
- )
+ )
+ ),
+ post.image.isDefined.option(
+ form3.split(
+ form3.group(form("imageAlt"), trans.ublog.imageAlt(), half = true)(form3.input(_)),
+ form3.group(form("imageCredit"), trans.ublog.imageCredit(), half = true)(form3.input(_))
+ )(cls := s"ublog-post-form__image-text visible")
)
)
diff --git a/modules/ui/src/main/helper/Form3.scala b/modules/ui/src/main/helper/Form3.scala
index e7a014b499010..91d52d25fb21d 100644
--- a/modules/ui/src/main/helper/Form3.scala
+++ b/modules/ui/src/main/helper/Form3.scala
@@ -178,8 +178,14 @@ final class Form3(formHelper: FormHelper & I18nHelper, flairApi: FlairApi):
// allows disabling of a field that defaults to true
def hiddenFalse(field: Field): Tag = hidden(field, "false".some)
- def passwordModified(field: Field, content: Frag)(modifiers: Modifier*)(using Translate): Frag =
- group(field, content)(input(_, typ = "password")(required)(modifiers))
+ def passwordModified(field: Field, content: Frag, reveal: Boolean = true)(
+ modifiers: Modifier*
+ )(using Translate): Frag =
+ group(field, content): f =>
+ div(cls := "password-wrapper")(
+ input(f, typ = "password")(required)(modifiers),
+ reveal.option(button(cls := "password-reveal", tpe := "button", dataIcon := Icon.Eye))
+ )
def passwordComplexityMeter(labelContent: Frag): Frag =
div(cls := "password-complexity")(
@@ -192,8 +198,14 @@ final class Form3(formHelper: FormHelper & I18nHelper, flairApi: FlairApi):
form.globalError.map: err =>
div(cls := "form-group is-invalid")(error(err))
- def fieldset(legend: Frag): Tag =
- st.fieldset(cls := "form-fieldset")(st.legend(legend))
+ def fieldset(legend: Frag, toggle: Option[Boolean] = none): Tag =
+ st.fieldset(
+ cls := List(
+ "form-fieldset" -> true,
+ "form-fieldset--toggle" -> toggle.isDefined,
+ "form-fieldset--toggle-off" -> toggle.has(false)
+ )
+ )(st.legend(toggle.map(_ => tabindex := 0))(legend))
private val dataEnableTime = attr("data-enable-time")
private val dataTime24h = attr("data-time_24h")
@@ -246,4 +258,4 @@ final class Form3(formHelper: FormHelper & I18nHelper, flairApi: FlairApi):
def image(name: String): Frag =
st.input(tpe := "file", st.name := name, accept := "image/png, image/jpeg, image/webp")
def pgn(name: String): Frag = st.input(tpe := "file", st.name := name, accept := ".pgn")
- def selectImage = button(cls := "button select-image")("select image")
+ def selectImage = button(cls := "button select-image", tpe := "button")("Select image")
diff --git a/modules/ui/src/main/scalatags.scala b/modules/ui/src/main/scalatags.scala
index c787f6f03c46d..74dd0feed5603 100644
--- a/modules/ui/src/main/scalatags.scala
+++ b/modules/ui/src/main/scalatags.scala
@@ -7,6 +7,7 @@ import scalalib.Render
import scalatags.Text.all.*
import scalatags.Text.{ Aggregate, Cap, GenericAttr }
import scalatags.text.Builder
+import io.mola.galimatias.URL
// collection of lila attrs
trait ScalatagsAttrs:
@@ -108,6 +109,7 @@ trait ScalatagsTemplate
/* Convert play URLs to scalatags attributes with toString */
given GenericAttr[Call] = GenericAttr[Call]
+ given GenericAttr[URL] = GenericAttr[URL]
object ScalatagsTemplate extends ScalatagsTemplate
@@ -118,6 +120,7 @@ trait ScalatagsExtensions:
export lila.core.perm.Granter
given Render[Icon] = _.value
+ given Render[URL] = _.toString
given [A](using Render[A]): Conversion[A, Frag] = a => StringFrag(a.render)
diff --git a/modules/user/src/main/Flags.scala b/modules/user/src/main/Flags.scala
index 150589bf31255..80cb40bc83c11 100644
--- a/modules/user/src/main/Flags.scala
+++ b/modules/user/src/main/Flags.scala
@@ -208,6 +208,8 @@ object Flags extends lila.core.user.FlagApi:
C("PR", "Puerto Rico"),
C("PS", "Palestine"),
C("PT", "Portugal"),
+ C("PT-20", "Azores"),
+ C("PT-30", "Madeira"),
C("PW", "Palau"),
C("PY", "Paraguay"),
C("QA", "Qatar"),
diff --git a/modules/user/src/main/Profile.scala b/modules/user/src/main/Profile.scala
index 92f1d155a7f08..db945490d1ba6 100644
--- a/modules/user/src/main/Profile.scala
+++ b/modules/user/src/main/Profile.scala
@@ -23,8 +23,7 @@ object Profile:
def filterTroll(troll: Boolean): Profile = p.copy(
bio = p.bio.ifFalse(troll),
- firstName = p.firstName.ifFalse(troll),
- lastName = p.lastName.ifFalse(troll),
+ realName = p.realName.ifFalse(troll),
location = p.location.ifFalse(troll),
links = p.links.ifFalse(troll)
)
diff --git a/modules/user/src/main/UserForm.scala b/modules/user/src/main/UserForm.scala
index a7986d85a9131..9ae6a0864a3fb 100644
--- a/modules/user/src/main/UserForm.scala
+++ b/modules/user/src/main/UserForm.scala
@@ -42,8 +42,7 @@ final class UserForm:
"flag" -> optional(text.verifying(Flags.codeSet contains _)),
"location" -> optional(cleanNoSymbolsAndNonEmptyText(maxLength = 80)),
"bio" -> optional(cleanNoSymbolsAndNonEmptyText(maxLength = 400)),
- "firstName" -> nameField,
- "lastName" -> nameField,
+ "realName" -> optional(cleanNoSymbolsText(minLength = 1, maxLength = 100)),
"fideRating" -> optional(number(min = 1400, max = 3000)),
"uscfRating" -> optional(number(min = 100, max = 3000)),
"ecfRating" -> optional(number(min = 0, max = 3000)),
@@ -58,8 +57,6 @@ final class UserForm:
def flair(using Me) = Form[Option[Flair]]:
single(FlairApi.formPair())
- private def nameField = optional(cleanNoSymbolsText(minLength = 1, maxLength = 20))
-
object UserForm:
val note = Form:
diff --git a/modules/user/src/main/UserRepo.scala b/modules/user/src/main/UserRepo.scala
index fe4fde0760da4..bb7d297848866 100644
--- a/modules/user/src/main/UserRepo.scala
+++ b/modules/user/src/main/UserRepo.scala
@@ -154,6 +154,9 @@ final class UserRepo(c: Coll)(using Executor) extends lila.core.user.UserRepo(c)
def setProfile(id: UserId, profile: Profile): Funit =
coll.updateField($id(id), F.profile, profile).void
+ def setRealName(id: UserId, name: String): Funit =
+ coll.updateField($id(id), s"${F.profile}.realName", name).void
+
def setUsernameCased(id: UserId, name: UserName): Funit =
if id.is(name) then
coll.update
diff --git a/modules/web/src/main/Limiters.scala b/modules/web/src/main/Limiters.scala
index 3bbfb32c617fe..d928b4ba29cb4 100644
--- a/modules/web/src/main/Limiters.scala
+++ b/modules/web/src/main/Limiters.scala
@@ -143,5 +143,7 @@ final class Limiters(using Executor, lila.core.config.RateLimit):
val studyPgn = RateLimit[IpAddress](credits = 31, duration = 1.minute, key = "export.study.pgn.ip")
+ val relayPgn = RateLimit[IpAddress](credits = 61, duration = 1.minute, key = "export.relay.pgn.ip")
+
val teamKick =
RateLimit.composite[IpAddress](key = "team.kick.api.ip")(("fast", 10, 2.minutes), ("slow", 50, 1.day))
diff --git a/modules/web/src/main/ui/AuthUi.scala b/modules/web/src/main/ui/AuthUi.scala
index 587d40472d729..8f2da7dddea76 100644
--- a/modules/web/src/main/ui/AuthUi.scala
+++ b/modules/web/src/main/ui/AuthUi.scala
@@ -197,8 +197,8 @@ email.setCustomValidity(email.validity.patternMismatch ? currentError : "");
Context
)(using me: Me) =
Page(s"${me.username} - ${trans.site.changePassword.txt()}")
- .css("bits.form3")
- .js(jsModuleInit("bits.passwordComplexity")):
+ .css("bits.auth")
+ .js(jsModuleInit("bits.login", "reset")):
main(cls := "page-small box box-pad")(
boxTop(
(ok match
diff --git a/modules/web/src/main/ui/LearnUi.scala b/modules/web/src/main/ui/LearnUi.scala
index 72054f2ef7631..f05e1b496518a 100644
--- a/modules/web/src/main/ui/LearnUi.scala
+++ b/modules/web/src/main/ui/LearnUi.scala
@@ -10,12 +10,18 @@ final class LearnUi(helpers: Helpers):
import helpers.{ *, given }
import trans.{ learn as trl }
- def apply(data: Option[play.api.libs.json.JsValue])(using Context) =
+ def apply(data: Option[play.api.libs.json.JsValue])(using ctx: Context) =
Page(s"${trl.learnChess.txt()} - ${trl.byPlaying.txt()}")
.js:
PageModule(
"learn",
- Json.obj("data" -> data, "i18n" -> i18nJsObject(i18nKeys))
+ Json.obj(
+ "data" -> data,
+ "i18n" -> i18nJsObject(i18nKeys),
+ "pref" -> Json.obj(
+ "coords" -> ctx.pref.coords
+ )
+ )
)
.css("learn")
.graph(
diff --git a/modules/web/src/main/ui/contact.scala b/modules/web/src/main/ui/contact.scala
index f94f159b55e55..50e12a301cec5 100644
--- a/modules/web/src/main/ui/contact.scala
+++ b/modules/web/src/main/ui/contact.scala
@@ -222,18 +222,6 @@ object contact:
)
)
),
- Leaf(
- "broadcast",
- wantBroadcastTournament(),
- frag(
- p(a(href := routes.RelayTour.help)(learnHowToMakeBroadcasts()), "."),
- p(
- contactAboutOfficialBroadcasts(),
- " ",
- sendEmailAt(contactEmailLink("broadcast@lichess.org"))
- )
- )
- ),
frag(
p(doNotMessageModerators()),
p(sendAppealTo(a(href := routes.Appeal.home)(routes.Appeal.home.url))),
@@ -322,7 +310,7 @@ object contact:
"dmca",
"DMCA / Intellectual Property Take Down Notice",
p(
- a(href := dmcaUrl)("Complete this form"),
+ a(href := "/dmca")("Complete this form"),
" ",
"if you are the original copyright holder, or an agent acting on behalf of the copyright holder, and believe Lichess is hosting work(s) you hold the copyright to."
)
@@ -339,5 +327,3 @@ object contact:
)
)
)
-
- val dmcaUrl = "/dmca"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 47e38a009a786..1bba8567486ad 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -496,6 +496,9 @@ importers:
chessops:
specifier: ^0.14.1
version: 0.14.1
+ common:
+ specifier: workspace:*
+ version: link:../common
snabbdom:
specifier: 3.5.1
version: 3.5.1
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index 88f7a4009c0d2..5cfd3dfbe088e 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -85,7 +85,7 @@ object Dependencies {
object play {
val playVersion = "2.8.18-lila_3.18"
- val json = "org.playframework" %% "play-json" % "3.0.3"
+ val json = "org.playframework" %% "play-json" % "3.0.4"
val api = "com.typesafe.play" %% "play" % playVersion
val server = "com.typesafe.play" %% "play-server" % playVersion
val netty = "com.typesafe.play" %% "play-netty-server" % playVersion
@@ -94,7 +94,7 @@ object Dependencies {
}
object playWs {
- val version = "2.2.7"
+ val version = "2.2.8"
val ahc = "com.typesafe.play" %% "play-ahc-ws-standalone" % version
val json = "com.typesafe.play" %% "play-ws-standalone-json" % version
val bundle = Seq(ahc, json)
diff --git a/public/images/flags/PT-20.png b/public/images/flags/PT-20.png
new file mode 100644
index 0000000000000..4cef77e54bee7
Binary files /dev/null and b/public/images/flags/PT-20.png differ
diff --git a/public/images/flags/PT-30.png b/public/images/flags/PT-30.png
new file mode 100644
index 0000000000000..8f170fd3f3212
Binary files /dev/null and b/public/images/flags/PT-30.png differ
diff --git a/public/piece-css/cardinal.css b/public/piece-css/cardinal.css
index a4d92e14347c7..3d0be4ae71e21 100644
--- a/public/piece-css/cardinal.css
+++ b/public/piece-css/cardinal.css
@@ -1,12 +1,12 @@
-.is2d .pawn.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iNDEyNy4zIiB4Mj0iNDIzNS43IiB5MT0iLTI1NTguNCIgeTI9Ii0yNTU4LjQiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjI3Njc3IDAgMCAuMjc1NTUgLTExMzIuMyA3MzEuOTYpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZTZlNmU2Ii8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGlkPSJiIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuNDk4IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii4zIi8+PGZlT2Zmc2V0IGR4PSIxIiBkeT0iMSIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNhKSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0ic3F1YXJlIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuMTM1IiBkPSJNMjUuMDI0IDQzLjQwMUgxMS4xMTljLTIuNTUxLTUuODg1IDQuMjEzLTExLjM0MSA4Ljk2OC0xMy4xOTQtNS42ODItMy4xNi0yLjYwMi0xMS4yMTkgMi4yNy0xMS44NzMtMS4xNi0uNzYzLTEuNzQtMi4zOTMtMS43NC0zLjcgMC0xLjA5LjQ2My0yLjA3MiAxLjI3NS0yLjgzNC44MTItLjc2MyAxLjg1Ni0xLjIgMy4xMzEtMS4yIDEuMTYgMCAyLjIwNC40MzcgMy4xMzIgMS4yLjgxMi43NjIgMS4yNzUgMS43NDMgMS4yNzUgMi44MzMgMCAxLjMwOC0uNTggMi45MzgtMS43NCAzLjcwMSA1LjMzNiAyLjA3IDcuMjU3IDkuNjkzIDIuMjcgMTEuODczIDYuNDk0IDIuMjg5IDExLjA1NiA4LjA3MiA4Ljk2OCAxMy4xOTR6IiBjbGFzcz0ic3QzMSIgZmlsdGVyPSJ1cmwoI2IpIiB0cmFuc2Zvcm09Im1hdHJpeCguOTY2NTggMCAwIC45NzI0NSAuODMzIDEuMjQzKSIvPjwvc3ZnPg==')}
-.is2d .knight.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iLTQ1NS4zOSIgeDI9Ii00MTkuNDEiIHkxPSItMzM4LjIzIiB5Mj0iLTMzOC4yMyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ZjZmNmOCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2U3ZTdlMyIvPjwvbGluZWFyR3JhZGllbnQ+PGZpbHRlciBpZD0iYiIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVGbG9vZCBmbG9vZC1jb2xvcj0iIzAwMCIgZmxvb2Qtb3BhY2l0eT0iLjQ5OCIgcmVzdWx0PSJmbG9vZCIvPjxmZUNvbXBvc2l0ZSBpbj0iZmxvb2QiIGluMj0iU291cmNlR3JhcGhpYyIgb3BlcmF0b3I9ImluIiByZXN1bHQ9ImNvbXBvc2l0ZTEiLz48ZmVHYXVzc2lhbkJsdXIgaW49ImNvbXBvc2l0ZTEiIHJlc3VsdD0iYmx1ciIgc3RkRGV2aWF0aW9uPSIuNiIvPjxmZU9mZnNldCBkeD0iMS42IiBkeT0iMS40IiByZXN1bHQ9Im9mZnNldCIvPjxmZUNvbXBvc2l0ZSBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJvZmZzZXQiIHJlc3VsdD0iY29tcG9zaXRlMiIvPjwvZmlsdGVyPjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS4wOTkiIGQ9Ik0tNDQzLjkyLTMzMi45NWMyLjEtMS4xOTggMy4zMjItMS4xODMgNS40NjMtMi4xOTkuMjI0IDcuNDI1LTkuOTAxIDcuNDU2LTguMDg3IDE1LjM2bDI2LjQwNS4wMDJzMy4wOTYtMzIuMjctMTYuNzgyLTMzLjYyMmMwIDAtMS45MTQtMy42MDUtMy45MjUtMy4yNSAwIDAtMS4wNjUuODM4LS40NTcgMy4yMDdsLTIuMzA0Ljc0NnMtMy4yMTQtMi4wNzItNC4xMjQtMS4yN2MtLjg1OC4zNyAxLjA5OCAzLjI4IDEuODc2IDMuOTg2LS43ODggMS4xNDItOC41NDIgMTIuMTA4LTguOTYgMTUuNjgtLjI2NiAyLjI3NyAyLjAyMSAzLjUxOCAzLjcxNiA0LjExOS45NjQuMzQxIDEuNzM2LjQ3NiAxLjczNi40NzYgMS40MjUtLjI1NiAzLjM0My0yLjAzNyA1LjQ0My0zLjIzNXoiIGZpbHRlcj0idXJsKCNiKSIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDA4IDAgMCAxLjAwMDEgNDYyLjc1IDM2My4yNikiLz48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yMy45NDEgMjguMDg2czQuNDMzLTEuODY3IDQuMjI0LTUuODM1Ii8+PHBhdGggc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iMS40IiBkPSJNMTkuMTA0IDE4LjQ3M3MuNTk0LTEuODQ2IDMuNDUzLTIuMjk0Ii8+PGVsbGlwc2UgY3g9IjIxLjAyNyIgY3k9IjE4LjAwMSIgcng9IjEuMjQyIiByeT0iMS4xNjgiIHN0eWxlPSJwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIi8+PHBhdGggZmlsbD0iI2ZmZiIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iMS40IiBkPSJNOS4xNyAyOS4yNDFzLjI1NC0uNjgyLjkyNC0xLjExOCIvPjxwYXRoIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuMiIgZD0iTTExLjY0IDMyLjI4M2MuNjktLjg4NyAxLjU4My0xLjMxOSAyLjM4NC0xLjk1NyIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0zMC44MDYgMTQuODcyYzQuMzA1IDIuNjMzIDguNDYgOS4yNSA4LjExIDI2LjA4Ii8+PC9zdmc+')}
-.is2d .bishop.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii40OTgiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjMiLz48ZmVPZmZzZXQgZHg9IjEiIGR5PSIxIiByZXN1bHQ9Im9mZnNldCIvPjxmZUNvbXBvc2l0ZSBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJvZmZzZXQiIHJlc3VsdD0iY29tcG9zaXRlMiIvPjwvZmlsdGVyPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjEzMTk3IiB4Mj0iMTMzNDEiIHkxPSItOTU5MSIgeTI9Ii05NTkxIiBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKC0zNDg1LjcgMjU2Mi42KSBzY2FsZSguMjY0NTgpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZTZlNmU2Ii8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNhKSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuMSIgZD0iTTI1IDYuNTVjLS44NzggMC0xLjY1NC4yOS0yLjI2MS45MDMtLjY0MS42MTItLjk0NiAxLjMyMS0uOTQ2IDIuMTU5IDAgMS4yMjUuNTc0IDIuMTI3IDEuNzU1IDIuNzQtMi45NjkgMy4yODUtOC43MDcgNS44MjEtOC44MSAxMC44MjcuMDA3IDIuNjc1IDEuNDY2IDQuNzY0IDMuMzA4IDYuOGwtMS4xMTQgNS44MzNjMS42OTcuNTQyIDMuMDkuOTQyIDQuODI3IDEuMTI4LTMuODgyIDQuNTc2LTEwLjc4Ny0xLjc0LTE1LjIwOSAyLjkzM2wyLjMzIDMuNTc3YzUuNTkzLTMuOTYyIDEzLjM3NSAzLjY3MyAxNi4xMi0zLjk2MiAyLjc0NiA3LjYzNSAxMC41MjguMDAzIDE2LjEyIDMuOTYybDIuMzMtMy41NzdjLTQuNDIyLTQuNjczLTExLjMyNyAxLjY0My0xNS4yMDktMi45MzMgMS43MzgtLjE4NiAzLjEzLS41ODYgNC44MjgtMS4xMjhsLTEuMTE1LTUuODMzYzEuODQzLTIuMDM2IDMuMzAyLTQuMTI1IDMuMzA5LTYuOC0uMTAzLTUuMDA2LTUuODQyLTcuNTQyLTguODExLTEwLjgyOCAxLjE4MS0uNjEyIDEuNzU1LTEuNTE0IDEuNzU1LTIuNzQgMC0uODM3LS4zMDQtMS41NDYtLjk0NS0yLjE1OC0uNjA4LS42MTMtMS4zODQtLjkwMy0yLjI2MS0uOTAzeiIgZmlsdGVyPSJ1cmwoI2IpIi8+PGVsbGlwc2UgY3g9IjI3MjAuMyIgY3k9Ii0yNzEuNCIgY2xhc3M9InN0MTUiIGZpbHRlcj0idXJsKCNjKSIgcng9IjE2LjMiIHJ5PSIyLjUiIHRyYW5zZm9ybT0ibWF0cml4KC4zMzIzMiAwIDAgLjI0OTk4IC04NzkuMDEgMTAyLjQ3KSIvPjxlbGxpcHNlIGN4PSIyNSIgY3k9IjkuNjExIiBjbGFzcz0ic3QxNSIgcng9IjEuMTQiIHJ5PSIxLjE0NyIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0yMS4zMzMgMjMuMjY2aDcuMzMzTTI1IDE5LjkzMnY2Ljc1MiIvPjwvc3ZnPg==')}
-.is2d .rook.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iNDUwMS41IiB4Mj0iNDU5NC42IiB5MT0iLTU3Mi40IiB5Mj0iLTU3Mi40IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC4zNDIwOCAwIDAgLjI4MzcgLTE1MzAuOCAxODcuMzkpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZTZlNmU2Ii8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGlkPSJiIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuNDk4IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii4zIi8+PGZlT2Zmc2V0IGR4PSIxIiBkeT0iMSIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNhKSIgc3Ryb2tlPSIjMDEwMTAxIiBzdHJva2Utd2lkdGg9IjEuMTQ0IiBkPSJNMjEuOTMyIDYuNTQ2VjkuNDhoLTQuMDkxVjYuODkyaC01Ljc5NnY3Ljk3NWw0LjUzMyAzLjE0MnYxMi41NjdsLTMuODUgMi40ODZ2NS4yMTNIOS42NTh2NS4xNzloMzAuNjgydi01LjE4aC0zLjA2OHYtNS4yMTJsLTMuODUtMi40ODZWMTguMDQzbDQuNTMyLTMuMjExdi03Ljk0aC01Ljc5NnYyLjU4N2gtNC40MzJWNi41NDZIMjQuODN6IiBjbGFzcz0ic3QxNCIgZmlsdGVyPSJ1cmwoI2IpIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAwNTUgMCAwIC45MTk4IC0uMTM3IDMuNTA1KSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0xOC44MjkgMzEuNDM4aDExLjk5OE0xOC44MjkgMjAuMDA2aDExLjk5OCIvPjwvc3ZnPg==')}
-.is2d .queen.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii40OTgiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjMiLz48ZmVPZmZzZXQgZHg9IjEiIGR5PSIxIiByZXN1bHQ9Im9mZnNldCIvPjxmZUNvbXBvc2l0ZSBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJvZmZzZXQiIHJlc3VsdD0iY29tcG9zaXRlMiIvPjwvZmlsdGVyPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9Ii03MS42MzgiIHgyPSItMzAuNjc5IiB5MT0iLTgzLjMyNCIgeTI9Ii04My4zMjQiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjk3NjQzIDAgMCAuOTkyODcgNzQuOTUyIDEwNy43MykiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNmZmYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNlNmU2ZTYiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yNC45OTQgNi41NDl2MGMtMS41NjguMDA2LTIuODM1IDEuMTgxLTIuODM2IDIuNjMuMDAyIDEuMTkzLjg3MyAyLjIzNSAyLjEyMiAyLjUzOS0uNjg4IDQuNDUtMS45NjcgOS43MjYtMi42MzQgMTQuMTEybC00LjA3LTEyLjkyN2MuOTY4LS40NDQgMS41OC0xLjM1NiAxLjU4LTIuMzU0IDAtMS40NTItMS4yNzUtMi42My0yLjg0Ny0yLjYzLTEuNTcyLjAwMS0yLjg0NyAxLjE3OC0yLjg0NyAyLjYzLjAwMiAxLjIwNi44OSAyLjI1NiAyLjE1NyAyLjU0OGwtLjQ0IDEzLjI1OC01LjQ4Mi0xMC42MTFjLjk1MS0uNDUgMS41NS0xLjM1NCAxLjU1LTIuMzQgMC0xLjQ1My0xLjI3NS0yLjYzLTIuODQ3LTIuNjMtMS41NzMgMC0yLjg0NyAxLjE3Ny0yLjg0NyAyLjYzIDAgMS4zMzQgMS4wODQgMi40NTYgMi41MTkgMi42MWwyLjc2IDE2LjUwNyA0LjA1IDUuMjU4LTEuMDA1IDMuNjM0Yy0uMDQyLjY1NiA0Ljg0OSAyLjAyNyAxMS4xMjIgMi4wNCA2LjI3NC0uMDEzIDExLjE2NC0xLjM4NCAxMS4xMjItMi4wNGwtMS4wMDQtMy42MzQgNC4wNS01LjI1OCAyLjc2LTE2LjUwN2MxLjQzNS0uMTU0IDIuNTE4LTEuMjc2IDIuNTItMi42MSAwLTEuNDUzLTEuMjc1LTIuNjMtMi44NDgtMi42My0xLjU3MiAwLTIuODQ2IDEuMTc3LTIuODQ2IDIuNjMgMCAuOTg2LjU5OCAxLjg5IDEuNTUgMi4zNGwtNS40ODQgMTAuNjEtLjQzOS0xMy4yNTdjMS4yNjYtLjI5MiAyLjE1NS0xLjM0MiAyLjE1Ny0yLjU0OCAwLTEuNDUyLTEuMjc1LTIuNjMtMi44NDctMi42My0xLjU3Mi4wMDEtMi44NDcgMS4xNzgtMi44NDcgMi42MyAwIC45OTguNjEyIDEuOTEgMS41OCAyLjM1NGwtNC4wNyAxMi45MjdjLS42NjgtNC4zODYtMS45NDYtOS42NjMtMi42MzUtMTQuMTEyIDEuMjUtLjMwNCAyLjEyMS0xLjM0NiAyLjEyMy0yLjU0IDAtMS40NDgtMS4yNjgtMi42MjMtMi44MzYtMi42Mjl2MGgtLjAxMXoiIGZpbHRlcj0idXJsKCNiKSIgc3R5bGU9InBhaW50LW9yZGVyOm5vcm1hbCIvPjxlbGxpcHNlIGN4PSI0NzA4LjciIGN5PSItMjUxNy42IiBjbGFzcz0ic3QxNSIgZmlsdGVyPSJ1cmwoI2MpIiByeD0iMzIuMTI2IiByeT0iMi44NDQiIHRyYW5zZm9ybT0ibWF0cml4KC4yNTkzOSAwIDAgLjI5Mjk4IC0xMTk2LjQgNzc4LjEyKSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBkPSJNMTUuMTcyIDM0LjA3NnMyLjctMS4yNDkgOS44MDItMS4yNTZjNy4xMDMtLjAxIDkuOCAxLjI1NiA5LjggMS4yNTYiIHN0eWxlPSJwYWludC1vcmRlcjpzdHJva2UgZmlsbCBtYXJrZXJzIi8+PC9zdmc+')}
-.is2d .king.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii40OTgiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjYiLz48ZmVPZmZzZXQgZHg9IjEuNiIgZHk9IjEuNCIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgxPSIyOTg2LjQiIHgyPSIzMTI4LjQiIHkxPSIxNjIzLjgiIHkyPSIxNjIzLjgiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjI3MTQxIDAgMCAuMjcyMTggLTgwNC44MSAtNDE3LjQ1KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ZmZiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2U2ZTZlNiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGZpbGw9InVybCgjYSkiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yMy4yODMgNS41NXYzLjIzOGgtMy4zNjR2Mi45MmgzLjM2NHYxLjc1OGMtMy4zNjggMi4xMjctMi45OTYgNS43NC0yLjk5NiA1Ljc0QzkuMjc4IDEwLjY5LS4zODUgMjYuNzcgMTIuMzQzIDMyLjI2djguNzM0YzAgLjk1IDUuNjY3IDIuNDU2IDEyLjY1NyAyLjQ1NnMxMi42NTctMS41MDYgMTIuNjU3LTIuNDU2VjMyLjI2YzEyLjcyOC01LjQ5IDMuMDY2LTIxLjU2OS03Ljk0My0xMy4wNTMgMCAwIC4zNzItMy42MTMtMi45OTYtNS43NHYtMS43NThoMy4zNjR2LTIuOTJoLTMuMzY0VjUuNTUxaC0xLjcxN3oiIGZpbHRlcj0idXJsKCNiKSIvPjxlbGxpcHNlIGN4PSI3MS4wNzciIGN5PSIxMzEuNTQiIGNsYXNzPSJzdDE1IiBmaWx0ZXI9InVybCgjYykiIHJ4PSIzMi4xMjYiIHJ5PSIyLjg0NCIgdHJhbnNmb3JtPSJtYXRyaXgoLjI4NTMzIDAgMCAuMzIyMyA0LjcyIC0xLjk4KSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0yNy4wMzIgMzAuMjY3YzEuNDktMTIuMTAyIDExLjk0My0xMi40NDEgMTMuMzY0LTcuMzggMS40MiA1LjA2Mi00LjczNiA3LjM4LTQuNzM2IDcuMzhzLTQuODc1LS42MzgtMTAuNjYtLjYzOC0xMC42Ni42MzgtMTAuNjYuNjM4LTYuMTU2LTIuMzE4LTQuNzM1LTcuMzggMTEuODc0LTQuNzIyIDEzLjM2NCA3LjM4Ii8+PC9zdmc+')}
-.is2d .pawn.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iNDEyNy4yIiB4Mj0iNDIzNS43IiB5MT0iLTI1NTguMyIgeTI9Ii0yNTU4LjMiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjI2NzQ5IDAgMCAuMjY3OTkgLTEwOTMuNSA3MTMuMTEpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjM2MzYzNjIi8+PHN0b3Agb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGlkPSJiIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuNDk4IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii4zIi8+PGZlT2Zmc2V0IGR4PSIxIiBkeT0iMSIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNhKSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2UtbGluZWNhcD0ic3F1YXJlIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuMSIgZD0iTTI1LjAxOSA0My40NUgxMS41OGMtMi40NjYtNS43MjQgNC4wNzItMTEuMDMgOC42NjgtMTIuODMyLTUuNDkzLTMuMDc0LTIuNTE1LTEwLjkxMSAyLjE5Mi0xMS41NDctMS4xMi0uNzQyLTEuNjgxLTIuMzI3LTEuNjgxLTMuNiAwLTEuMDYuNDQ4LTIuMDEzIDEuMjMzLTIuNzU1Ljc4NS0uNzQyIDEuNzkzLTEuMTY2IDMuMDI2LTEuMTY2IDEuMTIxIDAgMi4xMy40MjQgMy4wMjYgMS4xNjYuNzg1Ljc0MiAxLjIzMyAxLjY5NiAxLjIzMyAyLjc1NiAwIDEuMjcyLS41NiAyLjg1Ny0xLjY4MSAzLjU5OSA1LjE1NiAyLjAxNCA3LjAxMiA5LjQyNyAyLjE5MyAxMS41NDcgNi4yNzYgMi4yMjYgMTAuNjg1IDcuODUgOC42NjcgMTIuODMyeiIgY2xhc3M9InN0MzEiIGZpbHRlcj0idXJsKCNiKSIvPjwvc3ZnPg==')}
-.is2d .knight.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iLTQ1NS4zOSIgeDI9Ii00MTkuNDEiIHkxPSItMzM4LjIzIiB5Mj0iLTMzOC4yMyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAwMDggMCAwIDEuMDAwMSA0NjIuNzUgMzYzLjI2KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzNjM2MzYyIvPjxzdG9wIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PGZpbHRlciBpZD0iYiIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVGbG9vZCBmbG9vZC1jb2xvcj0iIzAwMCIgZmxvb2Qtb3BhY2l0eT0iLjQ5OCIgcmVzdWx0PSJmbG9vZCIvPjxmZUNvbXBvc2l0ZSBpbj0iZmxvb2QiIGluMj0iU291cmNlR3JhcGhpYyIgb3BlcmF0b3I9ImluIiByZXN1bHQ9ImNvbXBvc2l0ZTEiLz48ZmVHYXVzc2lhbkJsdXIgaW49ImNvbXBvc2l0ZTEiIHJlc3VsdD0iYmx1ciIgc3RkRGV2aWF0aW9uPSIuNiIvPjxmZU9mZnNldCBkeD0iMS42IiBkeT0iMS40IiByZXN1bHQ9Im9mZnNldCIvPjxmZUNvbXBvc2l0ZSBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJvZmZzZXQiIHJlc3VsdD0iY29tcG9zaXRlMiIvPjwvZmlsdGVyPjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS13aWR0aD0iMS4xIiBkPSJNMTguNDc0IDMwLjI4NWMyLjEwMy0xLjE5OCAzLjMyNS0xLjE4MyA1LjQ2Ny0yLjIuMjI0IDcuNDI2LTkuOTA5IDcuNDU3LTguMDkzIDE1LjM2MmwyNi40MjYuMDAzUzQ1LjM3MiAxMS4xNzYgMjUuNDggOS44MjRjMCAwLTEuOTE1LTMuNjA1LTMuOTI4LTMuMjUgMCAwLTEuMDY2LjgzOC0uNDU4IDMuMjA3bC0yLjMwNi43NDZzLTMuMjE2LTIuMDcyLTQuMTI3LTEuMjdjLS44NTguMzY5IDEuMSAzLjI4IDEuODc4IDMuOTg2LS43OSAxLjE0Mi04LjU0OSAxMi4xMDktOC45NjcgMTUuNjgyLS4yNjcgMi4yNzcgMi4wMjMgMy41MTggMy43MTkgNC4xMmExMS45MSAxMS45MSAwIDAgMCAxLjczNy40NzZjMS40MjYtLjI1NiAzLjM0NS0yLjAzOCA1LjQ0OC0zLjIzNnoiIGZpbHRlcj0idXJsKCNiKSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuMSIgZD0iTTIzLjk0MSAyOC4wODZzNC40MzMtMS44NjcgNC4yMjQtNS44MzUiLz48cGF0aCBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0xOS4xMDQgMTguNDczcy41OTQtMS44NDYgMy40NTMtMi4yOTQiLz48ZWxsaXBzZSBjeD0iMjEuMDI3IiBjeT0iMTguMDAxIiBmaWxsPSIjZTZlNmU2IiByeD0iMS4yNDIiIHJ5PSIxLjE2OCIgc3R5bGU9InBhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiLz48cGF0aCBmaWxsPSIjZmZmIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik05LjE3IDI5LjI0MXMuMjU0LS42ODIuOTI0LTEuMTE4Ii8+PHBhdGggZmlsbD0iI2ZmZiIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iMS4yIiBkPSJNMTEuNjQgMzIuMjgzYy42OS0uODg3IDEuNTgzLTEuMzE5IDIuMzg0LTEuOTU3Ii8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuNCIgZD0iTTMwLjgwNiAxNC44NzJjNC4zMDUgMi42MzMgOC40NiA5LjI1IDguMTEgMjYuMDgiLz48L3N2Zz4=')}
-.is2d .bishop.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii40OTgiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjMiLz48ZmVPZmZzZXQgZHg9IjEiIGR5PSIxIiByZXN1bHQ9Im9mZnNldCIvPjxmZUNvbXBvc2l0ZSBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJvZmZzZXQiIHJlc3VsdD0iY29tcG9zaXRlMiIvPjwvZmlsdGVyPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjEzMTk3IiB4Mj0iMTMzNDEiIHkxPSItOTU5MS4xIiB5Mj0iLTk1OTEuMSIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtMzQ4NS43IDI1NjIuNikgc2NhbGUoLjI2NDU4KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzNjM2MzYyIvPjxzdG9wIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGZpbGw9InVybCgjYSkiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yNSA2LjU1Yy0uODc4IDAtMS42NTQuMjktMi4yNjEuOTAzLS42NDEuNjEyLS45NDYgMS4zMjEtLjk0NiAyLjE1OSAwIDEuMjI1LjU3NCAyLjEyNyAxLjc1NiAyLjc0LTIuOTcgMy4yODUtOC43MDggNS44MjEtOC44MTEgMTAuODI3LjAxIDIuNjc1IDEuNDY2IDQuNzY0IDMuMzA4IDYuOGwtMS4xMTQgNS44MzNjMS42OTcuNTQyIDMuMDkuOTQyIDQuODI3IDEuMTI4LTMuODgyIDQuNTc2LTEwLjc4Ny0xLjc0LTE1LjIwOSAyLjkzM2wyLjMzIDMuNTc3YzUuNTkzLTMuOTYyIDEzLjM3NSAzLjY3MyAxNi4xMi0zLjk2MiAyLjc0NiA3LjYzNSAxMC41MjggMCAxNi4xMiAzLjk2MmwyLjMzLTMuNTc3Yy00LjQyMi00LjY3My0xMS4zMjcgMS42NDMtMTUuMjA5LTIuOTMzIDEuNzM4LS4xODYgMy4xMy0uNTg2IDQuODI4LTEuMTI4bC0xLjExNS01LjgzM2MxLjg0My0yLjAzNiAzLjMwMi00LjEyNSAzLjMwOS02LjgtLjEwMy01LjAwNi01Ljg0Mi03LjU0Mi04LjgxMS0xMC44MjggMS4xODEtLjYxMiAxLjc1NS0xLjUxNCAxLjc1NS0yLjc0IDAtLjgzNy0uMzA0LTEuNTQ2LS45NDUtMi4xNTgtLjYwOC0uNjEyLTEuMzg0LS45MDMtMi4yNjEtLjkwM3oiIGZpbHRlcj0idXJsKCNiKSIvPjxlbGxpcHNlIGN4PSIyNzIwLjMiIGN5PSItMjcxLjQiIGZpbGw9IiNlNmU2ZTYiIGNsYXNzPSJzdDE1IiBmaWx0ZXI9InVybCgjYykiIHJ4PSIxNi4zIiByeT0iMi41IiB0cmFuc2Zvcm09Im1hdHJpeCguMzMyMzIgMCAwIC4yNDk5OCAtODc5LjAxIDEwMi40NykiLz48ZWxsaXBzZSBjeD0iMjUiIGN5PSI5LjYxMiIgZmlsbD0iI2U2ZTZlNiIgY2xhc3M9InN0MTUiIHJ4PSIxLjE0IiByeT0iMS4xNDciLz48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS13aWR0aD0iMS40IiBkPSJNMjEuMzMzIDIzLjI2Nmg3LjMzM00yNSAxOS45MzJ2Ni43NTIiLz48L3N2Zz4=')}
-.is2d .rook.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iNDUwMS41IiB4Mj0iNDU5NC42IiB5MT0iLTU3Mi40IiB5Mj0iLTU3Mi40IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC4zNDIwOCAwIDAgLjI4MzcgLTE1MzAuOCAxODcuMzkpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjM2MzYzNjIi8+PHN0b3Agb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGlkPSJiIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuNDk4IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii4zIi8+PGZlT2Zmc2V0IGR4PSIxIiBkeT0iMSIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNhKSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2Utd2lkdGg9IjEuMTQ0IiBkPSJNMjEuOTMyIDYuNTQ2VjkuNDhoLTQuMDkxVjYuODkyaC01Ljc5NnY3Ljk3NWw0LjUzMyAzLjE0MnYxMi41NjdsLTMuODUgMi40ODZ2NS4yMTNIOS42NTh2NS4xNzloMzAuNjgydi01LjE4aC0zLjA2OHYtNS4yMTJsLTMuODUtMi40ODZWMTguMDQzbDQuNTMyLTMuMjExdi03Ljk0aC01Ljc5NnYyLjU4N2gtNC40MzJWNi41NDZIMjQuODN6IiBjbGFzcz0ic3QxNCIgZmlsdGVyPSJ1cmwoI2IpIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAwNTUgMCAwIC45MTk4IC0uMiAzLjUpIi8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2Utd2lkdGg9IjEuNCIgZD0iTTE4LjggMzEuNGgxMS45OThNMTguOCAyMGgxMS45OTgiLz48L3N2Zz4=')}
-.is2d .queen.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii40OTgiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjMiLz48ZmVPZmZzZXQgZHg9IjEiIGR5PSIxIiByZXN1bHQ9Im9mZnNldCIvPjxmZUNvbXBvc2l0ZSBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJvZmZzZXQiIHJlc3VsdD0iY29tcG9zaXRlMiIvPjwvZmlsdGVyPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9Ii03MS42MzciIHgyPSItMzAuNjc4IiB5MT0iLTgzLjMyNSIgeTI9Ii04My4zMjUiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjk3NjQ0IDAgMCAuOTkyODYgNzQuOTUyIDEwNy43MykiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiMzYzNjM2MiLz48c3RvcCBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yNC45OTQgNi41NDl2MGMtMS41NjguMDA2LTIuODM1IDEuMTgxLTIuODM2IDIuNjMuMDAyIDEuMTkzLjg3MyAyLjIzNSAyLjEyMiAyLjUzOS0uNjg4IDQuNDUtMS45NjcgOS43MjYtMi42MzQgMTQuMTEybC00LjA3LTEyLjkyN2MuOTY4LS40NDQgMS41OC0xLjM1NiAxLjU4LTIuMzUzIDAtMS40NTMtMS4yNzUtMi42My0yLjg0Ny0yLjYzcy0yLjg0NyAxLjE3Ny0yLjg0NyAyLjYzYy4wMDIgMS4yMDUuODkgMi4yNTUgMi4xNTcgMi41NDdsLS40NCAxMy4yNTgtNS40ODItMTAuNjExYy45NTEtLjQ1IDEuNTUtMS4zNTQgMS41NS0yLjM0IDAtMS40NTMtMS4yNzUtMi42My0yLjg0Ny0yLjYzLTEuNTczIDAtMi44NDcgMS4xNzctMi44NDcgMi42MyAwIDEuMzM0IDEuMDg0IDIuNDU2IDIuNTE5IDIuNjFsMi43NiAxNi41MDcgNC4wNSA1LjI1OC0xLjAwNCAzLjYzNGMtLjA0Mi42NTYgNC44NDggMi4wMjggMTEuMTIyIDIuMDQgNi4yNzMtLjAxMiAxMS4xNjQtMS4zODQgMTEuMTIyLTIuMDRsLTEuMDA1LTMuNjM0IDQuMDUtNS4yNTggMi43Ni0xNi41MDdjMS40MzUtLjE1NCAyLjUxOS0xLjI3NiAyLjUyLTIuNjEgMC0xLjQ1My0xLjI3NS0yLjYzLTIuODQ3LTIuNjMtMS41NzMgMC0yLjg0NyAxLjE3Ny0yLjg0NyAyLjYzIDAgLjk4Ni41OTggMS44OSAxLjU1IDIuMzRsLTUuNDg0IDEwLjYxLS40MzktMTMuMjU3YzEuMjY2LS4yOTIgMi4xNTUtMS4zNDIgMi4xNTctMi41NDcgMC0xLjQ1My0xLjI3NS0yLjYzLTIuODQ3LTIuNjNzLTIuODQ3IDEuMTc3LTIuODQ3IDIuNjNjMCAuOTk3LjYxMiAxLjkwOSAxLjU4IDIuMzUzbC00LjA3IDEyLjkyN2MtLjY2Ny00LjM4Ni0xLjk0Ni05LjY2Mi0yLjYzNC0xNC4xMTIgMS4yNDktLjMwNCAyLjEyLTEuMzQ2IDIuMTIyLTIuNTQgMC0xLjQ0OC0xLjI2OC0yLjYyMy0yLjgzNi0yLjYyOXYwaC0uMDExeiIgZmlsdGVyPSJ1cmwoI2IpIiBzdHlsZT0icGFpbnQtb3JkZXI6bm9ybWFsIi8+PGVsbGlwc2UgY3g9IjQ3MDguNyIgY3k9Ii0yNTE3LjYiIGZpbGw9IiNlNmU2ZTYiIGNsYXNzPSJzdDE1IiBmaWx0ZXI9InVybCgjYykiIHJ4PSIzMi4xMjYiIHJ5PSIyLjg0NCIgdHJhbnNmb3JtPSJtYXRyaXgoLjI1OTM5IDAgMCAuMjkyOTggLTExOTYuNCA3NzguMTIpIi8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIGQ9Ik0xNS4xNzIgMzQuMDc2czIuNy0xLjI0OSA5LjgwMi0xLjI1NmM3LjEwMy0uMDEgOS44MDEgMS4yNTYgOS44MDEgMS4yNTYiIHN0eWxlPSJwYWludC1vcmRlcjpzdHJva2UgZmlsbCBtYXJrZXJzIi8+PC9zdmc+')}
-.is2d .king.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MG1tIiBoZWlnaHQ9IjUwbW0iIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii40OTgiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjYiLz48ZmVPZmZzZXQgZHg9IjEuNiIgZHk9IjEuNCIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgxPSIyOTg2LjQiIHgyPSIzMTI4LjQiIHkxPSIxNjIzLjgiIHkyPSIxNjIzLjgiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjI3MTQxIDAgMCAuMjcyMTggLTgwNC44MSAtNDE3LjQ1KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzNjM2MzYyIvPjxzdG9wIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGZpbGw9InVybCgjYSkiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yMy4yODMgNS41NXYzLjIzOGgtMy4zNjR2Mi45MmgzLjM2NHYxLjc1OGMtMy4zNjggMi4xMjctMi45OTYgNS43NC0yLjk5NiA1Ljc0QzkuMjc4IDEwLjY5LS4zODUgMjYuNzcgMTIuMzQzIDMyLjI2djguNzM0YzAgLjk1IDUuNjY3IDIuNDU2IDEyLjY1NyAyLjQ1NnMxMi42NTctMS41MDYgMTIuNjU3LTIuNDU2VjMyLjI2YzEyLjcyOC01LjQ5IDMuMDY2LTIxLjU2OS03Ljk0My0xMy4wNTMgMCAwIC4zNzItMy42MTMtMi45OTYtNS43NHYtMS43NThoMy4zNjR2LTIuOTJoLTMuMzY0VjUuNTUxaC0xLjcxN3oiIGZpbHRlcj0idXJsKCNiKSIvPjxlbGxpcHNlIGN4PSI3MS4wNzciIGN5PSIxMzEuNTQiIGZpbGw9IiNlNmU2ZTYiIGNsYXNzPSJzdDE1IiBmaWx0ZXI9InVybCgjYykiIHJ4PSIzMi4xMjYiIHJ5PSIyLjg0NCIgdHJhbnNmb3JtPSJtYXRyaXgoLjI4NTMzIDAgMCAuMzIyMyA0LjcyIC0xLjk4KSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0yNy4wMzIgMzAuMjY3YzEuNDktMTIuMTAyIDExLjk0My0xMi40NDEgMTMuMzY0LTcuMzggMS40MiA1LjA2Mi00LjczNiA3LjM4LTQuNzM2IDcuMzhzLTQuODc1LS42MzgtMTAuNjYtLjYzOC0xMC42Ni42MzgtMTAuNjYuNjM4LTYuMTU2LTIuMzE4LTQuNzM1LTcuMzggMTEuODc0LTQuNzIyIDEzLjM2NCA3LjM4Ii8+PC9zdmc+')}
+.is2d .pawn.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iNDEyNy4zIiB4Mj0iNDIzNS43IiB5MT0iLTI1NTguNCIgeTI9Ii0yNTU4LjQiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjI3Njc3IDAgMCAuMjc1NTUgLTExMzIuMyA3MzEuOTYpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZTZlNmU2Ii8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGlkPSJiIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuNSIgcmVzdWx0PSJmbG9vZCIvPjxmZUNvbXBvc2l0ZSBpbj0iZmxvb2QiIGluMj0iU291cmNlR3JhcGhpYyIgb3BlcmF0b3I9ImluIiByZXN1bHQ9ImNvbXBvc2l0ZTEiLz48ZmVHYXVzc2lhbkJsdXIgaW49ImNvbXBvc2l0ZTEiIHJlc3VsdD0iYmx1ciIgc3RkRGV2aWF0aW9uPSIuMyIvPjxmZU9mZnNldCBkeD0iMSIgZHk9IjEiIHJlc3VsdD0ib2Zmc2V0Ii8+PGZlQ29tcG9zaXRlIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9Im9mZnNldCIgcmVzdWx0PSJjb21wb3NpdGUyIi8+PC9maWx0ZXI+PC9kZWZzPjxwYXRoIGZpbGw9InVybCgjYSkiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjE0IiBkPSJNMjUuMDIgNDMuNGgtMTMuOWMtMi41NS01Ljg4IDQuMjEtMTEuMzQgOC45Ny0xMy4yLTUuNjktMy4xNS0yLjYtMTEuMjEgMi4yNy0xMS44Ny0xLjE2LS43Ni0xLjc0LTIuMzktMS43NC0zLjcgMC0xLjA5LjQ2LTIuMDcgMS4yNy0yLjgzYTQuNDMgNC40MyAwIDAgMSAzLjEzLTEuMmMxLjE2IDAgMi4yLjQ0IDMuMTQgMS4yYTMuODQgMy44NCAwIDAgMSAxLjI3IDIuODNjMCAxLjMxLS41OCAyLjk0LTEuNzQgMy43IDUuMzQgMi4wNyA3LjI2IDkuNyAyLjI3IDExLjg4IDYuNSAyLjI5IDExLjA2IDguMDcgOC45NyAxMy4yeiIgY2xhc3M9InN0MzEiIGZpbHRlcj0idXJsKCNiKSIgdHJhbnNmb3JtPSJtYXRyaXgoLjk2NjU4IDAgMCAuOTcyNDUgLjgzIDEuMjQpIi8+PC9zdmc+')}
+.is2d .knight.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iLTQ1NS4zOSIgeDI9Ii00MTkuNDEiIHkxPSItMzM4LjIzIiB5Mj0iLTMzOC4yMyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ZjZmNmOCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2U3ZTdlMyIvPjwvbGluZWFyR3JhZGllbnQ+PGZpbHRlciBpZD0iYiIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVGbG9vZCBmbG9vZC1jb2xvcj0iIzAwMCIgZmxvb2Qtb3BhY2l0eT0iLjUiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjYiLz48ZmVPZmZzZXQgZHg9IjEuNiIgZHk9IjEuNCIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNhKSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuMSIgZD0iTS00NDMuOTItMzMyLjk1YzIuMS0xLjIgMy4zMi0xLjE4IDUuNDYtMi4yLjIzIDcuNDMtOS45IDcuNDYtOC4wOCAxNS4zNmgyNi40czMuMS0zMi4yNy0xNi43OC0zMy42MmMwIDAtMS45MS0zLjYtMy45My0zLjI1IDAgMC0xLjA2Ljg0LS40NSAzLjJsLTIuMy43NXMtMy4yMi0yLjA3LTQuMTMtMS4yN2MtLjg2LjM3IDEuMSAzLjI4IDEuODggMy45OS0uOCAxLjE0LTguNTUgMTIuMS04Ljk2IDE1LjY4LS4yNyAyLjI4IDIuMDIgMy41MiAzLjcxIDQuMTIuOTcuMzQgMS43NC40NyAxLjc0LjQ3IDEuNDItLjI1IDMuMzQtMi4wMyA1LjQ0LTMuMjN6IiBmaWx0ZXI9InVybCgjYikiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDAwOCAwIDAgMS4wMDAxIDQ2Mi43NSAzNjMuMjYpIi8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iMS4xIiBkPSJNMjMuOTQgMjguMDlzNC40My0xLjg3IDQuMjItNS44NCIvPjxwYXRoIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuNCIgZD0iTTE5LjEgMTguNDdzLjYtMS44NCAzLjQ2LTIuMyIvPjxlbGxpcHNlIGN4PSIyMS4wMyIgY3k9IjE4IiBwYWludC1vcmRlcj0ibWFya2VycyBmaWxsIHN0cm9rZSIgcng9IjEuMjQiIHJ5PSIxLjE3Ii8+PHBhdGggZmlsbD0iI2ZmZiIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iMS40IiBkPSJNOS4xNyAyOS4yNHMuMjUtLjY4LjkyLTEuMTIiLz48cGF0aCBmaWxsPSIjZmZmIiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjIiIGQ9Ik0xMS42NCAzMi4yOGMuNjktLjg4IDEuNTgtMS4zMiAyLjM4LTEuOTUiLz48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMS40IiBkPSJNMzAuOCAxNC44N2M0LjMxIDIuNjQgOC40NyA5LjI1IDguMTIgMjYuMDgiLz48L3N2Zz4=')}
+.is2d .bishop.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii41IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii4zIi8+PGZlT2Zmc2V0IGR4PSIxIiBkeT0iMSIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgxPSIxMzE5NyIgeDI9IjEzMzQxIiB5MT0iLTk1OTEiIHkyPSItOTU5MSIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtMzQ4NS43IDI1NjIuNikgc2NhbGUoLjI2NDU4KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ZmZiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2U2ZTZlNiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGZpbGw9InVybCgjYSkiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yNSA2LjU1Yy0uODggMC0xLjY1LjI5LTIuMjYuOWEyLjg2IDIuODYgMCAwIDAtLjk1IDIuMTZjMCAxLjIzLjU4IDIuMTMgMS43NiAyLjc0LTIuOTcgMy4yOS04LjcgNS44Mi04LjgxIDEwLjgzIDAgMi42NyAxLjQ2IDQuNzYgMy4zIDYuOGwtMS4xIDUuODNjMS42OS41NCAzLjA4Ljk0IDQuODIgMS4xMy0zLjg4IDQuNTgtMTAuNzktMS43NC0xNS4yMSAyLjkzbDIuMzMgMy41OGM1LjYtMy45NiAxMy4zOCAzLjY3IDE2LjEyLTMuOTYgMi43NSA3LjYzIDEwLjUzIDAgMTYuMTIgMy45NmwyLjMzLTMuNThjLTQuNDItNC42Ny0xMS4zMyAxLjY1LTE1LjItMi45M2EyMy4xIDIzLjEgMCAwIDAgNC44Mi0xLjEzbC0xLjEyLTUuODNjMS44NS0yLjA0IDMuMy00LjEzIDMuMzEtNi44LS4xLTUtNS44NC03LjU0LTguOC0xMC44MyAxLjE3LS42MSAxLjc1LTEuNTEgMS43NS0yLjc0IDAtLjg0LS4zLTEuNTUtLjk1LTIuMTYtLjYtLjYxLTEuMzgtLjktMi4yNi0uOXoiIGZpbHRlcj0idXJsKCNiKSIvPjxlbGxpcHNlIGN4PSIyNzIwLjMiIGN5PSItMjcxLjQiIGNsYXNzPSJzdDE1IiBmaWx0ZXI9InVybCgjYykiIHJ4PSIxNi4zIiByeT0iMi41IiB0cmFuc2Zvcm09Im1hdHJpeCguMzMyMzIgMCAwIC4yNDk5OCAtODc5LjAxIDEwMi40NykiLz48ZWxsaXBzZSBjeD0iMjUiIGN5PSI5LjYxIiBjbGFzcz0ic3QxNSIgcng9IjEuMTQiIHJ5PSIxLjE1Ii8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNCIgZD0iTTIxLjMzIDIzLjI3aDcuMzRNMjUgMTkuOTN2Ni43NSIvPjwvc3ZnPg==')}
+.is2d .rook.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iNDUwMS41IiB4Mj0iNDU5NC42IiB5MT0iLTU3Mi40IiB5Mj0iLTU3Mi40IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC4zNDIwOCAwIDAgLjI4MzcgLTE1MzAuOCAxODcuMzkpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZTZlNmU2Ii8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGlkPSJiIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuNSIgcmVzdWx0PSJmbG9vZCIvPjxmZUNvbXBvc2l0ZSBpbj0iZmxvb2QiIGluMj0iU291cmNlR3JhcGhpYyIgb3BlcmF0b3I9ImluIiByZXN1bHQ9ImNvbXBvc2l0ZTEiLz48ZmVHYXVzc2lhbkJsdXIgaW49ImNvbXBvc2l0ZTEiIHJlc3VsdD0iYmx1ciIgc3RkRGV2aWF0aW9uPSIuMyIvPjxmZU9mZnNldCBkeD0iMSIgZHk9IjEiIHJlc3VsdD0ib2Zmc2V0Ii8+PGZlQ29tcG9zaXRlIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9Im9mZnNldCIgcmVzdWx0PSJjb21wb3NpdGUyIi8+PC9maWx0ZXI+PC9kZWZzPjxwYXRoIGZpbGw9InVybCgjYSkiIHN0cm9rZT0iIzAxMDEwMSIgc3Ryb2tlLXdpZHRoPSIxLjE0IiBkPSJNMjEuOTMgNi41NXYyLjkzaC00LjA5VjYuODloLTUuOHY3Ljk4TDE2LjU4IDE4djEyLjU3bC0zLjg1IDIuNDh2NS4yMUg5LjY2djUuMThoMzAuNjh2LTUuMThoLTMuMDd2LTUuMmwtMy44NS0yLjVWMTguMDVsNC41My0zLjJWNi44OGgtNS44djIuNTloLTQuNDJWNi41NWgtMi45eiIgY2xhc3M9InN0MTQiIGZpbHRlcj0idXJsKCNiKSIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDU1IDAgMCAuOTE5OCAtLjE0IDMuNSkiLz48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS40IiBkPSJNMTguODMgMzEuNDRoMTJNMTguODMgMjBoMTIiLz48L3N2Zz4=')}
+.is2d .queen.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii41IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii4zIi8+PGZlT2Zmc2V0IGR4PSIxIiBkeT0iMSIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgxPSItNzEuNjQiIHgyPSItMzAuNjgiIHkxPSItODMuMzIiIHkyPSItODMuMzIiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjk3NjQzIDAgMCAuOTkyODcgNzQuOTUgMTA3LjczKSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ZmZiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2U2ZTZlNiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGZpbGw9InVybCgjYSkiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuMSIgZD0iTTI1IDYuNTV2MGMtMS41NyAwLTIuODQgMS4xOC0yLjg0IDIuNjMgMCAxLjIuODcgMi4yMyAyLjEyIDIuNTQtLjY5IDQuNDUtMS45NyA5LjcyLTIuNjMgMTQuMTFMMTcuNTggMTIuOWEyLjYyIDIuNjIgMCAwIDAgMS41OC0yLjM1YzAtMS40NS0xLjI4LTIuNjMtMi44NS0yLjYzcy0yLjg1IDEuMTgtMi44NSAyLjYzYzAgMS4yLjkgMi4yNSAyLjE2IDIuNTVsLS40NCAxMy4yNS01LjQ4LTEwLjZhMi42MiAyLjYyIDAgMCAwIDEuNTUtMi4zNWMwLTEuNDUtMS4yOC0yLjYzLTIuODUtMi42M3MtMi44NSAxLjE4LTIuODUgMi42M2MwIDEuMzQgMS4wOSAyLjQ2IDIuNTIgMi42MWwyLjc2IDE2LjUxIDQuMDUgNS4yNi0xIDMuNjNjLS4wNC42NiA0Ljg1IDIuMDMgMTEuMTIgMi4wNCA2LjI3LS4wMSAxMS4xNi0xLjM4IDExLjEyLTIuMDRsLTEtMy42MyA0LjA1LTUuMjYgMi43Ni0xNi41YTIuNzQgMi43NCAwIDAgMCAyLjUyLTIuNjJjMC0xLjQ1LTEuMjgtMi42My0yLjg1LTIuNjNzLTIuODUgMS4xOC0yLjg1IDIuNjNjMCAuOTkuNiAxLjkgMS41NSAyLjM0bC01LjQ4IDEwLjYxLS40NC0xMy4yNWEyLjY4IDIuNjggMCAwIDAgMi4xNi0yLjU1YzAtMS40NS0xLjI4LTIuNjMtMi44NS0yLjYzcy0yLjg1IDEuMTgtMi44NSAyLjYzYzAgMSAuNjEgMS45IDEuNTggMi4zNWwtNC4wNyAxMi45M2MtLjY3LTQuMzktMS45NC05LjY2LTIuNjMtMTQuMTFhMi42OCAyLjY4IDAgMCAwIDIuMTItMi41NGMwLTEuNDUtMS4yNy0yLjYzLTIuODQtMi42M3YwaDB6IiBmaWx0ZXI9InVybCgjYikiLz48ZWxsaXBzZSBjeD0iNDcwOC43IiBjeT0iLTI1MTcuNiIgY2xhc3M9InN0MTUiIGZpbHRlcj0idXJsKCNjKSIgcng9IjMyLjEzIiByeT0iMi44NCIgdHJhbnNmb3JtPSJtYXRyaXgoLjI1OTM5IDAgMCAuMjkyOTggLTExOTYuNCA3NzguMTIpIi8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIGQ9Ik0xNS4xNyAzNC4wOHMyLjctMS4yNSA5LjgtMS4yNmM3LjEtLjAxIDkuOCAxLjI2IDkuOCAxLjI2IiBwYWludC1vcmRlcj0ic3Ryb2tlIGZpbGwgbWFya2VycyIvPjwvc3ZnPg==')}
+.is2d .king.white {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii41IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii42Ii8+PGZlT2Zmc2V0IGR4PSIxLjYiIGR5PSIxLjQiIHJlc3VsdD0ib2Zmc2V0Ii8+PGZlQ29tcG9zaXRlIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9Im9mZnNldCIgcmVzdWx0PSJjb21wb3NpdGUyIi8+PC9maWx0ZXI+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iMjk4Ni40IiB4Mj0iMzEyOC40IiB5MT0iMTYyMy44IiB5Mj0iMTYyMy44IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC4yNzE0MSAwIDAgLjI3MjE4IC04MDQuODEgLTQxNy40NSkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNmZmYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNlNmU2ZTYiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS4xIiBkPSJNMjMuMjggNS41NXYzLjI0aC0zLjM2djIuOTJoMy4zNnYxLjc2Yy0zLjM2IDIuMTItMyA1Ljc0LTMgNS43NC0xMS04LjUyLTIwLjY3IDcuNTYtNy45NCAxMy4wNXY4LjczYzAgLjk1IDUuNjcgMi40NiAxMi42NiAyLjQ2czEyLjY2LTEuNSAxMi42Ni0yLjQ2di04LjczYzEyLjcyLTUuNDkgMy4wNi0yMS41Ny03Ljk1LTEzLjA1IDAgMCAuMzgtMy42Mi0zLTUuNzRWMTEuN2gzLjM3VjguNzloLTMuMzZWNS41NUgyNXoiIGZpbHRlcj0idXJsKCNiKSIvPjxlbGxpcHNlIGN4PSI3MS4wOCIgY3k9IjEzMS41NCIgY2xhc3M9InN0MTUiIGZpbHRlcj0idXJsKCNjKSIgcng9IjMyLjEzIiByeT0iMi44NCIgdHJhbnNmb3JtPSJtYXRyaXgoLjI4NTMzIDAgMCAuMzIyMyA0LjcyIC0xLjk4KSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0yNy4wMyAzMC4yN2MxLjUtMTIuMSAxMS45NC0xMi40NCAxMy4zNy03LjM4IDEuNDIgNS4wNi00Ljc0IDcuMzgtNC43NCA3LjM4cy00Ljg3LS42NC0xMC42Ni0uNjQtMTAuNjYuNjQtMTAuNjYuNjQtNi4xNi0yLjMyLTQuNzMtNy4zOCAxMS44Ny00LjczIDEzLjM2IDcuMzgiLz48L3N2Zz4=')}
+.is2d .pawn.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iNDEyNy4yIiB4Mj0iNDIzNS43IiB5MT0iLTI1NTguMyIgeTI9Ii0yNTU4LjMiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjI2NzQ5IDAgMCAuMjY3OTkgLTEwOTMuNSA3MTMuMTEpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjM2MzYzNjIi8+PHN0b3Agb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGlkPSJiIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuNDk4IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii4zIi8+PGZlT2Zmc2V0IGR4PSIxIiBkeT0iMSIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNhKSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2UtbGluZWNhcD0ic3F1YXJlIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuMSIgZD0iTTI1LjAxOSA0My40NUgxMS41OGMtMi40NjYtNS43MjQgNC4wNzItMTEuMDMgOC42NjgtMTIuODMyLTUuNDkzLTMuMDc0LTIuNTE1LTEwLjkxMSAyLjE5Mi0xMS41NDctMS4xMi0uNzQyLTEuNjgxLTIuMzI3LTEuNjgxLTMuNiAwLTEuMDYuNDQ4LTIuMDEzIDEuMjMzLTIuNzU1Ljc4NS0uNzQyIDEuNzkzLTEuMTY2IDMuMDI2LTEuMTY2IDEuMTIxIDAgMi4xMy40MjQgMy4wMjYgMS4xNjYuNzg1Ljc0MiAxLjIzMyAxLjY5NiAxLjIzMyAyLjc1NiAwIDEuMjcyLS41NiAyLjg1Ny0xLjY4MSAzLjU5OSA1LjE1NiAyLjAxNCA3LjAxMiA5LjQyNyAyLjE5MyAxMS41NDcgNi4yNzYgMi4yMjYgMTAuNjg1IDcuODUgOC42NjcgMTIuODMyeiIgY2xhc3M9InN0MzEiIGZpbHRlcj0idXJsKCNiKSIvPjwvc3ZnPg==')}
+.is2d .knight.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iLTQ1NS4zOSIgeDI9Ii00MTkuNDEiIHkxPSItMzM4LjIzIiB5Mj0iLTMzOC4yMyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAwMDggMCAwIDEuMDAwMSA0NjIuNzUgMzYzLjI2KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzNjM2MzYyIvPjxzdG9wIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PGZpbHRlciBpZD0iYiIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVGbG9vZCBmbG9vZC1jb2xvcj0iIzAwMCIgZmxvb2Qtb3BhY2l0eT0iLjUiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjYiLz48ZmVPZmZzZXQgZHg9IjEuNiIgZHk9IjEuNCIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNhKSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2Utd2lkdGg9IjEuMSIgZD0iTTE4LjQ3IDMwLjI5YzIuMS0xLjIgMy4zMy0xLjE5IDUuNDctMi4yLjIyIDcuNDItOS45IDcuNDUtOC4xIDE1LjM2aDI2LjQzczMuMS0zMi4yNy0xNi43OS0zMy42M2MwIDAtMS45Mi0zLjYtMy45My0zLjI1IDAgMC0xLjA2Ljg0LS40NiAzLjIxbC0yLjMuNzVzLTMuMjItMi4wOC00LjEzLTEuMjdjLS44Ni4zNyAxLjEgMy4yOCAxLjg4IDMuOTgtLjggMS4xNS04LjU1IDEyLjExLTguOTcgMTUuNjktLjI2IDIuMjcgMi4wMyAzLjUxIDMuNzIgNC4xMmExMS45MSAxMS45MSAwIDAgMCAxLjc0LjQ3YzEuNDItLjI2IDMuMzQtMi4wNCA1LjQ1LTMuMjR6IiBmaWx0ZXI9InVybCgjYikiLz48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yMy45NCAyOC4wOXM0LjQzLTEuODcgNC4yMi01Ljg0Ii8+PHBhdGggc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iMS40IiBkPSJNMTkuMSAxOC40N3MuNi0xLjg0IDMuNDYtMi4zIi8+PGVsbGlwc2UgY3g9IjIxLjAzIiBjeT0iMTgiIGZpbGw9IiNlNmU2ZTYiIHBhaW50LW9yZGVyPSJtYXJrZXJzIGZpbGwgc3Ryb2tlIiByeD0iMS4yNCIgcnk9IjEuMTciLz48cGF0aCBmaWxsPSIjZmZmIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik05LjE3IDI5LjI0cy4yNS0uNjguOTItMS4xMiIvPjxwYXRoIGZpbGw9IiNmZmYiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjEuMiIgZD0iTTExLjY0IDMyLjI4Yy42OS0uODggMS41OC0xLjMyIDIuMzgtMS45NSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0zMC44IDE0Ljg3YzQuMzEgMi42NCA4LjQ3IDkuMjUgOC4xMiAyNi4wOCIvPjwvc3ZnPg==')}
+.is2d .bishop.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii41IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii4zIi8+PGZlT2Zmc2V0IGR4PSIxIiBkeT0iMSIgcmVzdWx0PSJvZmZzZXQiLz48ZmVDb21wb3NpdGUgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0ib2Zmc2V0IiByZXN1bHQ9ImNvbXBvc2l0ZTIiLz48L2ZpbHRlcj48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgxPSIxMzE5NyIgeDI9IjEzMzQxIiB5MT0iLTk1OTEuMSIgeTI9Ii05NTkxLjEiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM0ODUuNyAyNTYyLjYpIHNjYWxlKC4yNjQ1OCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiMzYzNjM2MiLz48c3RvcCBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMS4xIiBkPSJNMjUgNi41NWMtLjg4IDAtMS42NS4yOS0yLjI2LjlhMi44NiAyLjg2IDAgMCAwLS45NSAyLjE2YzAgMS4yMy41OCAyLjEzIDEuNzYgMi43NC0yLjk3IDMuMjktOC43IDUuODItOC44MSAxMC44MyAwIDIuNjcgMS40NiA0Ljc2IDMuMyA2LjhsLTEuMSA1LjgzYzEuNjkuNTQgMy4wOC45NCA0LjgyIDEuMTMtMy44OCA0LjU4LTEwLjc5LTEuNzQtMTUuMjEgMi45M2wyLjMzIDMuNThjNS42LTMuOTYgMTMuMzggMy42NyAxNi4xMi0zLjk2IDIuNzUgNy42MyAxMC41MyAwIDE2LjEyIDMuOTZsMi4zMy0zLjU4Yy00LjQyLTQuNjctMTEuMzMgMS42NS0xNS4yLTIuOTNhMjMuMSAyMy4xIDAgMCAwIDQuODItMS4xM2wtMS4xMi01LjgzYzEuODUtMi4wNCAzLjMtNC4xMyAzLjMxLTYuOC0uMS01LTUuODQtNy41NC04LjgtMTAuODMgMS4xNy0uNjEgMS43NS0xLjUxIDEuNzUtMi43NCAwLS44NC0uMy0xLjU1LS45NS0yLjE2YTMuMSAzLjEgMCAwIDAtMi4yNi0uOXoiIGZpbHRlcj0idXJsKCNiKSIvPjxlbGxpcHNlIGN4PSIyNzIwLjMiIGN5PSItMjcxLjQiIGZpbGw9IiNlNmU2ZTYiIGNsYXNzPSJzdDE1IiBmaWx0ZXI9InVybCgjYykiIHJ4PSIxNi4zIiByeT0iMi41IiB0cmFuc2Zvcm09Im1hdHJpeCguMzMyMzIgMCAwIC4yNDk5OCAtODc5LjAxIDEwMi40NykiLz48ZWxsaXBzZSBjeD0iMjUiIGN5PSI5LjYxIiBmaWxsPSIjZTZlNmU2IiBjbGFzcz0ic3QxNSIgcng9IjEuMTQiIHJ5PSIxLjE1Ii8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2Utd2lkdGg9IjEuNCIgZD0iTTIxLjMzIDIzLjI3aDcuMzRNMjUgMTkuOTN2Ni43NSIvPjwvc3ZnPg==')}
+.is2d .rook.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iNDUwMS41IiB4Mj0iNDU5NC42IiB5MT0iLTU3Mi40IiB5Mj0iLTU3Mi40IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC4zNDIwOCAwIDAgLjI4MzcgLTE1MzAuOCAxODcuMzkpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjM2MzYzNjIi8+PHN0b3Agb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGlkPSJiIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLWNvbG9yPSIjMDAwIiBmbG9vZC1vcGFjaXR5PSIuNSIgcmVzdWx0PSJmbG9vZCIvPjxmZUNvbXBvc2l0ZSBpbj0iZmxvb2QiIGluMj0iU291cmNlR3JhcGhpYyIgb3BlcmF0b3I9ImluIiByZXN1bHQ9ImNvbXBvc2l0ZTEiLz48ZmVHYXVzc2lhbkJsdXIgaW49ImNvbXBvc2l0ZTEiIHJlc3VsdD0iYmx1ciIgc3RkRGV2aWF0aW9uPSIuMyIvPjxmZU9mZnNldCBkeD0iMSIgZHk9IjEiIHJlc3VsdD0ib2Zmc2V0Ii8+PGZlQ29tcG9zaXRlIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9Im9mZnNldCIgcmVzdWx0PSJjb21wb3NpdGUyIi8+PC9maWx0ZXI+PC9kZWZzPjxwYXRoIGZpbGw9InVybCgjYSkiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLXdpZHRoPSIxLjE0IiBkPSJNMjEuOTMgNi41NXYyLjkzaC00LjA5VjYuODloLTUuOHY3Ljk4TDE2LjU4IDE4djEyLjU3bC0zLjg1IDIuNDh2NS4yMUg5LjY2djUuMThoMzAuNjh2LTUuMThoLTMuMDd2LTUuMmwtMy44NS0yLjVWMTguMDVsNC41My0zLjJWNi44OGgtNS44djIuNTloLTQuNDJWNi41NWgtMi45eiIgY2xhc3M9InN0MTQiIGZpbHRlcj0idXJsKCNiKSIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDU1IDAgMCAuOTE5OCAtLjIgMy41KSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0xOC44IDMxLjRoMTJNMTguOCAyMGgxMiIvPjwvc3ZnPg==')}
+.is2d .queen.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii40OTgiIHJlc3VsdD0iZmxvb2QiLz48ZmVDb21wb3NpdGUgaW49ImZsb29kIiBpbjI9IlNvdXJjZUdyYXBoaWMiIG9wZXJhdG9yPSJpbiIgcmVzdWx0PSJjb21wb3NpdGUxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJjb21wb3NpdGUxIiByZXN1bHQ9ImJsdXIiIHN0ZERldmlhdGlvbj0iLjMiLz48ZmVPZmZzZXQgZHg9IjEiIGR5PSIxIiByZXN1bHQ9Im9mZnNldCIvPjxmZUNvbXBvc2l0ZSBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJvZmZzZXQiIHJlc3VsdD0iY29tcG9zaXRlMiIvPjwvZmlsdGVyPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9Ii03MS42MzciIHgyPSItMzAuNjc4IiB5MT0iLTgzLjMyNSIgeTI9Ii04My4zMjUiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLjk3NjQ0IDAgMCAuOTkyODYgNzQuOTUyIDEwNy43MykiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiMzYzNjM2MiLz48c3RvcCBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjEiIGQ9Ik0yNC45OTQgNi41NDl2MGMtMS41NjguMDA2LTIuODM1IDEuMTgxLTIuODM2IDIuNjMuMDAyIDEuMTkzLjg3MyAyLjIzNSAyLjEyMiAyLjUzOS0uNjg4IDQuNDUtMS45NjcgOS43MjYtMi42MzQgMTQuMTEybC00LjA3LTEyLjkyN2MuOTY4LS40NDQgMS41OC0xLjM1NiAxLjU4LTIuMzUzIDAtMS40NTMtMS4yNzUtMi42My0yLjg0Ny0yLjYzcy0yLjg0NyAxLjE3Ny0yLjg0NyAyLjYzYy4wMDIgMS4yMDUuODkgMi4yNTUgMi4xNTcgMi41NDdsLS40NCAxMy4yNTgtNS40ODItMTAuNjExYy45NTEtLjQ1IDEuNTUtMS4zNTQgMS41NS0yLjM0IDAtMS40NTMtMS4yNzUtMi42My0yLjg0Ny0yLjYzLTEuNTczIDAtMi44NDcgMS4xNzctMi44NDcgMi42MyAwIDEuMzM0IDEuMDg0IDIuNDU2IDIuNTE5IDIuNjFsMi43NiAxNi41MDcgNC4wNSA1LjI1OC0xLjAwNCAzLjYzNGMtLjA0Mi42NTYgNC44NDggMi4wMjggMTEuMTIyIDIuMDQgNi4yNzMtLjAxMiAxMS4xNjQtMS4zODQgMTEuMTIyLTIuMDRsLTEuMDA1LTMuNjM0IDQuMDUtNS4yNTggMi43Ni0xNi41MDdjMS40MzUtLjE1NCAyLjUxOS0xLjI3NiAyLjUyLTIuNjEgMC0xLjQ1My0xLjI3NS0yLjYzLTIuODQ3LTIuNjMtMS41NzMgMC0yLjg0NyAxLjE3Ny0yLjg0NyAyLjYzIDAgLjk4Ni41OTggMS44OSAxLjU1IDIuMzRsLTUuNDg0IDEwLjYxLS40MzktMTMuMjU3YzEuMjY2LS4yOTIgMi4xNTUtMS4zNDIgMi4xNTctMi41NDcgMC0xLjQ1My0xLjI3NS0yLjYzLTIuODQ3LTIuNjNzLTIuODQ3IDEuMTc3LTIuODQ3IDIuNjNjMCAuOTk3LjYxMiAxLjkwOSAxLjU4IDIuMzUzbC00LjA3IDEyLjkyN2MtLjY2Ny00LjM4Ni0xLjk0Ni05LjY2Mi0yLjYzNC0xNC4xMTIgMS4yNDktLjMwNCAyLjEyLTEuMzQ2IDIuMTIyLTIuNTQgMC0xLjQ0OC0xLjI2OC0yLjYyMy0yLjgzNi0yLjYyOXYwaC0uMDExeiIgZmlsdGVyPSJ1cmwoI2IpIi8+PGVsbGlwc2UgY3g9IjQ3MDguNyIgY3k9Ii0yNTE3LjYiIGZpbGw9IiNlNmU2ZTYiIGNsYXNzPSJzdDE1IiBmaWx0ZXI9InVybCgjYykiIHJ4PSIzMi4xMjYiIHJ5PSIyLjg0NCIgdHJhbnNmb3JtPSJtYXRyaXgoLjI1OTM5IDAgMCAuMjkyOTggLTExOTYuNCA3NzguMTIpIi8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTZlNmU2IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIGQ9Ik0xNS4xNzIgMzQuMDc2czIuNy0xLjI0OSA5LjgwMi0xLjI1NmM3LjEwMy0uMDEgOS44MDEgMS4yNTYgOS44MDEgMS4yNTYiIHBhaW50LW9yZGVyPSJzdHJva2UgZmlsbCBtYXJrZXJzIi8+PC9zdmc+')}
+.is2d .king.black {background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PGZpbHRlciBpZD0iYyIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249IjAuMDEgMC4wMSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImIiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+PGZlRmxvb2QgZmxvb2QtY29sb3I9IiMwMDAiIGZsb29kLW9wYWNpdHk9Ii41IiByZXN1bHQ9ImZsb29kIi8+PGZlQ29tcG9zaXRlIGluPSJmbG9vZCIgaW4yPSJTb3VyY2VHcmFwaGljIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iY29tcG9zaXRlMSIvPjxmZUdhdXNzaWFuQmx1ciBpbj0iY29tcG9zaXRlMSIgcmVzdWx0PSJibHVyIiBzdGREZXZpYXRpb249Ii42Ii8+PGZlT2Zmc2V0IGR4PSIxLjYiIGR5PSIxLjQiIHJlc3VsdD0ib2Zmc2V0Ii8+PGZlQ29tcG9zaXRlIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9Im9mZnNldCIgcmVzdWx0PSJjb21wb3NpdGUyIi8+PC9maWx0ZXI+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iMjk4Ni40IiB4Mj0iMzEyOC40IiB5MT0iMTYyMy44IiB5Mj0iMTYyMy44IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC4yNzE0MSAwIDAgLjI3MjE4IC04MDQuODEgLTQxNy40NSkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiMzYzNjM2MiLz48c3RvcCBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS13aWR0aD0iMS4xIiBkPSJNMjMuMjggNS41NXYzLjI0aC0zLjM2djIuOTJoMy4zNnYxLjc2Yy0zLjM2IDIuMTItMyA1Ljc0LTMgNS43NC0xMS04LjUyLTIwLjY3IDcuNTYtNy45NCAxMy4wNXY4LjczYzAgLjk1IDUuNjcgMi40NiAxMi42NiAyLjQ2czEyLjY2LTEuNSAxMi42Ni0yLjQ2di04LjczYzEyLjcyLTUuNDkgMy4wNi0yMS41Ny03Ljk1LTEzLjA1IDAgMCAuMzgtMy42Mi0zLTUuNzRWMTEuN2gzLjM3VjguNzloLTMuMzZWNS41NUgyNXoiIGZpbHRlcj0idXJsKCNiKSIvPjxlbGxpcHNlIGN4PSI3MS4wOCIgY3k9IjEzMS41NCIgZmlsbD0iI2U2ZTZlNiIgY2xhc3M9InN0MTUiIGZpbHRlcj0idXJsKCNjKSIgcng9IjMyLjEzIiByeT0iMi44NCIgdHJhbnNmb3JtPSJtYXRyaXgoLjI4NTMzIDAgMCAuMzIyMyA0LjcyIC0xLjk4KSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2U2ZTZlNiIgc3Ryb2tlLXdpZHRoPSIxLjQiIGQ9Ik0yNy4wMyAzMC4yN2MxLjUtMTIuMSAxMS45NC0xMi40NCAxMy4zNy03LjM4IDEuNDIgNS4wNi00Ljc0IDcuMzgtNC43NCA3LjM4cy00Ljg3LS42NC0xMC42Ni0uNjQtMTAuNjYuNjQtMTAuNjYuNjQtNi4xNi0yLjMyLTQuNzMtNy4zOCAxMS44Ny00LjczIDEzLjM2IDcuMzgiLz48L3N2Zz4=')}
diff --git a/public/piece/cardinal/bB.svg b/public/piece/cardinal/bB.svg
index 010eb5e91f0ed..7050e902f4d14 100644
--- a/public/piece/cardinal/bB.svg
+++ b/public/piece/cardinal/bB.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/bK.svg b/public/piece/cardinal/bK.svg
index 17854b81c3270..2f5ff4ae96a3c 100644
--- a/public/piece/cardinal/bK.svg
+++ b/public/piece/cardinal/bK.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/bN.svg b/public/piece/cardinal/bN.svg
index a5de017abf128..57389102bf4bd 100644
--- a/public/piece/cardinal/bN.svg
+++ b/public/piece/cardinal/bN.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/bP.svg b/public/piece/cardinal/bP.svg
index f080eace9d18d..3a37a7da284cf 100644
--- a/public/piece/cardinal/bP.svg
+++ b/public/piece/cardinal/bP.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/bQ.svg b/public/piece/cardinal/bQ.svg
index 5f9eccfe8938a..204d14991cbeb 100644
--- a/public/piece/cardinal/bQ.svg
+++ b/public/piece/cardinal/bQ.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/bR.svg b/public/piece/cardinal/bR.svg
index d9f89d553d95a..a01b04d2ab4fb 100644
--- a/public/piece/cardinal/bR.svg
+++ b/public/piece/cardinal/bR.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/wB.svg b/public/piece/cardinal/wB.svg
index 2d7b358b1eede..11450c687d28d 100644
--- a/public/piece/cardinal/wB.svg
+++ b/public/piece/cardinal/wB.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/wK.svg b/public/piece/cardinal/wK.svg
index e9e076f8e9e95..58ec38d0a67b1 100644
--- a/public/piece/cardinal/wK.svg
+++ b/public/piece/cardinal/wK.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/wN.svg b/public/piece/cardinal/wN.svg
index b596a4c23a161..23944a3082635 100644
--- a/public/piece/cardinal/wN.svg
+++ b/public/piece/cardinal/wN.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/wP.svg b/public/piece/cardinal/wP.svg
index 86287ed6c69e3..3b47f67a5abfe 100644
--- a/public/piece/cardinal/wP.svg
+++ b/public/piece/cardinal/wP.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/wQ.svg b/public/piece/cardinal/wQ.svg
index c561ed108b80e..2e904c745db9e 100644
--- a/public/piece/cardinal/wQ.svg
+++ b/public/piece/cardinal/wQ.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/piece/cardinal/wR.svg b/public/piece/cardinal/wR.svg
index 548ad4e659937..8ba39b2b3d1bd 100644
--- a/public/piece/cardinal/wR.svg
+++ b/public/piece/cardinal/wR.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/translation/dest/activity/es-ES.xml b/translation/dest/activity/es-ES.xml
index a5296ee69bd19..4e71a086008e0 100644
--- a/translation/dest/activity/es-ES.xml
+++ b/translation/dest/activity/es-ES.xml
@@ -66,7 +66,7 @@
Ha competido en %s torneo suizoHa competido en %s torneos suizos
- #%1$s en la clasificación en %2$s
+ #%1$s En la Clasificatoria de %2$sRegistrado en LichessMiembro de %s equipo
diff --git a/translation/dest/activity/he-IL.xml b/translation/dest/activity/he-IL.xml
index fa46e214bcc9e..622f988d615b1 100644
--- a/translation/dest/activity/he-IL.xml
+++ b/translation/dest/activity/he-IL.xml
@@ -82,23 +82,23 @@
השתתף/ה בטורניר זירה %s
- השתתף/ה ב-%s טורנירי זירה
- השתתף/ה ב-%s טורנירי זירה
- השתתף/ה ב-%s טורנירי זירה
+ השתתף/ה ב־%s טורנירי זירה
+ השתתף/ה ב־%s טורנירי זירה
+ השתתף/ה ב־%s טורנירי זירה
- סיים/ה במקום #%1$s (אחוזון %%%2$s) עם משחק %3$s ב-%4$s
+ סיים/ה במקום #%1$s (אחוזון %%%2$s) עם משחק %3$s ב־%4$sסיים/ה במקום #%1$s (אחוזון %%%2$s) עם %3$s משחקים ב%4$sסיים/ה במקום #%1$s (אחוזון %%%2$s) עם %3$s משחקים ב%4$sסיים/ה במקום #%1$s (אחוזון %%%2$s) עם %3$s משחקים ב%4$sהשתתף/ה בטורניר שוויצרי %s
- השתתף/ה ב-%s טורנירים שוויצריים
- השתתף/ה ב-%s טורנירים שוויצריים
- השתתף/ה ב-%s טורנירים שוויצריים
+ השתתף/ה ב־%s טורנירים שוויצריים
+ השתתף/ה ב־%s טורנירים שוויצריים
+ השתתף/ה ב־%s טורנירים שוויצריים
- סיים/ה במקום %1$s ב-%2$s
+ סיים/ה במקום %1$s ב־%2$sנרשם/ה לlichess.orgהצטרף/ה לקבוצה %s
diff --git a/translation/dest/appeal/ca-ES.xml b/translation/dest/appeal/ca-ES.xml
index e16728297af9f..8b702a604fcb1 100644
--- a/translation/dest/appeal/ca-ES.xml
+++ b/translation/dest/appeal/ca-ES.xml
@@ -7,15 +7,15 @@
El teu compte té prohibit jugar tornejos amb premis reals.El teu compte està marcat com a manipulació de la puntuació.Ho definim com manipular la puntuació perdent partides expressament, o jugant contra un altre compte que està perdent partides deliberadament.
- El teu compte està silenciat.
- Llegiu la nostra %s. No respectar les normes de comunicació pot provocar que els comptes se silenciïn.
+ El teu compte està silenciat.
+ Llegiu la nostra %s. No respectar les normes de comunicació pot provocar que els comptes se silenciïn.El vostre compte ha estat exclòs de les classificacions.Ho definim com fer servir alguna forma bruta per pujar a la clarificació.El vostre compte ha estat tancat pels moderadors.Les vostres entrades del blog han estat amagades pels moderadors.Assegureu-vos de llegir de nou la nostra %s.
- Teniu un temps d\'espera per jugar.
- guia de comunicació
+ Teniu un temps d\'espera per jugar.
+ guia de comunicaciónormes del blogJoc net
diff --git a/translation/dest/appeal/da-DK.xml b/translation/dest/appeal/da-DK.xml
index 8694ae3aa9e5e..d01a13e1b86e9 100644
--- a/translation/dest/appeal/da-DK.xml
+++ b/translation/dest/appeal/da-DK.xml
@@ -7,15 +7,15 @@
Din konto er udelukket fra turneringer med rigtige præmier.Din konto er markeret for ratingmanipulation.Vi definerer dette som bevidst manipulation af rating ved at tabe partier med vilje eller ved at spille mod en anden konto, der bevidst taber partier.
- Din konto er gjort stum.
- Læs vores %s. Hvis retningslinjerne for kommunikation ikke følges, kan det resultere i, at konti bliver gjort stumme.
+ Din konto er gjort stum.
+ Læs vores %s. Hvis retningslinjerne for kommunikation ikke følges, kan det resultere i, at konti bliver gjort stumme.Din konto er blevet udelukket fra ranglister.Vi definerer dette som at bruge unfair metoder til at komme på ranglisten.Din konto blev lukket af moderatorer.Dine blogs er blevet skjult af moderatorer.Sørg for igen at læse vores %s.
- Du har en spille-timeout.
- retningslinjer for kommunikation
+ Du har en spille-timeout.
+ retningslinjer for kommunikationblogreglerFairplay
diff --git a/translation/dest/appeal/en-US.xml b/translation/dest/appeal/en-US.xml
index f85d0c50813f1..6e07d2cd1155d 100644
--- a/translation/dest/appeal/en-US.xml
+++ b/translation/dest/appeal/en-US.xml
@@ -7,15 +7,15 @@
Your account is banned from tournaments with real prizes.Your account is marked for rating manipulation.We define this as deliberately manipulating a rating by losing games on purpose or by playing against another account that is deliberately losing games.
- Your account is muted.
- Read our %s. Failure to comply with the communication guidelines may result in your account being muted.
+ Your account is muted.
+ Read our %s. Failure to comply with the communication guidelines may result in your account being muted.Your account has been excluded from leaderboards.We define this as using any unfair way to get on the leaderboard.Your account was closed by moderators.Your blogs have been hidden by moderators.Make sure to read again our %s.
- You have a play timeout.
- communication guidelines
+ You have a play timeout.
+ communication guidelinesblog rulesFair Play
diff --git a/translation/dest/appeal/es-ES.xml b/translation/dest/appeal/es-ES.xml
index 95dfda7f61b58..7c5e0344ab51a 100644
--- a/translation/dest/appeal/es-ES.xml
+++ b/translation/dest/appeal/es-ES.xml
@@ -7,15 +7,15 @@
Tu cuenta tiene prohibido participar en torneos con premios reales.Tu cuenta está marcada por manipulación de la calificación.Definimos manipular deliberadamente la calificación como el perder partidas a propósito, o jugar contra otra cuenta que está perdiendo partidas deliberadamente.
- Tu cuenta está silenciada.
- Lee nuestro %s. No seguir las directrices de comunicación puede provocar que las cuentas sean silenciadas.
+ Tu cuenta está silenciada.
+ Lee nuestro %s. No seguir las directrices de comunicación puede provocar que las cuentas sean silenciadas.Se ha excluido a su cuenta de las tablas de clasificación.Definimos esto como usar cualquier forma injusta de posicionarse en la tabla de clasificaciones.Tu cuenta fue cerrada por moderadores.Tus blogs han sido ocultados por los moderadores.Asegúrate de leer de nuevo nuestro %s.
- Tienes un tiempo de espera agotado.
- directrices de comunicación
+ Tienes un tiempo de espera agotado.
+ directrices de comunicaciónreglas del blogJuego limpio
diff --git a/translation/dest/appeal/fi-FI.xml b/translation/dest/appeal/fi-FI.xml
index 5cd863947840f..b5428565d6766 100644
--- a/translation/dest/appeal/fi-FI.xml
+++ b/translation/dest/appeal/fi-FI.xml
@@ -7,15 +7,15 @@
Tunnuksesi on estetty pelaamasta turnauksissa, joissa on oikeita palkintoja.Tunnukseesi on lisätty merkintä vahvuusluvun manipuloinnista.Määritelmämme mukaan tällä tarkoitetaan vahvuusluvun peukalointia joko häviämällä pelejä tahallisesti tai pelaamalla sellaista tunnusta vastaan, joka häviää pelejä tarkoituksella.
- Tunnuksesi on mykistetty.
- Lue meidän %s. Viestintäsääntöjen noudattamatta jättäminen voi johtaa tunnusten mykistämiseen.
+ Tunnuksesi on mykistetty.
+ Lue meidän %s. Viestintäsääntöjen noudattamatta jättäminen voi johtaa tunnusten mykistämiseen.Tunnuksesi on estetty näkymästä pistetaulukoissa.Määritelmämme mukaan tämä tarkoittaa mitä tahansa epäreilua keinoa, jolla tavoitellaan pistetaulukkoon pääsyä.Moderaattorit ovat sulkeneet tunnuksesi.Moderaattorit ovat piilottaneet blogisi.Ole hyvä ja lue uudelleen %s.
- Sinulle on asetettu pelitauko.
- viestintäsääntömme
+ Sinulle on asetettu pelitauko.
+ viestintäsääntömmeblogisäännötReilu peli
diff --git a/translation/dest/appeal/fr-FR.xml b/translation/dest/appeal/fr-FR.xml
index 2eac3d7a7eacb..02c1ff3018a3c 100644
--- a/translation/dest/appeal/fr-FR.xml
+++ b/translation/dest/appeal/fr-FR.xml
@@ -8,14 +8,14 @@
Votre compte est marqué pour manipulation de classement (cote).Par manipulation de classement, on entend une manipulation délibérée du classement par un joueur qui perd volontairement des parties ou qui affronte un autre joueur en sachant que ce dernier perd volontairement ses parties.Vous ne pouvez plus clavarder avec votre adversaire ni envoyer des messages.
- Lisez nos %s. Ne pas les suivre peut entraîner la mise en sourdine de votre compte.
+ Lisez nos %s. Ne pas les suivre peut entraîner la mise en sourdine de votre compte.Vous avez été exclu(e) du classement.L\'exclusion du classement résulte habituellement de l\'utilisation délibérée d\'un moyen déloyal pour faire partie du classement.Votre compte a été fermé par les modérateurs.Votre blogue a été masqué par les modérateurs.Relisez nos %s.Vous ne pouvez plus jouer de partie temporairement.
- Lignes directrices de communication
+ Lignes directrices de communicationRègles relatives aux bloguesEsprit sportif
diff --git a/translation/dest/appeal/gl-ES.xml b/translation/dest/appeal/gl-ES.xml
index 0add6635f5c5a..48412370e5cda 100644
--- a/translation/dest/appeal/gl-ES.xml
+++ b/translation/dest/appeal/gl-ES.xml
@@ -7,15 +7,15 @@
A túa conta ten prohibido participar en torneos con premios reais.A túa conta está marcada por manipulación da puntuación.Isto definímolo como a manipulación deliberada da puntuación mediante a derrota adrede das partidas, ou mediante o xogo contra outra conta que perde deliberadamente as partidas.
- A túa conta está silenciada.
- Le as nosas %s. Non respectar as directrices de comunicación pode implicar que as contas sexan silenciadas.
+ A túa conta está silenciada.
+ Le as nosas %s. Non respectar as directrices de comunicación pode implicar que as contas sexan silenciadas.A túa conta foi excluída das listaxes de líderes.Isto definímolo como o uso de calquera procedemento inxusto para aparecer nas listaxes de líderes.A túa conta foi pechada polos moderadores.As túas publicacións no blog foron agochadas polos moderadores.Asegúrate de ler de novo as nosas %s.
- Non podes xogar debido a unha suspensión temporal.
- directrices de comunicación
+ Non podes xogar debido a unha suspensión temporal.
+ directrices de comunicaciónregras do blogXogo limpo
diff --git a/translation/dest/appeal/gsw-CH.xml b/translation/dest/appeal/gsw-CH.xml
index 3699abb8c5a92..1ba63439b4a23 100644
--- a/translation/dest/appeal/gsw-CH.xml
+++ b/translation/dest/appeal/gsw-CH.xml
@@ -7,15 +7,15 @@
Dis Konto isch gschperrt, für Turnier mit ächte Prise.Dis Konto isch markiert wäge Wertigs - Manipulation.Mir definiered das als absichtlichi Manipulation vu de Wertig, dur absichtlichs Verlüre vu Schpil oder dur Schpille gäge es anders Konto, wo ansichtlich Schpil verlürt.
- Dis Konto isch schtumm g\'schaltet.
- Lies euseri %s. D\'Nödihaltig vu de Kommunikationsrichtlinie chann dezue fühere, dass Konte schtumm g\'eschaltet werded.
+ Dis Konto isch schtumm g\'schaltet.
+ Lies euseri %s. D\'Nödihaltig vu de Kommunikationsrichtlinie chann dezue fühere, dass Konte schtumm g\'eschaltet werded.Dis Konto isch vu de Beschtelischte usgschlosse.Mir definiered das als es Usnütze vu jegliche unfaire Methode, zum uf d\'Beschtelischte zcho.Dis Konto isch vu de Moderatore g\'schlosse worde.Dini Tagebüecher (Blogs) händ d\'Moderatore unsichtbar g\'macht.Lies unbedingt nomal euseri %s.
- Du häsch es Schpil - Timeout.
- Kommunikations - Richtlinie
+ Du häsch es Schpil - Timeout.
+ Kommunikations - RichtlinieTagebuech RegleFair Play
diff --git a/translation/dest/appeal/he-IL.xml b/translation/dest/appeal/he-IL.xml
index 623fe47c65075..0222635f83f7c 100644
--- a/translation/dest/appeal/he-IL.xml
+++ b/translation/dest/appeal/he-IL.xml
@@ -7,15 +7,15 @@
חשבונך לא יכול לשמש להצטרפות לטורנירים עם פרסים אמיתיים.חשבונך מוגבל בשל מניפולציה בדירוג.אסור לבצע מניפולציה בדירוג באמצעות הפסד של משחקים בכוונה או שימוש בחשבון אחר כדי להקטין את דירוגך.
- חשבונך מושתק.
- קראו את %s שלנו. חובה לעמוד בכללי השיח שלנו כדי להימנע מהשתקה של החשבון.
+ חשבונך מושתק.
+ קראו את %s שלנו. חובה לעמוד בכללי השיח שלנו כדי להימנע מהשתקה של החשבון.חשבונך לא יכול להופיע בטבלאות האלופים.חשבונות שמשתמשים בדרכים לא כשרות כדי להופיע בטבלאות יימחקו מהן.חשבונך נסגר על ידי המנהלים.הפוסטים שלך בבלוג הוסתרו על ידי המנהלים.אנא קראו את %s שלנו שוב.
- חשבונך מושעה ממשחקים.
- כללי השיח
+ חשבונך מושעה ממשחקים.
+ כללי השיחחוקי הבלוגמשחק ההוגן
diff --git a/translation/dest/appeal/ko-KR.xml b/translation/dest/appeal/ko-KR.xml
index 7269ec3ebcf3d..6c608ec7c716e 100644
--- a/translation/dest/appeal/ko-KR.xml
+++ b/translation/dest/appeal/ko-KR.xml
@@ -7,15 +7,15 @@
당신의 계정은 현금 상금이 걸려 있는 대회 참가가 금지되어 있습니다.당신의 계정은 레이팅 조작으로 표시되었습니다.이것은 고의로 게임에서 패배하거나, 고의로 게임에서 패배를 하고 있는 계정과 플레이함으로써 의도적으로 레이팅을 조작하는 행위로 정의됩니다.
- 당신의 계정에 침묵 제재가 적용중입니다.
- %s을 읽어보세요. 의사소통 가이드라인을 준수하지 않는다면, 계정에 침묵 제재가 적용될 수 있습니다.
+ 당신의 계정에 침묵 제재가 적용중입니다.
+ %s을 읽어보세요. 의사소통 가이드라인을 준수하지 않는다면, 계정에 침묵 제재가 적용될 수 있습니다.당신의 계정은 순위표에서 제외되었습니다.이것은 순위표에 오르기 위해서 임의의 부정직한 방법을 사용하는 것으로 정의됩니다.당신의 계정은 운영진에 의해 폐쇄되었습니다.당신의 블로그는 운영진에 의해 숨김 처리 되었습니다.꼭 %s를 읽어주세요.
- 당신은 게임 타임아웃 상태입니다.
- 의사소통 가이드라인
+ 당신은 게임 타임아웃 상태입니다.
+ 의사소통 가이드라인블로그 규칙페어플레이
diff --git a/translation/dest/appeal/nb-NO.xml b/translation/dest/appeal/nb-NO.xml
index 422b2a65069c5..d83d78c849132 100644
--- a/translation/dest/appeal/nb-NO.xml
+++ b/translation/dest/appeal/nb-NO.xml
@@ -8,14 +8,14 @@
Kontoen din har en anmerkning for manipulering av rating.Dette defineres som bevisst manipulering av rating ved å tape partier med vilje eller ved å spille mot en annen konto som taper partier med vilje.Kontoen din er gjort stum.
- Les våre %s. Hvis retningslinjene ikke blir fulgt, kan det føre til at kontoer blir gjort stumme.
+ Les våre %s. Hvis retningslinjene ikke blir fulgt, kan det føre til at kontoer blir gjort stumme.Kontoen din er utelatt fra ledertabellene.Dette defineres som å bruke urettferdige metoder for å komme på ledertabellene.Kontoen din ble avsluttet av moderatorene.Bloggene dine er blitt skjult av moderatorene.Les våre %s.Du har fått timeout fra å spille.
- retningslinjer for kommunikasjon
+ retningslinjer for kommunikasjonbloggreglersportslig opptreden
diff --git a/translation/dest/appeal/nn-NO.xml b/translation/dest/appeal/nn-NO.xml
index 556bc5de8a051..b4cd4ab4ecbab 100644
--- a/translation/dest/appeal/nn-NO.xml
+++ b/translation/dest/appeal/nn-NO.xml
@@ -7,15 +7,15 @@
Kontoen din er stengd ute frå deltaking i turneringar med premiepengar.Kontoen din er merka for ratingmanipulering.Vi definerer dette som bevisst manipulering av rating ved med hensikt å tapa parti, eller ved å spela mot ein annan konto som med hensikt tapar parti.
- Kontoen din er gjort stum.
- Les vår %s. Dersom desse retningslinjene ikkje vert følgd kan det føre til at kontoane vert gjort stumme.
+ Kontoen din er gjort stum.
+ Les vår %s. Dersom desse retningslinjene ikkje vert følgd kan det føre til at kontoane vert gjort stumme.Kontoen din er utelukka frå ranglistene.Vi definerer dette som å bruka urettvise måtar å koma på rangeringslistene.Moderatorane har stengd kontoen din.Moderatorane har skjult bloggane dine.Sørg for å lese vår %s opp att.
- Du har ei pause i spelet.
- retningslinjer for kommunikasjon
+ Du har ei pause i spelet.
+ retningslinjer for kommunikasjonbloggreglarFair Play
diff --git a/translation/dest/appeal/pt-BR.xml b/translation/dest/appeal/pt-BR.xml
index 9bf10bccc6475..59f4a5c176ff7 100644
--- a/translation/dest/appeal/pt-BR.xml
+++ b/translation/dest/appeal/pt-BR.xml
@@ -8,14 +8,14 @@
Sua conta está marcada por manipulação de rating.Nós definimos isso como uma manipulação deliberada perdendo jogos de propósito ou jogando contra outra conta que está deliberadamente perdendo jogos.Sua conta está silenciada.
- Leia as nossas %s. O não cumprimento das diretrizes de comunicação pode resultar no silenciamento das contas.
+ Leia as nossas %s. O não cumprimento das diretrizes de comunicação pode resultar no silenciamento das contas.Sua conta foi excluída das tabelas de classificação.Definimos isto como uma forma injusta de conseguir posições na tabela de classificações.Sua conta foi fechada pelos moderadores.Seus blogs foram ocultados pelos moderadores.Certifique-se de ler novamente as nossas %s.Você está temporariamente suspenso de jogar.
- diretrizes de comunicação
+ diretrizes de comunicaçãoregras do blogJogo Limpo
diff --git a/translation/dest/appeal/pt-PT.xml b/translation/dest/appeal/pt-PT.xml
index 5d8bd4c3879e4..0c243ffdd785c 100644
--- a/translation/dest/appeal/pt-PT.xml
+++ b/translation/dest/appeal/pt-PT.xml
@@ -7,15 +7,15 @@
A tua conta está banida dos torneios com prémios reais.A tua conta está marcada por manipulação de classificação.Definimos isto como manipular deliberadamente a classificação ao perder jogos de propósito ou ao jogar contra outra conta que esteja deliberadamente a perder jogos.
- A tua conta foi silenciada.
- Leia as nossas %s. O não cumprimento das diretrizes de comunicação pode resultar no silenciamento das contas.
+ A tua conta foi silenciada.
+ Leia as nossas %s. O não cumprimento das diretrizes de comunicação pode resultar no silenciamento das contas.A tua conta foi excluída das tabelas de classificação.Definimos isto como a utilização de qualquer forma injusta para entrar na tabela de liderança.A tua conta foi encerrada pelos moderadores.Os teus blogues foram ocultados pelos moderadores.Certifica que leias novamente as nossas %s.
- Estás temporariamente impedido de jogar.
- diretrizes de comunicação
+ Estás temporariamente impedido de jogar.
+ diretrizes de comunicaçãoregras do blogueJogo Justo
diff --git a/translation/dest/appeal/ru-RU.xml b/translation/dest/appeal/ru-RU.xml
index 3046326e13111..0a71961c4ff8a 100644
--- a/translation/dest/appeal/ru-RU.xml
+++ b/translation/dest/appeal/ru-RU.xml
@@ -7,15 +7,15 @@
Ваша учётная запись заблокирована для участия в турнирах с реальными призами.Ваша учётная запись помечена за манипуляции рейтингом.Мы определяем это как преднамеренное манипулирование рейтингом путём намеренного проигрыша партий или игрой против другого игрока, который намеренно проигрывает партии.
- Ваша учётная запись ограничена.
- Прочтите наши %s. Несоблюдение правил общения может привести к ограничению учётных записей.
+ Ваша учётная запись ограничена.
+ Прочтите наши %s. Несоблюдение правил общения может привести к ограничению учётных записей.Ваша учётная запись исключена из списка лидеров.Мы определяем это как использование нечестного способа попасть в список лидеров.Ваша учётная запись была закрыта модераторами.Ваши блоги были скрыты модераторами.Обязательно перечитайте наши %s.
- У вас есть таймаут.
- правила общения
+ У вас есть таймаут.
+ правила общенияправила ведения блоговЧестная игра
diff --git a/translation/dest/appeal/sl-SI.xml b/translation/dest/appeal/sl-SI.xml
index 46ad773473d8f..45eca1b4c2adf 100644
--- a/translation/dest/appeal/sl-SI.xml
+++ b/translation/dest/appeal/sl-SI.xml
@@ -7,15 +7,15 @@
Vaš račun je prepovedan za turnirje s pravimi nagradami.Vaš račun je označen za manipulacijo z rejtingi.To opredeljujemo kot namerno manipuliranje z rejtingom z namerno izgubo iger ali z igranjem proti drugemu računu, ki namerno izgublja igre.
- Vaš račun je izklopljen.
- Preberite naše %s. Neupoštevanje komunikacijskih smernic lahko povzroči utišanje računov.
+ Vaš račun je izklopljen.
+ Preberite naše %s. Neupoštevanje komunikacijskih smernic lahko povzroči utišanje računov.Vaš račun je bil izključen iz lestvic najboljših.Vaš račun je bil izključen iz lestvic najboljših.Vaš račun so zaprli moderatorji.Moderatorji so skrili vaše bloge.Ponovno preberite naše %s.
- Imate časovno omejitev za igranje.
- komunikacijske smernice
+ Imate časovno omejitev za igranje.
+ komunikacijske smernicepravila blogaPoštena igra
diff --git a/translation/dest/appeal/sq-AL.xml b/translation/dest/appeal/sq-AL.xml
index d4d6d4cedfc11..f908cbf8605d3 100644
--- a/translation/dest/appeal/sq-AL.xml
+++ b/translation/dest/appeal/sq-AL.xml
@@ -7,14 +7,14 @@
Llogarisë tuaj i është ndaluar të marrë pjesë në turne me çmime të njëmendta.Llogarisë tuaj i është vënë shenjë për manipulim vlerësimi.Këtë e përkufizojmë si manipulim me vetëdije i vlerësimit, duke humbur lojëra, ose duke luajtur kudnër një llogarije tjetër që po humb me vetëdije lojëra.
- Llogaria juaj është heshtuar.
- Lexoni %s tonë. Mosndjekja e udhëzimeve tona për komunikimin mund të sjellë heshtimin e llogarisë.
+ Llogaria juaj është heshtuar.
+ Lexoni %s tonë. Mosndjekja e udhëzimeve tona për komunikimin mund të sjellë heshtimin e llogarisë.Llogaria juaj është përjashtuar nga tabelat.Këtë e pkufizojmë si përdorim të çfarëdo rrute të padrejtë për të hyrë te tabela.Llogaria juaj u mbyll nga moderatorë.Blogjet tuaja janë fshehur nga moderatorë.Sigurohuni se lexoni edhe një herë %s tona.
- Keni një mbarim kohe lëvizjeje.
- udhëzime komunikimi
+ Keni një mbarim kohe lëvizjeje.
+ udhëzime komunikimirregulla blogjesh
diff --git a/translation/dest/appeal/tr-TR.xml b/translation/dest/appeal/tr-TR.xml
index 3fe8b2d980056..e69a2d85031f2 100644
--- a/translation/dest/appeal/tr-TR.xml
+++ b/translation/dest/appeal/tr-TR.xml
@@ -14,7 +14,7 @@
Hesabınız moderatörler tarafından kapatılmıştır.Bloglarınız moderatörler tarafından görünmeze alınmıştır.%s bölümümüzü tekrar okuduğunuzdan emin olun.
- Oyun zaman aşımınız var.
+ Uzaklaştırma cezanız var.iletişim kurallarıblog kurallarıFair Play
diff --git a/translation/dest/appeal/vi-VN.xml b/translation/dest/appeal/vi-VN.xml
index bb682ac1599ea..dab9fb42283a0 100644
--- a/translation/dest/appeal/vi-VN.xml
+++ b/translation/dest/appeal/vi-VN.xml
@@ -8,14 +8,14 @@
Tài khoản của bạn bị đánh dấu vì thao túng xếp hạng.Chúng tôi định nghĩa điều này là cố tình thao túng xếp hạng bằng cách cố tình thua ván cờ hoặc bằng cách chơi với một tài khoản khác đang cố tình thua ván cờ.Tài khoản của bạn bị tắt tiếng.
- Đọc %s của chúng tôi. Việc không tuân thủ các nguyên tắc giao tiép có thể dẫn đến việc tài khoản bị tắt tiếng.
+ Đọc %s của chúng tôi. Việc không tuân thủ các nguyên tắc giao tiép có thể dẫn đến việc tài khoản bị tắt tiếng.Tài khoản của bạn đã bị loại khỏi bảng xếp hạng.Chúng tôi định nghĩa điều này là sử dụng bất kỳ cách không công bằng nào để có được vị trí trên bảng xếp hạng.Tài khoản của bạn đã bị đóng bởi điều hành viên.Blog của bạn đã bị người điều hành ẩn.Hãy nhớ đọc lại %s của chúng tôi.Bạn có thời gian chờ chơi.
- hướng dẫn giao tiếp
+ hướng dẫn giao tiếpquy tắc blogChơi Công Bằng
diff --git a/translation/dest/arena/bg-BG.xml b/translation/dest/arena/bg-BG.xml
index 834aa6ed60eb1..8d7c4826575ca 100644
--- a/translation/dest/arena/bg-BG.xml
+++ b/translation/dest/arena/bg-BG.xml
@@ -71,8 +71,8 @@
медианиОбщоСреднени точки
- Сума на точките
- Среднен рейтинг
+ Сума на точките
+ Среднен рейтингПобедители в турнираСамо титулувани играчиИзискване на официална титла за участие в турнира
diff --git a/translation/dest/arena/ca-ES.xml b/translation/dest/arena/ca-ES.xml
index ac6b5213ca5f9..e1762bf2c45f3 100644
--- a/translation/dest/arena/ca-ES.xml
+++ b/translation/dest/arena/ca-ES.xml
@@ -77,8 +77,8 @@ Per exemple, estar en el tercer lloc en un torneig de 100 jugadors = 3%. Ser cla
Totes les mitjanes d\'aquesta pàgina són %s.TotalMitjana de punts
- Suma de punts
- Rànquing mitjà
+ Suma de punts
+ Rànquing mitjàGuanyadors de tornejosInsígnies de tornejosNomés jugadors titulats
diff --git a/translation/dest/arena/da-DK.xml b/translation/dest/arena/da-DK.xml
index b98f26b066ec3..818edf656b379 100644
--- a/translation/dest/arena/da-DK.xml
+++ b/translation/dest/arena/da-DK.xml
@@ -77,8 +77,8 @@ Eksempelvis er en rangering som nummer 3 i en turnering med 100 spillere = 3%. A
Alle gennemsnit på denne side er %s.I altGennemsnitlige point
- Sum af point
- Gennemsnitlig rangering
+ Sum af point
+ Gennemsnitlig rangeringTurneringsvindereTurneringsskjoldKun spillere med titel
diff --git a/translation/dest/arena/de-DE.xml b/translation/dest/arena/de-DE.xml
index 6837b0feb79b0..0fc28b807c32f 100644
--- a/translation/dest/arena/de-DE.xml
+++ b/translation/dest/arena/de-DE.xml
@@ -79,8 +79,8 @@ Ein Beispiel: Wenn man in einem Turnier von 100 Spielern Platz 3 erreicht hat =
Alle Durchschnittswerte auf dieser Seite sind %s.GesamtPunkte im Schnitt
- Punkte insgesamt
- Platzierungs-Durchschnitt
+ Punkte insgesamt
+ Platzierungs-DurchschnittTurniersiegerTurnier-SchildeNur Spieler mit Titel
diff --git a/translation/dest/arena/el-GR.xml b/translation/dest/arena/el-GR.xml
index 5a4d1f24e897f..541e95d2285d6 100644
--- a/translation/dest/arena/el-GR.xml
+++ b/translation/dest/arena/el-GR.xml
@@ -79,8 +79,8 @@ To Berserk δεν ισχύει για παρτίδες με μηδενικό α
Όλοι οι μέσοι όροι σε αυτή τη σελίδα είναι %s.ΣύνολοΜέσος όρος πόντων
- Σύνολο πόντων
- Μέσος όρος κατάταξης
+ Σύνολο πόντων
+ Μέσος όρος κατάταξηςΝικητές πρωταθλήματοςΠρωταθλήματα ΑσπίδαςΜόνο τιτλούχοι παίκτες
diff --git a/translation/dest/arena/en-US.xml b/translation/dest/arena/en-US.xml
index 63a9057477bf2..2e354f59aff4d 100644
--- a/translation/dest/arena/en-US.xml
+++ b/translation/dest/arena/en-US.xml
@@ -80,8 +80,8 @@ For instance, being ranked 3 in a tournament of 100 players = 3%. Being ranked 1
All averages on this page are %s.TotalPoints avg
- Points sum
- Rank avg
+ Points sum
+ Rank avgTournament winnersTournament shieldsOnly titled players
diff --git a/translation/dest/arena/es-ES.xml b/translation/dest/arena/es-ES.xml
index ca3629e787f5e..8c6f7da1cd54d 100644
--- a/translation/dest/arena/es-ES.xml
+++ b/translation/dest/arena/es-ES.xml
@@ -79,8 +79,8 @@ Por ejemplo, ocupar el puesto 3 en un torneo de 100 jugadores = 3%. Estar en el
Todos los promedios en esta página son %s.TotalPromedio de puntos
- Suma de puntos
- Promedio de clasificación
+ Suma de puntos
+ Promedio de clasificaciónGanadores del torneoEscudos de torneoSolo jugadores titulados
diff --git a/translation/dest/arena/fi-FI.xml b/translation/dest/arena/fi-FI.xml
index 2131da2173be2..83809b27f9ea9 100644
--- a/translation/dest/arena/fi-FI.xml
+++ b/translation/dest/arena/fi-FI.xml
@@ -77,8 +77,8 @@ Esimerkiksi sijoittuminen 3. sijalle 100 pelaajan turnauksessa = 3%. Sijoittumin
Kaikki keskiarvot tällä sivulla ovat %s.YhteensäPisteiden keskiarvo
- Pisteiden summa
- Sijoitusten keskiarvo
+ Pisteiden summa
+ Sijoitusten keskiarvoTurnauksen voittajatTurnauskilvetVain arvonimen saaneet pelaajat
diff --git a/translation/dest/arena/fr-FR.xml b/translation/dest/arena/fr-FR.xml
index 2df67b2616799..401be64e2dfd3 100644
--- a/translation/dest/arena/fr-FR.xml
+++ b/translation/dest/arena/fr-FR.xml
@@ -77,8 +77,8 @@ Par exemple, être classé 3e dans un tournoi de 100 joueurs = 3 %. Être class
Toutes les moyennes sur cette page sont des %s.TotalMoyenne des points
- Somme des points
- Classement moyen
+ Somme des points
+ Classement moyenVainqueurs du tournoiTournois des BoucliersUniquement les joueurs titrés
diff --git a/translation/dest/arena/gl-ES.xml b/translation/dest/arena/gl-ES.xml
index 6558c4f6ddfca..ba09441d40760 100644
--- a/translation/dest/arena/gl-ES.xml
+++ b/translation/dest/arena/gl-ES.xml
@@ -78,8 +78,8 @@ Por exemplo, ficar en 3º lugar nun torneo de 100 xogadores = 3%. Ficar 10º nun
Todas as medias nesta páxina son %s.TotalMedia de puntos
- Suma dos puntos
- Clasificación media
+ Suma dos puntos
+ Clasificación mediaGañadores do torneoTorneos de EscudoSó xogadores titulados
diff --git a/translation/dest/arena/he-IL.xml b/translation/dest/arena/he-IL.xml
index 301d1b935d5a2..588e92fd103ef 100644
--- a/translation/dest/arena/he-IL.xml
+++ b/translation/dest/arena/he-IL.xml
@@ -8,7 +8,7 @@
טורניר זה אינו מדורג ולא ישפיע על דירוגך.חלק מהתחרויות הן מדורגות ויקבעו את דירוגך.איך מחושבות תוצאות המשחקים?
- נצחון מזכה ב-2 נקודות, תיקו באחת, והפסד לא מזכה בנקודות. לאחר שני ניצחונות רצופים, יוכפלו הנקודות: 4 לניצחון, 2 לתיקו, 0 להפסד. מצב זה יסומן באמצעות אייקון להבה. הפסד או תיקו יסיימו את סדרת הכפלת הנקודות והניקוד יחושב אחריהם באופן רגיל. למשל, 2 נצחונות ואחריהם תיקו שווים 2+2+(2x1) או 6 נקודות
+ נצחון מזכה ב־2 נקודות, תיקו באחת, והפסד לא מזכה בנקודות. לאחר שני ניצחונות רצופים, יוכפלו הנקודות: 4 לניצחון, 2 לתיקו, 0 להפסד. מצב זה יסומן באמצעות אייקון להבה. הפסד או תיקו יסיימו את סדרת הכפלת הנקודות והניקוד יחושב אחריהם באופן רגיל. למשל, 2 נצחונות ואחריהם תיקו שווים 2+2+(2x1) או 6 נקודותאטרף בטורנירי זירההבוחר באופציית האטרף מאבד מחצית מזמנו, אך ניצחון יזכה אותו בנקודה נוספת, בתנאי שעשה במשחק לפחות 7 מסעים.
@@ -52,7 +52,7 @@
תאריך התחלהבאזור הזמן המקומי שלך. אפשרות זו עוקפת את ההגדרה \"זמן לפני תחילת הטורניר\"אפשרו את כפתור האטרף
- אפשרו לשחקנים לחלק ב-2 את הזמן בשעונם כדי לקבל עוד נקודה
+ אפשרו לשחקנים לחלק ב־2 את הזמן בשעונם כדי לקבל עוד נקודהאפשרו לשחקנים לנהל דיונים בחדר שיחהרצפי ניצחונות בטורניר זירהלאחר 2 ניצחונות, ניצחונות רצופים מקנים 4 נקודות במקום 2.
@@ -81,8 +81,8 @@
כל הממוצעים בעמוד זה הם למעשה %s.סך הכלממוצע הנקודות
- סכום הנקודות
- ממוצע הדירוג
+ סכום הנקודות
+ ממוצע הדירוגמנצחי הטורניריםמגיני הטורניריםשחקנים עטורי דרגות בלבד
diff --git a/translation/dest/arena/hi-IN.xml b/translation/dest/arena/hi-IN.xml
index 61ea218ff1da4..b99d06030bfa8 100644
--- a/translation/dest/arena/hi-IN.xml
+++ b/translation/dest/arena/hi-IN.xml
@@ -78,8 +78,8 @@
इस पृष्ठ पर सभी औसत हैं %sकुलअंक औसत
- अंक योग
- रैंक औसत
+ अंक योग
+ रैंक औसतटूर्नामेंट विजेताटूर्नामेंट शील्ड्सकेवल शीर्षक वाले खिलाड़ी
diff --git a/translation/dest/arena/lb-LU.xml b/translation/dest/arena/lb-LU.xml
index 7e2cad508b18d..0b87eb85129b2 100644
--- a/translation/dest/arena/lb-LU.xml
+++ b/translation/dest/arena/lb-LU.xml
@@ -72,7 +72,7 @@ Spill schnell an géih zeréck an d\'Turnéieriwwersicht fir méi Partien ze spi
All Duerchschnëttswäerter op dëser Säit sinn %s.InsgesamtPunktenduerchschnëtt
- Punktenzomm
+ PunktenzommGewënner vum TurnéierTurnéierschëlterJust Spiller mat Titel
diff --git a/translation/dest/arena/nb-NO.xml b/translation/dest/arena/nb-NO.xml
index f52775d36d8d1..592488f72c2ba 100644
--- a/translation/dest/arena/nb-NO.xml
+++ b/translation/dest/arena/nb-NO.xml
@@ -72,8 +72,8 @@ For eksempel tilsvarer en tredjeplass i en turnering med 100 spillere 3 %. En ti
Alle snittverdiene på denne siden er %s.TotaltPoengsnitt
- Poengsum
- Prosentrangering
+ Poengsum
+ ProsentrangeringTurneringsvinnereTurneringsskjoldKun spillere med sjakktittel
diff --git a/translation/dest/arena/nn-NO.xml b/translation/dest/arena/nn-NO.xml
index dc2e23196ea0e..2fe9be6c6484a 100644
--- a/translation/dest/arena/nn-NO.xml
+++ b/translation/dest/arena/nn-NO.xml
@@ -72,8 +72,8 @@ Til dømes vil ein tredjeplass i ei turnering med 100 deltakarar gje plasserings
Alle snittverdiar på denne sida er %s.TotaltPoengsnitt
- Poengsum
- Snittplassering
+ Poengsum
+ SnittplasseringTurneringsvinnararTurneringsskjoldBerre spelarar med sjakktittel
diff --git a/translation/dest/arena/pl-PL.xml b/translation/dest/arena/pl-PL.xml
index 44e5094e56f51..ea235df8afb6e 100644
--- a/translation/dest/arena/pl-PL.xml
+++ b/translation/dest/arena/pl-PL.xml
@@ -82,8 +82,8 @@ Na przykład, będąc 3 w rankingu turnieju liczącym 100 graczy = 3%. Będąc 1
Wszystkie średnie na tej stronie to %s.OgółemŚrednia liczba punktów
- Suma punktów
- Średni ranking
+ Suma punktów
+ Średni rankingZwycięzcy turniejuTarcze turniejoweTylko gracze z tytułem
diff --git a/translation/dest/arena/pt-BR.xml b/translation/dest/arena/pt-BR.xml
index da2214e071516..24207637de778 100644
--- a/translation/dest/arena/pt-BR.xml
+++ b/translation/dest/arena/pt-BR.xml
@@ -76,8 +76,8 @@ Por exemplo, estar classificado como 3° de um torneio de 100 jogadores = 3%. Es
Todas as médias desta página são %s.TotalMédia de pontos
- Soma dos pontos
- Média de classificação
+ Soma dos pontos
+ Média de classificaçãoVencedores de torneioTorneios de escudoApenas jogadores titulados
diff --git a/translation/dest/arena/pt-PT.xml b/translation/dest/arena/pt-PT.xml
index 5663ff32219fb..afcc89d38f6bd 100644
--- a/translation/dest/arena/pt-PT.xml
+++ b/translation/dest/arena/pt-PT.xml
@@ -79,8 +79,8 @@ Por exemplo, ficar em 3º lugar num torneio de 100 jogadores = 3%. Estar em 10º
Todas as médias desta página são %s.TotalMédia de pontos
- Pontos Somados
- Classificação Média
+ Pontos Somados
+ Classificação MédiaVencedores do torneioEscudos do torneioApenas jogadores titulados
diff --git a/translation/dest/arena/ru-RU.xml b/translation/dest/arena/ru-RU.xml
index 00ae84488b09a..5dfdc3abf9404 100644
--- a/translation/dest/arena/ru-RU.xml
+++ b/translation/dest/arena/ru-RU.xml
@@ -76,8 +76,8 @@
Средние значения по этой странице: %s.ВсегоОчки в среднем
- Сумма очков
- Среднее занятое место
+ Сумма очков
+ Среднее занятое местоПобедители турнираЩиты турнировТолько игроки со званиями
diff --git a/translation/dest/arena/sl-SI.xml b/translation/dest/arena/sl-SI.xml
index 4b6559d81dc94..ea2214563ad94 100644
--- a/translation/dest/arena/sl-SI.xml
+++ b/translation/dest/arena/sl-SI.xml
@@ -82,8 +82,8 @@ Na primer, 3. mesto na turnirju s 100 igralci = 3%. 10. mesto na turnirju s 1000
Vsa povprečja na tej strani so %s.SkupajPovprečje točk
- Seštevek točk
- Povprečje uvrstitve
+ Seštevek točk
+ Povprečje uvrstitveZmagovalci turnirjevTurnirski ščitiSamo igralci z nazivom
diff --git a/translation/dest/arena/sq-AL.xml b/translation/dest/arena/sq-AL.xml
index ade3619d72597..c0fd85dca0d6a 100644
--- a/translation/dest/arena/sq-AL.xml
+++ b/translation/dest/arena/sq-AL.xml
@@ -76,8 +76,8 @@ Për shembull, të qenët i renditur i 3-i në një turne me 100 lojtarë = 3%.
Krejt mesataret në këtë faqe janë %s.GjithsejMesatare pikësh
- Shumë pikësh
- Mesatare renditjeje
+ Shumë pikësh
+ Mesatare renditjejeFitues turneshVetëm lojtarë me titullPër të marrë pjesë në turne, kërko doemos një titull zyrtar
diff --git a/translation/dest/arena/th-TH.xml b/translation/dest/arena/th-TH.xml
index 461c069730dd0..d354c557c8256 100644
--- a/translation/dest/arena/th-TH.xml
+++ b/translation/dest/arena/th-TH.xml
@@ -68,8 +68,8 @@
ค่าเฉลี่ยทั้งหมดในหน้านี้คือ %sทั้งหมดแต้มเฉลี่ย
- ผลรวมแต้ม
- อันดับเฉลี่ย
+ ผลรวมแต้ม
+ อันดับเฉลี่ยผู้ชนะทัวร์นาเมนต์โล่การแข่งขันผู้เล่นที่มีตำแหน่ง
diff --git a/translation/dest/arena/uk-UA.xml b/translation/dest/arena/uk-UA.xml
index 85e9d677918cc..512113ed6bd46 100644
--- a/translation/dest/arena/uk-UA.xml
+++ b/translation/dest/arena/uk-UA.xml
@@ -81,8 +81,8 @@
Усі середні значення на цій сторінці є %s.ЗагальніСередні значення очків
- Сума очок
- Середнє місце
+ Сума очок
+ Середнє місцеПереможці турніруТурнірні щитиТільки титуловані гравці
diff --git a/translation/dest/arena/vi-VN.xml b/translation/dest/arena/vi-VN.xml
index ef5c287ecbbcd..f407fbe82d5f3 100644
--- a/translation/dest/arena/vi-VN.xml
+++ b/translation/dest/arena/vi-VN.xml
@@ -52,7 +52,7 @@ Chơi nhanh và trở lại phòng chờ để chơi được nhiều ván và g
Cho phép BerserkCho phép các kỳ thủ giảm một nửa thời gian để lấy thêm một điểmCho phép các kỳ thủ trò chuyện trong phòng trò chuyện
- Đấu trường chuỗi
+ Chuỗi đấu trườngSau 2 ván thắng, mỗi ván thắng liên tiếp sẽ được 4 điểm thay vì 2 điểm.Không cho phép BerserkKhông có chuỗi Đấu trường
@@ -77,8 +77,8 @@ Ví dụ: được hạng 3 trong một giải đấu có 100 kỳ thủ = 3%. H
Tất cả các giá trị trung bình trên trang này đều là %s.TổngĐiểm trung bình
- Tổng điểm
- Thứ hạng trung bình
+ Tổng điểm
+ Thứ hạng trung bìnhCác nhà vô địch giảiCác khiên giải đấuChỉ những kỳ thủ có danh hiệu
diff --git a/translation/dest/arena/zh-CN.xml b/translation/dest/arena/zh-CN.xml
index f08f65439ef7e..1d6daa258883a 100644
--- a/translation/dest/arena/zh-CN.xml
+++ b/translation/dest/arena/zh-CN.xml
@@ -75,8 +75,8 @@
此页面上的所有平均值是 %s。总计平均分数
- 总分数
- 平均等级
+ 总分数
+ 平均等级锦标赛赢家锦标赛盾牌仅限有头衔玩家
diff --git a/translation/dest/broadcast/af-ZA.xml b/translation/dest/broadcast/af-ZA.xml
index d0e649c0eeae4..9aae5c00797cc 100644
--- a/translation/dest/broadcast/af-ZA.xml
+++ b/translation/dest/broadcast/af-ZA.xml
@@ -14,12 +14,11 @@
Kort beskrywing van die toernooiVolle geleentheid beskrywingOpsionele lang beskrywing van die uitsending. %1$s is beskikbaar. Lengte moet minder as %2$s karakters.
+ PGN-BronskakelURL wat Lichess sal nagaan vir PGN opdaterings. Dit moet openbaar beskikbaar wees vanaf die Internet.Begin datum in jou eie tydsoneOptioneel, indien jy weet wanner die geleentheid beginGee krediet aan die bron
- Uitsaai bronadres
- Huidige ronde se bronadresHuidige spel se bronadresLaai al die rondes afHerstel die ronde
@@ -30,4 +29,13 @@
Vee beslis die hele toernooi uit, met al sy rondtes en spelle.Opsioneel: vervang spelername, graderings en titelsPeriode in sekondes
+ FIDE-federasies
+ Top 10 gradering
+ FIDE-deelnemers
+ FIDE-deelnemer nie gevind nie
+ FIDE-profiel
+ Federasie
+ Ouderdom vanjaar
+ Ongegradeerd
+ Onlangse toernooie
diff --git a/translation/dest/broadcast/an-ES.xml b/translation/dest/broadcast/an-ES.xml
index a0c9494602f13..9b90677dd6922 100644
--- a/translation/dest/broadcast/an-ES.xml
+++ b/translation/dest/broadcast/an-ES.xml
@@ -19,7 +19,5 @@
Data d\'inicio en a tuya zona horariaOpcional, si sabes quan prencipia l\'eventoCita la fuent
- URL d\'a emisión
- Vinclo d\'a ronda actualVinclo d\'a partida actual
diff --git a/translation/dest/broadcast/ar-SA.xml b/translation/dest/broadcast/ar-SA.xml
index fa854c94789a4..d81246c170890 100644
--- a/translation/dest/broadcast/ar-SA.xml
+++ b/translation/dest/broadcast/ar-SA.xml
@@ -27,12 +27,12 @@
وصف موجز للبطولةالوصف الكاملالوصف الاختياري الطويل للبث. %1$s متوفر. يجب أن لا يتجاوز طول النص %2$s حرفاً.
+ رابط مصدر PGNURL الذي سيتحقق منه Lichess للحصول على تحديثات PGN. يجب أن يكون متاحًا للجميع على الإنترنت.
+ حتى 64 معرف لُعْبَة ليتشيس، مفصولة بمسافات.تاريخ البدء في المنطقة الزمنية الخاصة بكاختياري، إذا كنت تعرف متى يبدأ الحدثائتمن المصدر
- رابط البث
- رابط الجولة الحاليةرابط المباراة الحاليةتحميل جميع المبارياتإعادة ضبط هذه الجولة
diff --git a/translation/dest/broadcast/az-AZ.xml b/translation/dest/broadcast/az-AZ.xml
index d02db396eec5b..b591255097c86 100644
--- a/translation/dest/broadcast/az-AZ.xml
+++ b/translation/dest/broadcast/az-AZ.xml
@@ -17,8 +17,6 @@
Öz saat qurşağınızdakı başlama tarixiİstəyə bağlı, tədbirin başlama vaxtını bilirsinizsəMənbəyə bax
- Yayım URL-i
- Hazırkı tur URL-iHazırkı oyun URL-iBu turu sıfırlaBu turu sil
diff --git a/translation/dest/broadcast/be-BY.xml b/translation/dest/broadcast/be-BY.xml
index 75968908b127e..832821c0fb46d 100644
--- a/translation/dest/broadcast/be-BY.xml
+++ b/translation/dest/broadcast/be-BY.xml
@@ -20,8 +20,6 @@
Дата пачатаку ў вашым часавым поясеПа жаданні, калі вы ведаеце пачатак падзеіПадзякаваць крыніцы
- Спасылка на трансляцыю
- Спасылка на бягучы турСпасылка на бягучую гульнюСпампаваць усе турыСкасаваць гэты тур
diff --git a/translation/dest/broadcast/bg-BG.xml b/translation/dest/broadcast/bg-BG.xml
index 87a40894b8942..fdb21fb10a49e 100644
--- a/translation/dest/broadcast/bg-BG.xml
+++ b/translation/dest/broadcast/bg-BG.xml
@@ -23,8 +23,6 @@
Дата на започване във вашата часова зонаПо избор, ако знаете, кога започва събитиетоПризнателност на източника
- URL на предаването
- URL на настоящия гундURL на настоящата партияИзтегли всички рундовеНулирай този рунд
@@ -34,4 +32,7 @@
Изтрий този турнирОкончателно изтрий целия турнир, всичките му рундове и игри.По избор: промени имената на играчите, рейтингите и титлите
+ ФИДЕ федерации
+ ФИДЕ профил
+ Федерация
diff --git a/translation/dest/broadcast/bs-BA.xml b/translation/dest/broadcast/bs-BA.xml
index 7d537e804b639..cc667e6c3a81f 100644
--- a/translation/dest/broadcast/bs-BA.xml
+++ b/translation/dest/broadcast/bs-BA.xml
@@ -23,8 +23,6 @@
Datum početka po Vašoj vremenskoj zoniNeobavezno, ukoliko znate kada počinje događajNavedite ko je zaslužan
- Link za prenos
- Link za trenutno koloLink za trenutnu partijuSkinite sve rundePonovo postavite ovo kolo
diff --git a/translation/dest/broadcast/ca-ES.xml b/translation/dest/broadcast/ca-ES.xml
index a57524541db57..57e70c2dbd9cc 100644
--- a/translation/dest/broadcast/ca-ES.xml
+++ b/translation/dest/broadcast/ca-ES.xml
@@ -23,12 +23,12 @@
Breu descripció del torneigDescripció total de l\'esdevenimentOpció de llarga descripció de l\'esdeveniment. %1$s és disponible. Ha de tenir menys de %2$s lletres.
+ URL origen del PGNURL que Lichess comprovarà per a obtenir actualitzacions PGN. Ha de ser públicament accessible des d\'Internet.
+ Fins a 64 identificadors de partides de Lichess, separades per espais.Data d\'inici en la teva zona horàriaOpcional, si saps quan comença l\'esdevenimentCita la font
- URL d\'emissió
- URL actual de rondaURL actual de jocBaixa totes les rondesRestablir aquesta ronda
@@ -43,4 +43,13 @@
Opcional: Reemplaça noms dels jugadors, puntuacions i títolsPeríode en segonsOpcional, quant de temps esperar entre sol·licituds. Mínim 2 segons, màxim 60 segons. Per defecte es gestiona automàticament en funció del nombre de visualitzadors.
+ Federacions FIDE
+ Top 10 Ràting
+ Jugadors FIDE
+ No s\'ha trobat el jugador FIDE
+ Perfil FIDE
+ Federació
+ Edat aquest any
+ Sense avaluació
+ Tornejos recents
diff --git a/translation/dest/broadcast/ckb-IR.xml b/translation/dest/broadcast/ckb-IR.xml
index 5fca9553a022d..533a78190b0b6 100644
--- a/translation/dest/broadcast/ckb-IR.xml
+++ b/translation/dest/broadcast/ckb-IR.xml
@@ -25,8 +25,6 @@
بەرواری دەستپێکردن لە چوارچێوەی کاتی خۆتدابە ھەلبژاردنی خۆتە چ کاتێک دەس پێ بکاتلە سەرچاوەکە دڵنیابە
- لینکی پالەوانێتیەکە
- لینکی خولی یەکەملینکی یاریەکانی ئێستادابەزاندنی ھەموو خولەکاندەسکاری کردنی ئەم خولە
@@ -37,4 +35,13 @@
ئەم پاڵەوانێتییە بسڕەوەبە دڵنیاییەوە تەواوی پاڵەوانێتییەکە و هەموو خولەکانی و هەموو یارییەکانی بسڕەوە.ئارەزوومەندانە: گۆڕینی ناوی یاریزانان، هەڵسەنگاندن و نازناوەکان
+ فیدراسیۆنی FIDE
+ ڕیزبەندی ١٠ باشترینەکان
+ یاریزانەکانی FIDE
+ یاریزانی FIDE نەدۆزرایەوە
+ پرۆفایلی FIDE
+ فیدراسیۆن
+ تەمەنی ئەمساڵ
+ ڕیزبەندی نەکراوە
+ پاڵەوانێتییەکانی ئەم دواییە
diff --git a/translation/dest/broadcast/cs-CZ.xml b/translation/dest/broadcast/cs-CZ.xml
index 5827af04c0b2e..b415a32e290af 100644
--- a/translation/dest/broadcast/cs-CZ.xml
+++ b/translation/dest/broadcast/cs-CZ.xml
@@ -28,8 +28,6 @@
Datum a čas zahájení ve vašem časovém pásmuNepovinné, pokud víte, kdy událost začínáUveďte zdroj
- URL adresa přenosu
- URL aktuálního kolaURL adresa právě probíhající partieStáhnout hry ze všech kolResetovat toto kolo
diff --git a/translation/dest/broadcast/da-DK.xml b/translation/dest/broadcast/da-DK.xml
index 9214e24fc7640..8791b6cbc953c 100644
--- a/translation/dest/broadcast/da-DK.xml
+++ b/translation/dest/broadcast/da-DK.xml
@@ -23,14 +23,12 @@
Kort beskrivelse af turneringFuld beskrivelse af begivenhedenValgfri lang beskrivelse af transmissionen. %1$s er tilgængelig. Længde skal være mindre end %2$s tegn.
- URL for PGN-kilde
+ URL for PGN-kildeURL som Lichess vil trække på for at få PGN updates. Den skal være offentlig tilgængelig fra internettet.Op til 64 Lichess parti-ID\'er, adskilt af mellemrum.Startdato i din egen tidszoneValgfri, hvis du ved, hvornår begivenheden starterKrediter kilden
- Udsendelse-URL
- Nuværende runde URLNuværende parti URLDownload alle runderNulstil denne runde
@@ -45,4 +43,13 @@
Valgfrit: udskift spillernavne, ratings og titlerPeriode i sekunderValgfri, hvor lang tid der skal ventes mellem anmodninger. Min 2s, maks. 60s. Er som standard automatisk baseret på antallet af seere.
+ FIDE-føderationer
+ Top 10 rating
+ FIDE-spillere
+ FIDE-spiller ikke fundet
+ FIDE-profil
+ Føderation
+ Alder i år
+ Uden rating
+ Seneste turneringer
diff --git a/translation/dest/broadcast/de-DE.xml b/translation/dest/broadcast/de-DE.xml
index 54fcd97d89d31..8582eff0c95ab 100644
--- a/translation/dest/broadcast/de-DE.xml
+++ b/translation/dest/broadcast/de-DE.xml
@@ -23,14 +23,12 @@
Kurze TurnierbeschreibungVollständige EreignisbeschreibungOptionale, ausführliche Beschreibung der Übertragung. %1$s ist verfügbar. Die Beschreibung muss kürzer als %2$s Zeichen sein.
- PGN Quell-URL
+ PGN Quell-URLURL die Lichess abfragt um PGN Aktualisierungen zu erhalten. Sie muss öffentlich aus dem Internet zugänglich sein.Bis zu 64 Lichess Partie-IDs, getrennt durch Leerzeichen.Startdatum in deiner eigenen ZeitzoneOptional, falls du weißt wann das Ereignis beginntErwähne die Quelle
- URL der Übertragung
- URL der aktuellen RundeURL der aktuellen PartieAlle Runden herunterladenDiese Runde zurücksetzen
@@ -45,4 +43,13 @@
Optional: Spielernamen, Wertungen und Titel ersetzenDauer in SekundenOptional, wie lange zwischen den Anfragen gewartet werden soll. Mindestens 2s, maximal 60s. Standardmäßig auf der Zuschaueranzahl basierend.
+ FIDE-Verbände
+ Top 10 Wertung
+ FIDE-Spieler
+ FIDE-Spieler nicht gefunden
+ FIDE-Profil
+ Verband
+ Alter in diesem Jahr
+ Ungewertet
+ Letzte Turniere
diff --git a/translation/dest/broadcast/el-GR.xml b/translation/dest/broadcast/el-GR.xml
index 5aeb0c835599f..d16573b6a01c9 100644
--- a/translation/dest/broadcast/el-GR.xml
+++ b/translation/dest/broadcast/el-GR.xml
@@ -26,8 +26,6 @@
Ημερομηνία έναρξης στη δική σας ζώνη ώραςΠροαιρετικό, εάν γνωρίζετε πότε αρχίζει η εκδήλωσηΑναφέρετε την πηγή
- Διεύθυνση URL μετάδοσης
- Διεύθυνση URL αυτού του γύρουΔιεύθυνση URL αυτού του παιχνιδιούΛήψη όλων των γύρωνΕπαναφορά αυτού του γύρου
@@ -37,4 +35,11 @@
Επεξεργασία μελέτης γύρουΔιαγραφή αυτού του τουρνουάΣίγουρα διαγράψτε ολόκληρο τον διαγωνισμό, όλους τους γύρους του και όλα τα παιχνίδια του.
+ Ομοσπονδίες FIDE
+ Παίκτες FIDE
+ Δε βρέθηκε παίκτης FIDE
+ Προφίλ FIDE
+ Ομοσπονδία
+ Φετινή ηλικία
+ Πρόσφατα τουρνουά
diff --git a/translation/dest/broadcast/en-US.xml b/translation/dest/broadcast/en-US.xml
index 449b09b6167d1..c969a0d18f7bd 100644
--- a/translation/dest/broadcast/en-US.xml
+++ b/translation/dest/broadcast/en-US.xml
@@ -23,14 +23,12 @@
Short tournament descriptionFull event descriptionOptional long description of the broadcast. %1$s is available. Length must be less than %2$s characters.
- PGN Source URL
+ PGN Source URLURL that Lichess will check to get PGN updates. It must be publicly accessible from the Internet.Up to 64 Lichess game IDs, separated by spaces.Start date in your own timezoneOptional, if you know when the event startsCredit the source
- Broadcast URL
- Current round URLCurrent game URLDownload all roundsReset this round
@@ -45,4 +43,13 @@
Optional: replace player names, ratings and titlesPeriod in secondsOptional, how long to wait between requests. Min 2s, max 60s. Defaults to automatic based on the number of viewers.
+ FIDE federations
+ Top 10 rating
+ FIDE players
+ FIDE player not found
+ FIDE profile
+ Federation
+ Age this year
+ Unrated
+ Recent tournaments
diff --git a/translation/dest/broadcast/eo-UY.xml b/translation/dest/broadcast/eo-UY.xml
index ff7c8046daf57..977be04ab97ab 100644
--- a/translation/dest/broadcast/eo-UY.xml
+++ b/translation/dest/broadcast/eo-UY.xml
@@ -27,8 +27,6 @@
Komenca dato en via propra horzonoLaŭvola, se vi scias, kiam komenciĝas la eventoCitu la fonton
- Elsenda URL
- Nuna raŭnda URLNuna luda URLElŝuti ĉiujn raŭndojnRestarigi ĉi tiun raŭndon
diff --git a/translation/dest/broadcast/es-ES.xml b/translation/dest/broadcast/es-ES.xml
index 715a6e1f9aada..465fe239f8522 100644
--- a/translation/dest/broadcast/es-ES.xml
+++ b/translation/dest/broadcast/es-ES.xml
@@ -23,14 +23,12 @@
Breve descripción del torneoDescripción completa del eventoDescripción larga opcional de la emisión. %1$s está disponible. La longitud debe ser inferior a %2$s caracteres.
- URL origen del archivo PGN
+ URL origen del archivo PGNURL que Lichess comprobará para obtener actualizaciones PGN. Debe ser públicamente accesible desde Internet.Hasta 64 identificadores de partidas de Lichess, separados por espacios.Fecha de inicio en tu zona horariaOpcional, si sabes cuando comienza el eventoCita la fuente
- Enlace de la emisión
- Enlace de la ronda actualEnlace de la partida actualDescargar todas las rondasRestablecer esta ronda
@@ -45,4 +43,13 @@
Opcional: reemplazar nombres de jugadores, puntuaciones y títulosPeríodo en segundosOpcional, cuánto tiempo esperar entre peticiones. Mín. 2 s., máx. 60 s. Por defecto es automático según el número de espectadores.
+ Federaciones FIDE
+ Los 10 mejores
+ Jugadores FIDE
+ Jugador FIDE no encontrado
+ Perfil FIDE
+ Federación
+ Edad actual
+ Sin puntuación
+ Torneos recientes
diff --git a/translation/dest/broadcast/et-EE.xml b/translation/dest/broadcast/et-EE.xml
index 46a035083600f..64e4f4d38d700 100644
--- a/translation/dest/broadcast/et-EE.xml
+++ b/translation/dest/broadcast/et-EE.xml
@@ -17,8 +17,6 @@
Alguskuupäev sinu ajavööndisValikuline, kui tead millal sündmus algabViita allikale
- Otseülekande URL
- Preaguse vooru URLPraeguse mängu URLLae alla kõik voorudLähtesta see voor
diff --git a/translation/dest/broadcast/eu-ES.xml b/translation/dest/broadcast/eu-ES.xml
index e4e2a834d6743..6c4e49ebd18a0 100644
--- a/translation/dest/broadcast/eu-ES.xml
+++ b/translation/dest/broadcast/eu-ES.xml
@@ -27,8 +27,6 @@
Zure ordu-zonako hasiera dataHautazkoa, ekitaldia noiz hasten den baldin badakizuJatorria zein den esaiguzu
- Zuzeneko emankizunaren URL helbidea
- Uneko txandaren URL helbideaUneko partidaren URL helbideaDeskargatu txanda guztiakBerrezarri txanda hau
diff --git a/translation/dest/broadcast/fa-IR.xml b/translation/dest/broadcast/fa-IR.xml
index 9c0bb795b9ed1..1d222de5fb759 100644
--- a/translation/dest/broadcast/fa-IR.xml
+++ b/translation/dest/broadcast/fa-IR.xml
@@ -23,13 +23,12 @@
توضیحات کوتاه مسابقاتتوضیحات کامل مسابقاتتوضیحات بلند و اختیاری پخش همگانی. %1$s قابلاستفاده است. طول متن باید کمتر از %2$s نویسه باشد.
+ وبنشانیِ PGNوبنشانیای که Lichess برای دریافت بهروزرسانیهای PGN میبررسد. آن باید از راه اینترنت در دسترس همگان باشد.
- تا ۶۴ نشانه بازی لیچس٬ جداشده با فاصله.
+ تا ۶۴ شناسه بازی لیچس٬ جداشده با فاصله.تاریخ شروع، در منطقه زمانی خودتاناختیاری است، اگر میدانید چه زمانی رویداد شروع میشودبه منبع اعتبار دهید
- وبنشانی پخش همگانی
- نشانی دور کنونینشانی بازی کنونیبارگیری همه دورهاازنوکردن این دور
@@ -44,4 +43,13 @@
اختیاری: عوض کردن نام، درجهبندی و عنوان بازیکنانمدت در واحد ثانیهاختیاری است، چه مدت باید بین درخواستها صبر کرد. حداقل 2 ثانیه، حداکثر 60 ثانیه. بر اساس تعداد بینندگان، پیشفرضها، به صورت خودکار مقدار میگیرند.
+ کشورگانهای فیده
+ ده درجهبندی برتر
+ بازیکنان فیده
+ بازیکن فیده پیدا نشد
+ رُخنمای فیده
+ کشورگان
+ سنِ امسال
+ بیدرجهبندی
+ مسابقاتِ اخیر
diff --git a/translation/dest/broadcast/fi-FI.xml b/translation/dest/broadcast/fi-FI.xml
index 6e54bd3b0bdf1..6ac87f8237923 100644
--- a/translation/dest/broadcast/fi-FI.xml
+++ b/translation/dest/broadcast/fi-FI.xml
@@ -23,14 +23,12 @@
Turnauksen lyhyt kuvausTäysimittainen kuvaus tapahtumastaEi-pakollinen pitkä kuvaus lähetyksestä. %1$s-muotoiluja voi käyttää. Pituus voi olla enintään %2$s merkkiä.
- PGN:n lähde-URL
+ PGN:n lähde-URLURL, josta Lichess hakee PGN-päivitykset. Sen täytyy olla julkisesti saatavilla internetissä.Korkeintaan 64 Lichess-pelin tunnistenumeroa välilyönneillä eroteltuna.Alkamispäivämäärä omalla aikavyöhykkeelläsiEi-pakollinen, laita jos tiedät milloin tapahtuma alkaaMainitse lähde
- Lähetyksen URL
- Tämän kierroksen URLTämän pelin URLLataa kaikki kierroksetNollaa tämä kierros
@@ -45,4 +43,12 @@
Valinnainen: korvaa pelaajien nimet, vahvuusluvut ja arvonimetJakso sekunteinaTarvittaessa pyyntöjen välinen odotusaika: vähintään 2 s, enintään 60 s. Oletuksena on katsojien määrään perustuva automaattinen arvo.
+ FIDEn liitot
+ Top 10 -vahvuuslukulista
+ FIDE-pelaajat
+ FIDE-pelaajaa ei löytynyt
+ FIDE-profiili
+ Kansallinen liitto
+ Ikä tänä vuonna
+ Viimeisimmät turnaukset
diff --git a/translation/dest/broadcast/fr-FR.xml b/translation/dest/broadcast/fr-FR.xml
index 49a3ee11bde87..c6696c5e26ca5 100644
--- a/translation/dest/broadcast/fr-FR.xml
+++ b/translation/dest/broadcast/fr-FR.xml
@@ -23,14 +23,12 @@
Brève description du tournoiDescription complète de l\'événementDescription détaillée et optionnelle de la diffusion. %1$s est disponible. La longueur doit être inférieure à %2$s caractères.
- URL source de la partie en PGN
+ URL source de la partie en PGNURL que Lichess interrogera pour obtenir les mises à jour du PGN. Elle doit être accessible publiquement depuis Internet.Jusqu\'à 64 ID de partie Lichess séparés par des espaces.Date de début dans votre fuseau horaireFacultatif, si vous savez quand l\'événement commenceCréditer la source
- URL de diffusion
- Ronde actuelleURL de la partie en coursTélécharger toutes les rondesRéinitialiser cette ronde
@@ -45,4 +43,13 @@
Facultatif : remplacer les noms des joueurs, les classements et les titresPériode en secondesFacultatif : temps d\'attente entre les requêtes. Min. 2 sec, max. 60 sec. Par défaut automatique selon le nombre de spectateurs.
+ Fédérations FIDE
+ 10 plus hauts classements
+ Joueurs FIDE
+ Joueur FIDE introuvable
+ Profil FIDE
+ Fédération
+ Âge cette année
+ Non classé
+ Tournois récents
diff --git a/translation/dest/broadcast/ga-IE.xml b/translation/dest/broadcast/ga-IE.xml
index 97bab1791832e..38356993f0fee 100644
--- a/translation/dest/broadcast/ga-IE.xml
+++ b/translation/dest/broadcast/ga-IE.xml
@@ -17,8 +17,6 @@
Dáta tosaigh i do chrios ama féinRoghnach, má tá a fhios agat cathain a thosóidh an ócáidCreidmheas an fhoinse
- Craoladh URL
- URL babhta reathaURL cluiche reathaÍoslódáil gach babhtaAthshocraigh an babhta seo
diff --git a/translation/dest/broadcast/gl-ES.xml b/translation/dest/broadcast/gl-ES.xml
index 4852c77cbf46b..f5b6fa6af0ba6 100644
--- a/translation/dest/broadcast/gl-ES.xml
+++ b/translation/dest/broadcast/gl-ES.xml
@@ -16,21 +16,19 @@
En cursoProximamenteCompletadas
- Lichess detecta o final das roldas en función das partidas de orixe. Usa esta opción se non hai orixe.
+ Malia que Lichess detecta o final das roldas, pódese equivocar. Usa esta opción para facelo manualmente.Nome da roldaNúmero de roldaNome do torneoBreve descrición do torneoDescrición completa do eventoDescrición longa opcional da retransmisión. %1$s está dispoñíbel. A lonxitude debe ser menor de %2$s caracteres.
- URL de orixe do arquivo PGN
+ URL de orixe do arquivo PGNLigazón que Lichess comprobará para obter actualizacións dos PGN. Debe ser publicamente accesíbel desde a Internet.Até 64 identificadores de partidas de Lichess, separados por espazos.Data de inicio na túa zona horariaOpcional, se sabes cando comeza o eventoCita a fonte
- Ligazón da transmisión
- Ligazón da rolda actualLigazón da partida actualDescargar todas as roldasRestablecer esta rolda
@@ -45,4 +43,13 @@
Opcional: substituír os nomes dos xogadores, as puntuacións e os títulosPeríodo en segundosOpcional: canto tempo se agarda entre peticións. Min 2s, max 60s. Por defecto é automático baseado no número de espectadores.
+ Federacións FIDE
+ Media do top 10
+ Xogadores FIDE
+ Xogador FIDE non atopado
+ Perfil FIDE
+ Federación
+ Idade actual
+ Sen puntuar
+ Torneos recentes
diff --git a/translation/dest/broadcast/gsw-CH.xml b/translation/dest/broadcast/gsw-CH.xml
index 7a3b2f16d796b..b868614360d4f 100644
--- a/translation/dest/broadcast/gsw-CH.xml
+++ b/translation/dest/broadcast/gsw-CH.xml
@@ -23,12 +23,12 @@
Churzi Turnier BeschribigVollschtändigi EreignisbeschribigOptionali, usfüehrlichi Beschribig vu de Überträgig. %1$s isch verfügbar. Die Beschribig muess chürzer als %2$s Zeiche si.
+ PGN Quälle URLURL wo Lichess abfrögt, für PGN Aktualisierige z\'erhalte. Sie muess öffentlich im Internet zuegänglich si.
+ Bis zu 64 Lichess Partie - IDs, trännt dur en Leerschlag.Startdatum in dinere eigene ZitzoneOptional, falls du weisch, wänn das Ereignis afangtErwähn die Quälle
- Überträgigs-URL
- URL vode laufende RundiURL vode laufende PartieAlli Runde abeladeDie Rundi zruggsetze
@@ -43,4 +43,13 @@
Optional: Schpillernäme, Wertige und Titel weg lahPeriode i SekundeOptional, wie lang zwüsche Afrage gwartet werden söll. Minimal 2, maximal 60 Sekunde. Die Standardischtellig isch automatisch, basierend uf der Azahl vu de Zueschauer.
+ FIDE Wältschachverband
+ Top 10 Ratings
+ FIDE Schpiller
+ FIDE Schpiller nöd g\'funde
+ FIDE Profil
+ Verband
+ Alter i dem Jahr
+ Ungwertet
+ Aktuellschti Turnier
diff --git a/translation/dest/broadcast/he-IL.xml b/translation/dest/broadcast/he-IL.xml
index f938cd4c992a4..ae6cda1b66287 100644
--- a/translation/dest/broadcast/he-IL.xml
+++ b/translation/dest/broadcast/he-IL.xml
@@ -12,27 +12,25 @@
הקרנה ישירה חדשההקרנות שנרשמת אליהןהסבר על הקרנות
- איך להשתמש בהקרנות ב-Lichess.
+ איך להשתמש בהקרנות ב־Lichess.הסבב החדש יכלול את אותם התורמים והחברים כמו בסבב הקודם.הוספת סבבכרגעבקרובשהושלמו
- ליצ׳ס מאתר מתי הושלם הסבב על פי המשחקים שבקישור למהלכים בשידור חי (המקור). הפעילו את האפשרות הזאת אם אין מקור שממנו נשאבים המשחקים.
+ Lichess מאתר מתי הושלם הסבב על פי המשחקים שבקישור למהלכים בשידור חי (המקור). הפעילו את האפשרות הזאת אם אין מקור שממנו נשאבים המשחקים.שם סבבמספר סבבשם הטורנירתיאור הטורניר בקצרהתיאור מלא של הטורנירתיאור מפורט של הטורניר (אופציונאלי). %1$s זמין. אורך התיאור לא יעלה על %2$s תווים.
- קישור המקור של ה-PGN
- הקישור ש־Lichess יבדוק כדי לקלוט עדכונים ב-PGN. הוא חייב להיות פומבי ונגיש דרך האינטרנט.
+ קישור המקור של ה־PGN
+ הקישור ש־Lichess יבדוק כדי לקלוט עדכונים ב־PGN. הוא חייב להיות פומבי ונגיש דרך האינטרנט.עד 64 מזהי משחק של Lichess, מופרדים ברווחים.תאריך ההתחלה באזור הזמן שלךאופציונאלי, אם את/ה יודע/ת מתי האירוע צפוי להתחילתן/י קרדיט למקור
- הקישור להקרנה
- הקישור לסבב הנוכחיהקישור למשחק הנוכחיהורדת כל הסבביםאפס את הסיבוב הזה
@@ -46,5 +44,14 @@
הצגת טבלה פשוטה שמתבססת על תוצאות המשחקיםאופציונאלי: החלפה של שמות השחקנים, דירוגיהם ותאריהםתדירות בשניות
- אופציונאלי. משפיע על משך הזמן שעובר בין משיכות הנתונים מהמקור. בין 2 ל-60 שניות. כתלות במספר הצופים, הקצב עשוי לחזור לברירת המחדל.
+ אופציונאלי. משפיע על משך הזמן שעובר בין משיכות הנתונים מהמקור. בין 2 ל־60 שניות. כתלות במספר הצופים, הקצב עשוי לחזור לברירת המחדל.
+ איגודי FIDE
+ דירוג עשרת המובילים
+ שחקני FIDE
+ לא נמצא שחקן FIDE
+ פרופיל FIDE
+ איגוד
+ גיל השנה
+ לא מדורג
+ טורנירים אחרונים
diff --git a/translation/dest/broadcast/hi-IN.xml b/translation/dest/broadcast/hi-IN.xml
index d27142de5a14f..e87b3901e3a12 100644
--- a/translation/dest/broadcast/hi-IN.xml
+++ b/translation/dest/broadcast/hi-IN.xml
@@ -22,8 +22,6 @@
अपने स्वयं के समयक्षेत्र में प्रारंभ दिनांकवैकल्पिक, यदि आप जानना चाहते हो की प्रतिस्प्रधा कब शुरू होगीस्रोत को श्रेय दें
- प्रसारण की कड़ी
- वर्तमान अध्याय URLवर्तमान अध्याय URLसभी राउंड डाउनलोड करेंइस फॉर्म को रीसेट करें
diff --git a/translation/dest/broadcast/hr-HR.xml b/translation/dest/broadcast/hr-HR.xml
index 5a8a5071df827..e41927412f7fb 100644
--- a/translation/dest/broadcast/hr-HR.xml
+++ b/translation/dest/broadcast/hr-HR.xml
@@ -22,8 +22,6 @@
Datum početka u vlastitoj vremenskoj zoniNeobavezno, ako znaš kada događaj počinjeNaglasi izvor
- Emitiraj URL
- URL trenutne rundeURL trenutne igrePreuzmite sve igreResetiraj ovu rundu
diff --git a/translation/dest/broadcast/hu-HU.xml b/translation/dest/broadcast/hu-HU.xml
index d0adfb37758bc..20d429283f462 100644
--- a/translation/dest/broadcast/hu-HU.xml
+++ b/translation/dest/broadcast/hu-HU.xml
@@ -21,8 +21,6 @@
Kezdés időpontja a saját időzónádbanOpcionális, ha tudod mikor kezdődik az eseményForrásmegjelölés
- Közvetítés URL
- Jelenlegi forduló URLJelenlegi játszma URLÖsszes játszma letöltéseA forduló újrakezdése
diff --git a/translation/dest/broadcast/hy-AM.xml b/translation/dest/broadcast/hy-AM.xml
index 16be2356bdea2..71757a855652e 100644
--- a/translation/dest/broadcast/hy-AM.xml
+++ b/translation/dest/broadcast/hy-AM.xml
@@ -17,8 +17,6 @@
Սկսվելու ամսաթիվը Ձեր ժամագոտումԼրացուցիչ, եթե գիտեք, թե երբ է սկսվելու իրադարձությունըԵրախտագիտություն
- Հեռարձակման URL-հասցեն
- Ընթացիկ խաղափուլի URL-հասցենԸնթացիկ պարտիայի URL-հասցենԲեռնել բոլոր խաղափուլերըՀեռացնել այս խաղափուլը
diff --git a/translation/dest/broadcast/id-ID.xml b/translation/dest/broadcast/id-ID.xml
index 80fb0440c0161..d91125b65a363 100644
--- a/translation/dest/broadcast/id-ID.xml
+++ b/translation/dest/broadcast/id-ID.xml
@@ -17,8 +17,6 @@
Tanggal mulai di zona waktu Anda sendiriOpsional, jika Anda tahu kapan acara dimulaiSertakan sumber
- Tautan siaran
- Tautan ronde iniTautan permainan iniUnduh semua rondeAtur ulang ronde ini
diff --git a/translation/dest/broadcast/it-IT.xml b/translation/dest/broadcast/it-IT.xml
index adc748be56885..8d54528c4721d 100644
--- a/translation/dest/broadcast/it-IT.xml
+++ b/translation/dest/broadcast/it-IT.xml
@@ -27,8 +27,6 @@
Data di inizio nel tuo fuso orarioFacoltativo, se sai quando inizia l\'eventoCita la fonte
- URL della diretta
- URL del turno correnteURL della partita correnteScarica tutti i roundReimposta questo turno
diff --git a/translation/dest/broadcast/ja-JP.xml b/translation/dest/broadcast/ja-JP.xml
index 53bdbd425abe8..b45c916f4d6b9 100644
--- a/translation/dest/broadcast/ja-JP.xml
+++ b/translation/dest/broadcast/ja-JP.xml
@@ -22,12 +22,12 @@
大会の短い説明長い説明内容の詳しい説明(オプション)。%1$s が利用できます。長さは [欧文換算で] %2$s 字まで。
+ PGN のソース URLLichess が PGN を取得するための URL。インターネット上に公表されているもののみ。
+ Lichess ゲーム ID、半角スペースで区切って最大 64 個まで。開始日付(あなたの現地時間)イベント開始時刻(オプション)ソースを表示する
- ブロードキャスト URL
- 現在のラウンドの URL現在のゲームの URL全ラウンドをダウンロードこのラウンドをリセット
@@ -42,4 +42,13 @@
オプション:プレイヤーの名前、レーティング、タイトルの変更待機時間(秒)オプション、次のリクエストまでの待機時間を指定。最小 2 秒、最大 60 秒。デフォルト値は視聴者数から自動的に決まります。
+ FIDE 加盟協会
+ レーティング トップ10
+ FIDE 選手
+ FIDE 選手が見つかりません
+ FIDE プロフィール
+ 所属協会
+ 今年時点の年齢
+ レーティングなし
+ 最近のトーナメント
diff --git a/translation/dest/broadcast/ka-GE.xml b/translation/dest/broadcast/ka-GE.xml
index d5b948037c1d6..09f32253cc559 100644
--- a/translation/dest/broadcast/ka-GE.xml
+++ b/translation/dest/broadcast/ka-GE.xml
@@ -12,8 +12,6 @@
შეჯიბრის სახელიტურნირი მცირე აღწერატურნირის სრული აღწერა
- გადაცემის URL
- მიმდინარე ტურის URLმიმდინარე პარტიის URLჩამოტვირთე ყველა ტურიგადატვირთე ეს ტური
diff --git a/translation/dest/broadcast/kaa-UZ.xml b/translation/dest/broadcast/kaa-UZ.xml
index e1e3345d0d14c..382aecc290122 100644
--- a/translation/dest/broadcast/kaa-UZ.xml
+++ b/translation/dest/broadcast/kaa-UZ.xml
@@ -12,8 +12,6 @@
Turnir atamasıTurnirdiń qısqasha táriypiTurnirdiń tolıq táriypi
- Esittiriwdiń URL mánzili
- Házirgi tur URL mánziliHázirgi oyın URL mánziliBarlıq turlardı júklep alıwBul turdı qayta ornatıw
diff --git a/translation/dest/broadcast/kk-KZ.xml b/translation/dest/broadcast/kk-KZ.xml
index 6406d3b24d3af..4813e2cfc3638 100644
--- a/translation/dest/broadcast/kk-KZ.xml
+++ b/translation/dest/broadcast/kk-KZ.xml
@@ -22,8 +22,6 @@
Басталу күні (өз уақыт белдеуіңізде)Міндетті емес, егер күнін біліп тұрсаңызҚайнар көзіне сілтеңіз
- Көрсетілім сілтемесі
- Қазіргі айналым сілтемесіҚазіргі ойын сілтемесіБарлық айналымдарды жүктеп алуБұл айналымды жаңарту
diff --git a/translation/dest/broadcast/kmr-TR.xml b/translation/dest/broadcast/kmr-TR.xml
index 830f1b58748e0..537cdca056584 100644
--- a/translation/dest/broadcast/kmr-TR.xml
+++ b/translation/dest/broadcast/kmr-TR.xml
@@ -11,8 +11,6 @@
Hejmara roundêNavê pêşbirkêBi kurtasî di derbqrê pêşbirkî da
- Lînka Weşanê
- Lînka raundê nihaLînka lîstika nihaVî raundî bîne serîVî raundî jê bibe
diff --git a/translation/dest/broadcast/kn-IN.xml b/translation/dest/broadcast/kn-IN.xml
index 132a6c33e8ba4..b661fc44ca339 100644
--- a/translation/dest/broadcast/kn-IN.xml
+++ b/translation/dest/broadcast/kn-IN.xml
@@ -21,8 +21,6 @@
ನಿಮ್ಮ ಸ್ವಂತ ಸಮಯವಲಯದಲ್ಲಿ ದಿನಾಂಕವನ್ನು ಪ್ರಾರಂಭಿಸಿಐಚ್ಛಿಕ, ಈವೆಂಟ್ ಯಾವಾಗ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ ಎಂದು ನಿಮಗೆ ತಿಳಿದಿದ್ದರೆಮೂಲವನ್ನು ಕ್ರೆಡಿಟ್ ಮಾಡಿ
- URL ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿ
- ಪ್ರಸ್ತುತ ಸುತ್ತಿನ URLಪ್ರಸ್ತುತ ಆಟದ URLಎಲ್ಲಾ ಸುತ್ತುಗಳನ್ನು ಡೌನ್ಲೋಡ್ ಮಾಡಿಈ ಸುತ್ತನ್ನು ಮರುಹೊಂದಿಸಿ
diff --git a/translation/dest/broadcast/ko-KR.xml b/translation/dest/broadcast/ko-KR.xml
index 162ee9fefe881..78dcdf8131b66 100644
--- a/translation/dest/broadcast/ko-KR.xml
+++ b/translation/dest/broadcast/ko-KR.xml
@@ -24,8 +24,6 @@
본인 시간대 기준 시작일선택사항. 언제 이벤트가 시작되는지 알고 있는 경우출처
- 방송 URL
- 현재 라운드 URL현재 게임 URL모든 라운드 다운로드이 라운드 초기화
diff --git a/translation/dest/broadcast/lb-LU.xml b/translation/dest/broadcast/lb-LU.xml
index fe30e6accdee3..4de7ba194bd4a 100644
--- a/translation/dest/broadcast/lb-LU.xml
+++ b/translation/dest/broadcast/lb-LU.xml
@@ -18,11 +18,10 @@
Komplett TurnéierbeschreiwungOptional laang Beschreiwung vum Turnéier. %1$s ass disponibel. Längt muss manner wéi %2$s Buschtawen sinn.URL déi Lichess checkt fir PGN à jour ze halen. Muss ëffentlech iwwer Internet zougänglech sinn.
+ Bis zu 64 Lichess-Partie-IDen, duerch Espacë getrennt.Startdatum an denger eegener ZäitzonOptional, wann du wees wéini den Turnéier ufänktQuell kreditéieren
- Iwwerdroungs-URL
- URL vun der aktueller RonnURL vun der aktueller PartieAll Ronnen erofluedenRonn zerécksetzen
@@ -34,4 +33,12 @@
De ganzen Turnéier definitiv läschen, all seng Ronnen an all seng Partien.Optional: Spillernimm, Wäertungen an Titelen ersetzenPeriod a Sekonnen
+ FIDE-Federatiounen
+ FIDE-Spiller
+ FIDE-Spiller net tfonnt
+ FIDE-Profil
+ Federatioun
+ Alter dëst Joer
+ Ongewäert
+ Rezent Turnéieren
diff --git a/translation/dest/broadcast/lt-LT.xml b/translation/dest/broadcast/lt-LT.xml
index c4c5fcdf314cb..bc65f2322cfc1 100644
--- a/translation/dest/broadcast/lt-LT.xml
+++ b/translation/dest/broadcast/lt-LT.xml
@@ -24,8 +24,6 @@
Pradžios laikas jūsų laiko juostojeNeprivaloma; tik jeigu žinote, kada prasideda renginysPaminėkite šaltinį
- Transliacijos adresas
- Dabartinio raundo adresasDabartinio žaidimo adresasAtsisiųsti visus raundusAtstatyti raundą
diff --git a/translation/dest/broadcast/lv-LV.xml b/translation/dest/broadcast/lv-LV.xml
index 92eac6b60cebb..fa09b699e8597 100644
--- a/translation/dest/broadcast/lv-LV.xml
+++ b/translation/dest/broadcast/lv-LV.xml
@@ -17,8 +17,6 @@
Sākuma datums jūsu laika joslāNeobligāts, ja zināt, kad pasākums sākasKreditējiet avotu
- Tiešraides URL
- Pašreizējā raunda URLPašreizējās spēles URLLejupielādēt visus raundusAtiestatīt šo raundu
diff --git a/translation/dest/broadcast/ml-IN.xml b/translation/dest/broadcast/ml-IN.xml
index aee06d3cc0322..42cd329da8aa3 100644
--- a/translation/dest/broadcast/ml-IN.xml
+++ b/translation/dest/broadcast/ml-IN.xml
@@ -1,6 +1,4 @@
- പ്രക്ഷേപണം ചെയ്യുനതിനുള്ള URL
- നിലവിലെ ഘട്ടത്തിന്റെ URLനിലവിലെ കളിയുടെ URL
diff --git a/translation/dest/broadcast/mr-IN.xml b/translation/dest/broadcast/mr-IN.xml
index 3111fb098a28d..562d8ea38e0d7 100644
--- a/translation/dest/broadcast/mr-IN.xml
+++ b/translation/dest/broadcast/mr-IN.xml
@@ -26,8 +26,6 @@
आपल्या स्वत: च्या टाइमझोनमधील तारीखपर्यायी, इव्हेंट कधी सुरू होतो हे आपल्याला माहिती असल्यासCredit the source
- URL चे प्रसारण
- चालू फेरीचा URLचालू खेळाचा URLसर्व फेऱ्या डाउनलोड कराही फेरी रेसेट करा
diff --git a/translation/dest/broadcast/nb-NO.xml b/translation/dest/broadcast/nb-NO.xml
index 55d652db79fa9..8a03ee7d37fbf 100644
--- a/translation/dest/broadcast/nb-NO.xml
+++ b/translation/dest/broadcast/nb-NO.xml
@@ -23,12 +23,12 @@
Kort beskrivelse av turneringenFull beskrivelse av turneringenValgfri lang beskrivelse av turneringen. %1$s er tilgjengelig. Beskrivelsen må være kortere enn %2$s tegn.
+ URL til PGN-kildenLenke som Lichess vil hente PGN-oppdateringer fra. Den må være offentlig tilgjengelig på internett.
+ Opptil 64 ID-er for partier hos Lichess. De må være adskilt med mellomrom.Startdato i din egen tidssoneValgfritt, hvis du vet når arrangementet starterKrediter kilden
- URL for denne overføringen
- URL for denne rundenURL for dette partietLast ned alle rundeneNullstill denne runden
@@ -43,4 +43,13 @@
Valgfritt: erstatt spillernavn, ratinger og titlerTidsrom i sekunderValgfritt, hvor lenge man skal vente mellom forespørslene. Minst 2 sekunder, maks 60 sekunder. Standardinnstillingen er automatisk basert på antall seere.
+ FIDE-forbund
+ Topp 10 rating
+ FIDE-spillere
+ Fant ikke FIDE-spiller
+ FIDE-profil
+ Forbund
+ Alder i år
+ Uratet
+ Nylige turneringer
diff --git a/translation/dest/broadcast/nl-NL.xml b/translation/dest/broadcast/nl-NL.xml
index 8063d1ddd6a4c..516934639b08b 100644
--- a/translation/dest/broadcast/nl-NL.xml
+++ b/translation/dest/broadcast/nl-NL.xml
@@ -26,8 +26,6 @@
Aanvangsdatum in je eigen tijdzoneOptioneel, als je weet wanneer het evenement startBronvermelding
- Uitzendingslink
- Huidige ronde-linkHuidige partij-linkAlle rondes downloadenDeze ronde opnieuw instellen
@@ -42,4 +40,13 @@
Optioneel: vervang spelersnamen, beoordelingen en titelsPeriode in secondenOptioneel, hoe lang te wachten tussen aanvragen. Minimaal 2 seconden, maximaal 60 seconden. Standaard automatisch gebaseerd op het aantal kijkers.
+ FIDE-federaties
+ Top 10-rating
+ FIDE-spelers
+ FIDE-speler niet gevonden
+ FIDE-profiel
+ Federatie
+ Leeftijd dit jaar
+ Zonder rating
+ Recente toernooien
diff --git a/translation/dest/broadcast/nn-NO.xml b/translation/dest/broadcast/nn-NO.xml
index f73a33756d29b..d262abf44feba 100644
--- a/translation/dest/broadcast/nn-NO.xml
+++ b/translation/dest/broadcast/nn-NO.xml
@@ -23,14 +23,12 @@
Kortfatta skildring av turneringaFull omtale av arrangementetValfri lang omtale av overføringa. %1$s er tilgjengeleg. Omtalen må vera kortare enn %2$s teikn.
- PGN kjelde-URL
+ PGN kjelde-URLLenke som Lichess vil hente PGN-oppdateringar frå. Den må vera offentleg tilgjengeleg på internett.Opp til 64 Lichess spel-ID\'ar, skilde med mellomrom.Startdato i di eiga tidssoneValfritt, om du veit når arrangementet startarKreditér kjelda
- Kunngjerings-URL
- URL til noverande rundeURL til pågåande partiLast ned alle rundeneTilbakestill denne runden
@@ -45,4 +43,13 @@
Valfritt: bytt ut spelarnamn, rangeringar og titlarPeriode i sekundVentetida mellom førespurnadene er valfri frå 2 til 60 sekund. Default tid er basert på sjåartalet.
+ FIDE-forbund
+ Topp 10 rating
+ FIDE-spelarar
+ Fann ikkje FIDE-spelar
+ FIDE-profil
+ Forbund
+ Alder i år
+ Urangert
+ Nylegaste turneringar
diff --git a/translation/dest/broadcast/pl-PL.xml b/translation/dest/broadcast/pl-PL.xml
index 62130d166a1e2..a8b9583e17ad0 100644
--- a/translation/dest/broadcast/pl-PL.xml
+++ b/translation/dest/broadcast/pl-PL.xml
@@ -25,14 +25,12 @@
Krótki opis turniejuPełny opis wydarzeniaOpcjonalny długi opis transmisji. %1$s jest dostępny. Długość musi być mniejsza niż %2$s znaków.
- Adres URL zapisu PGN
+ Adres URL zapisu PGNAdres URL, który Lichess będzie udostępniał, aby można było uzyskać aktualizacje PGN. Musi być publicznie dostępny z internetu.Do 64 identyfikatorów partii, oddzielonych spacjami.Data rozpoczęcia wydarzenia w Twojej strefie czasowejOpcjonalne, jeśli wiesz kiedy wydarzenie się rozpoczniePotwierdź źródło
- Adres URL transmisji
- Adres URL bieżącej rundyAdres URL bieżącej partiiPobierz wszystkie rundyZresetuj tę rundę
@@ -47,4 +45,13 @@
Opcjonalnie: zmień nazwy, rankingi oraz tytuły graczaPrzedział czasu w sekundachOpcjonalnie, jak długo czekać pomiędzy odpytaniami. Min 2s, max 60s. Domyślnie jest to ustawiane automatycznie na podstawie liczby widzów.
+ Federacje FIDE
+ 10 najlepszych rankingów
+ Zawodnicy FIDE
+ Nie znaleziono zawodnika FIDE
+ Profil FIDE
+ Federacja
+ Wiek w tym roku
+ Bez rankingu
+ Najnowsze turnieje
diff --git a/translation/dest/broadcast/pt-BR.xml b/translation/dest/broadcast/pt-BR.xml
index 827ac3fd43520..1b5fcf3c45826 100644
--- a/translation/dest/broadcast/pt-BR.xml
+++ b/translation/dest/broadcast/pt-BR.xml
@@ -23,12 +23,12 @@
Descrição curta do torneioDescrição completa do eventoDescrição longa e opcional da transmissão. %1$s está disponível. O tamanho deve ser menor que %2$s caracteres.
+ URL de origem de PGNURL que Lichess irá verificar para obter atualizações PGN. Deve ser acessível ao público a partir da Internet.
+ Até 64 IDs de partidas do Lichess, separados por espaços.Data de início em seu próprio fuso horárioOpcional, se você sabe quando o evento começaCrédito a fonte
- URL da transmissão
- URL da rodada atualURL da partida atualBaixar todas as rodadasReiniciar esta rodada
@@ -43,4 +43,13 @@
Opcional: substituir nomes de jogador, ratings e títulosPeríodo em segundosOpcional: tempo entre as solicitações. Mín. 2s, máx. 60s. Por padrão, é calculado com base no número de espectadores.
+ Federações FIDE
+ Classificação top 10
+ Jogadores FIDE
+ Jogador não encontrando na FIDE
+ Perfil FIDE
+ Federação
+ Idade atual
+ Sem rating
+ Torneios recentes
diff --git a/translation/dest/broadcast/pt-PT.xml b/translation/dest/broadcast/pt-PT.xml
index 098522ff13a8d..12d85abc467af 100644
--- a/translation/dest/broadcast/pt-PT.xml
+++ b/translation/dest/broadcast/pt-PT.xml
@@ -23,14 +23,12 @@
Breve descrição do torneioDescrição completa do eventoDescrição longa do evento opcional da transmissão. %1$s está disponível. Tem de ter menos que %2$s carácteres.
- URL da fonte PGN
+ URL da fonte PGNLink que o Lichess vai verificar para obter atualizações da PGN. Deve ser acessível ao público a partir da internet.Até 64 IDs de jogo Lichess, separados por espaços.Data de início no teu fuso horárioOpcional, se souberes quando começa o eventoCredita a fonte
- Transmitir o link
- Link da ronda atualLink da partida atualTransferir todas as rondasReiniciar esta ronda
@@ -45,4 +43,13 @@
Opcional: substituir nomes de jogadores, avaliações e títulosPeríodo em segundosOpcional, quanto tempo de espera entre as requisições. Mínimo 2s, máximo de 60s. O padrão é automático com base no número de espetadores.
+ Federações FIDE
+ 10 melhores classificações
+ Jogadores FIDE
+ Jogador FIDE não encontrado
+ Perfil FIDE
+ Federação
+ Idade neste ano
+ Sem classificação
+ Torneio recentes
diff --git a/translation/dest/broadcast/ro-RO.xml b/translation/dest/broadcast/ro-RO.xml
index b1df2049de7e2..fabcf2f9bc6da 100644
--- a/translation/dest/broadcast/ro-RO.xml
+++ b/translation/dest/broadcast/ro-RO.xml
@@ -23,12 +23,12 @@
O descriere scurtă a turneuluiÎntreaga descriere a evenimentuluiDescriere lungă, opțională, a difuzării. %1$s este disponibil. Lungimea trebuie să fie mai mică decât %2$s caractere.
+ URL sursă PGNURL-ul pe care Lichess îl va verifica pentru a obține actualizări al PGN-ului. Trebuie să fie public accesibil pe Internet.
+ Până la 64 de ID-uri de joc Lichess, separate prin spații.Data de începere conform fusului tău orarOpțional, dacă știi când va începe evenimentulCreditează sursa
- URL pentru difuzare
- URL runda curentaURL-ul partidei curenteDescarcă toate rundeleResetează această rundă
@@ -42,4 +42,12 @@
Calculează și afișează un clasament simplu bazat pe rezultatele joculuiOpțional: înlocuiește numele jucătorilor, ratingurile și titlurilePerioada în secunde
+ Federații FIDE
+ Jucători FIDE
+ Jucătorul FIDE nu a fost găsit
+ Profil FIDE
+ Federație
+ Vârsta în acest an
+ Fără rating
+ Turnee recente
diff --git a/translation/dest/broadcast/ru-RU.xml b/translation/dest/broadcast/ru-RU.xml
index 4146cf59a043b..804d16ce4c5f1 100644
--- a/translation/dest/broadcast/ru-RU.xml
+++ b/translation/dest/broadcast/ru-RU.xml
@@ -30,8 +30,6 @@
Дата начала в вашем часовом поясеДополнительно, если вы знаете, когда событие начнётсяПризнательность
- URL-адрес трансляции
- URL-адрес текущего тураURL-адрес текущей партииСкачать все турыСбросить тур
diff --git a/translation/dest/broadcast/ry-UA.xml b/translation/dest/broadcast/ry-UA.xml
index 4625abe83fc1f..532fe812fafe3 100644
--- a/translation/dest/broadcast/ry-UA.xml
+++ b/translation/dest/broadcast/ry-UA.xml
@@ -17,8 +17,6 @@
Дата старта у вашум часовум поясіОпціонално, кідь знаєте коли ся зачинат припадОддяка
- Адрес трансляції
- Одкликованя теперішнього тураОдкликованя теперішньої бавкыСтерьхати вшыткі рундыПерепустити сисю рунду
diff --git a/translation/dest/broadcast/sk-SK.xml b/translation/dest/broadcast/sk-SK.xml
index 75d8978539a7a..be0882a396e40 100644
--- a/translation/dest/broadcast/sk-SK.xml
+++ b/translation/dest/broadcast/sk-SK.xml
@@ -21,12 +21,12 @@
Krátky popis turnajaÚplný popis turnajaVoliteľný dlhý popis vysielania. %1$s je dostupný. Dĺžka musí byť menej ako %2$s znakov.
+ Zdrojová URL pre PGN súborURL, ktorú bude Lichess kontrolovať, aby získal aktualizácie PGN. Musí byť verejne prístupná z internetu.
+ Až do 64 identifikátorov Lichess partií oddelených medzerami.Dátum a čas začiatku, vo vašej časovej zóneVoliteľné, ak viete kedy sa udalosť začneUveďte zdroj
- Adresa URL pre sledovanie
- Adresa URL aktuálneho kolaAdresa URL aktuálnej partieStiahnuť všetky koláResetovať toto kolo
@@ -37,4 +37,13 @@
Vymazať tento turnajDefinitívne odstrániť celý turnaj so všetkými kolami a všetkými partiami.Voliteľné: nahradiť mená hráčov, hodnotenia a tituly
+ FIDE federácie
+ 10 najlepšie hodnotených
+ FIDE šachisti
+ FIDE šachista sa nenašiel
+ FIDE profil
+ Federácia
+ Vek tento rok
+ Bez hodnotenia
+ Posledné turnaje
diff --git a/translation/dest/broadcast/sl-SI.xml b/translation/dest/broadcast/sl-SI.xml
index 719c85ee31daa..5e472972abba2 100644
--- a/translation/dest/broadcast/sl-SI.xml
+++ b/translation/dest/broadcast/sl-SI.xml
@@ -29,8 +29,6 @@
Datum začetka v vaše časovnem pasuIzbirno, če veste, kdaj se dogodek začneNavedi vir
- URL oddaje
- URL trenutnega krogaURL trenutno igrane igrePrenesite vse krogePonastavi ta krog
diff --git a/translation/dest/broadcast/sq-AL.xml b/translation/dest/broadcast/sq-AL.xml
index ff873de32923a..776a22485daf9 100644
--- a/translation/dest/broadcast/sq-AL.xml
+++ b/translation/dest/broadcast/sq-AL.xml
@@ -23,12 +23,12 @@
Përshkrim i shkurtër i turneutPërshkrim i plotë i turneutPërshkrim i gjatë opsional i turneut. %1$s është e disponueshme. Gjatësia duhet të jetë më pak se %2$s shenja.
+ URL Burimi PNG-jeURL-ja që do të kontrollojë Lichess-i për të marrë përditësime PGN-sh. Duhet të jetë e përdorshme publikisht që nga Interneti.
+ Deri në 64 ID lojërash Lichess, ndarë me hapësira.Datë fillimi në zonën tuaj kohoreOpsionale, nëse e dini kur fillon veprimtariaAtriboji merita burimit
- URL Transmetimi
- URL e raundit të tanishëmURL e lojës së tanishmeShkarko krejt raundetFshije këtë raund
@@ -42,4 +42,13 @@
Opsionale: zëvendësoni emra lojëtarësh, vlerësime dhe titujPeriudhë, në sekondaOpsionale, sa gjatë të pritet mes kërkesash. Min. 2s, maks. 60s. Si parazgjedhje, përdoret vlera automatike bazuar në numrin e parësve.
+ Federata FIDE
+ 10 vlerësimet kryesuese
+ Lojtarë FIDE
+ S’u gjet lojtar FIDE
+ Profil FIDE
+ Federim
+ Moshë këtë vit
+ Pa pikë
+ Turne së fundi
diff --git a/translation/dest/broadcast/sv-SE.xml b/translation/dest/broadcast/sv-SE.xml
index b7507af95de49..1fc590d49b093 100644
--- a/translation/dest/broadcast/sv-SE.xml
+++ b/translation/dest/broadcast/sv-SE.xml
@@ -26,8 +26,6 @@
Startdatum i din egen tidszonValfritt, om du vet när händelsen startarKreditera källan
- Länk till direktsändning (URL)
- Länk till aktuellt runda (URL)Länk till aktuellt parti (URL)Ladda ner alla omgångarÅterställ den här omgången
diff --git a/translation/dest/broadcast/th-TH.xml b/translation/dest/broadcast/th-TH.xml
index 76255f55d2b3b..64e1a2df641a8 100644
--- a/translation/dest/broadcast/th-TH.xml
+++ b/translation/dest/broadcast/th-TH.xml
@@ -21,8 +21,6 @@
วันที่เริ่มในเขตเวลาของคุณไม่บังคับ, ถ้าคุณรู้ว่ารายการจะเริ่มเมื่อใดเครดิตแหล่ง
- URL การถ่ายทอดสด
- URL รอบปัจจุบันURL เกมปัจจุบันตารางผู้นำอัตโนมัติคำนวณและแสดงกระดานผู้นำอย่างง่ายตามผลลัพธ์ของเกม
diff --git a/translation/dest/broadcast/tr-TR.xml b/translation/dest/broadcast/tr-TR.xml
index 76e5a6567899d..de6471db7c349 100644
--- a/translation/dest/broadcast/tr-TR.xml
+++ b/translation/dest/broadcast/tr-TR.xml
@@ -23,12 +23,12 @@
Turnuvanın kısa tanımıEtkinliğin detaylıca açıklamasıEtkinliğin isteğe bağlı detaylı açıklaması. %1$s seçeneği mevcuttur. Metnin uzunluğu azami %2$s karakter olmalıdır.
+ PGN Kaynak URL\'siLichess, sağladığınız URL yardımıyla PGN\'yi güncelleyecektir. İnternet üzerinden herkese açık bir URL yazmalısınız.
+ Boşluklarla ayrılmış 64 adede kadar Lichess oyun ID\'si.Kendi saat diliminizdeki başlangıç zamanıİsteğe bağlı, etkinliğin ne zaman başladığını biliyorsanız ekleyebilirsiniz.Kaynağı görüntüle
- Yayın linki
- Şu anki turun linkiŞu anki oyunun linkiBütün maçları indirBu turu sıfırla
@@ -43,4 +43,13 @@
İsteğe bağlı: Oyuncu adlarını, derecelendirmelerini ve unvanlarını değiştirinSaniye cinsinden dönemİsteğe bağlı olarak, istekler arasında beklenmesi gereken süreyi belirtin. Minimum 2 saniye, maksimum 60 saniye. Varsayılan değer, izleyici sayısına göre otomatik olarak belirlenir.
+ FIDE federasyonları
+ İlk 10 rating
+ FIDE oyuncuları
+ FIDE oyuncusu bulunamadı
+ FIDE profili
+ Federasyon
+ Bu yılki yaşı
+ Derecelendirilmemiş
+ Son Turnuvalar
diff --git a/translation/dest/broadcast/uk-UA.xml b/translation/dest/broadcast/uk-UA.xml
index d8cbe8d1075de..9dee5fc54a82d 100644
--- a/translation/dest/broadcast/uk-UA.xml
+++ b/translation/dest/broadcast/uk-UA.xml
@@ -25,12 +25,12 @@
Короткий опис турніруПовний опис подіїНеобов\'язковий довгий опис трансляції. Наявна розмітка %1$s. Довжина має бути менша ніж %2$s символів.
+ Адреса джерела PGNПосилання, яке Lichess перевірятиме, щоб отримати оновлення PGN. Воно має бути загальнодоступним в Інтернеті.
+ До 64 ігрових ID Lichess, відокремлені пробілами.Дата початку у вашому часовому поясіЗа бажанням, якщо ви знаєте, коли починається подіяВдячність джерелу
- Посилання на трансляцію
- Посилання на поточний раундПосилання на поточну груЗавантажити всі туриСкинути цей раунд
@@ -45,4 +45,11 @@
За бажанням: замінити імена, рейтинги та титули гравцівПеріод у секундахОпціонально: час очікування між запитами. Мінімально 2 с, максимально 60 с. За замовчуванням - автоматично, виходячи з кількості запитів глядачів.
+ Федерації FIDE
+ Гравці FIDE
+ Гравця FIDE не знайдено
+ Профіль FIDE
+ Федерація
+ Без рейтингу
+ Нещодавні турніри
diff --git a/translation/dest/broadcast/vi-VN.xml b/translation/dest/broadcast/vi-VN.xml
index 4c1b2fafbcbf0..316da5e8119ca 100644
--- a/translation/dest/broadcast/vi-VN.xml
+++ b/translation/dest/broadcast/vi-VN.xml
@@ -22,14 +22,12 @@
Mô tả ngắn giải đấuMô tả đầy đủ giải đấuTùy chọn mô tả dài về giải đấu. Có thể sử dụng %1$s. Độ dài phải nhỏ hơn %2$s ký tự.
- URL Nguồn PGN
+ URL Nguồn PGNURL mà Lichess sẽ khảo sát để nhận cập nhật PGN. Nó phải được truy cập công khai từ Internet.Tối đa 64 ID ván cờ trên Lichess, phân tách bằng dấu cách.Ngày bắt đầu theo múi giờ của bạnTùy chọn, nếu bạn biết khi nào sự kiện bắt đầuCông nhận nguồn
- URL phát sóng
- URL vòng đấu hiện tạiURL ván đấu hiện tạiTải về tất cả ván đấuĐặt lại vòng này
@@ -44,4 +42,13 @@
Tùy chọn: biệt danh, hệ số Elo và danh hiệuKhoảng thời gian tính bằng giâyTùy chọn, thời gian chờ đợi giữa các yêu cầu. Tối thiểu 2 giây, tối đa 60 giây. Mặc định là tự động dựa trên số lượng người xem.
+ Các liên đoàn FIDE
+ Hệ số Elo top 10
+ Các kỳ thủ FIDE
+ Không tìm thấy kỳ thủ FIDE
+ Hồ sơ FIDE
+ Liên đoàn
+ Tuổi năm nay
+ Chưa xếp hạng
+ Các giải đấu tham gia gần đây
diff --git a/translation/dest/broadcast/zh-CN.xml b/translation/dest/broadcast/zh-CN.xml
index 975fa3503897a..027c600aa2274 100644
--- a/translation/dest/broadcast/zh-CN.xml
+++ b/translation/dest/broadcast/zh-CN.xml
@@ -26,8 +26,6 @@
开始日期,在你的本地时区如果你知道比赛开始时间 (可选)信任来源
- 直播链接
- 当前一轮链接当前棋局链接下载所有棋局重置此轮
@@ -42,4 +40,5 @@
可选项:替换选手的名字、等级分和头衔时长(秒)可选项,请求之间等待多长时间。最小2秒,最大60秒。默认值为基于观众数量的自动值。
+ 今年的年龄
diff --git a/translation/dest/broadcast/zh-TW.xml b/translation/dest/broadcast/zh-TW.xml
index fbe5362588d1b..3b39eb7f68bc5 100644
--- a/translation/dest/broadcast/zh-TW.xml
+++ b/translation/dest/broadcast/zh-TW.xml
@@ -17,8 +17,6 @@
開始日期 (當地時間)可選,如果知道比賽開始時間將來源歸因
- 直播連結
- 目前回合連結目前棋局連結下載所有棋局重設此回合
diff --git a/translation/dest/challenge/he-IL.xml b/translation/dest/challenge/he-IL.xml
index 03847c825b4d5..78051d8fd900f 100644
--- a/translation/dest/challenge/he-IL.xml
+++ b/translation/dest/challenge/he-IL.xml
@@ -9,7 +9,7 @@
לא ניתן להזמין את %s למשחק.%s לא מקבל/ת הזמנות למשחקים.הדירוג שלך ב%1$s רחוק מדי מהדירוג של %2$s.
- אין אפשרות להזמין למשחק בגלל שדירוגך ב-%s זמני.
+ אין אפשרות להזמין למשחק בגלל שדירוגך ב־%s זמני.%s מאשר/ת רק אתגרים מחברים.אני לא מקבל/ת הזמנות עכשיו.זה לא הזמן המתאים עבורי, אנא שאל שוב מאוחר יותר.
diff --git a/translation/dest/class/fa-IR.xml b/translation/dest/class/fa-IR.xml
index 9a2c2455b3ada..a3961045033ce 100644
--- a/translation/dest/class/fa-IR.xml
+++ b/translation/dest/class/fa-IR.xml
@@ -32,7 +32,7 @@
نام واقعیخصوصی. هرگز در خارج از کلاس نمایش داده نخواهد شد. به یاد آوری دانش آموز کمک می کند.دانشآموز اضافه کنید
- نمایه %1$s برای %2$s ساخته شد.
+ رُخنما %1$s برای %2$s ساخته شد.دانشجو: %1$s
نامِ کاربری: %2$s
گذرواژه: %3$s
diff --git a/translation/dest/class/he-IL.xml b/translation/dest/class/he-IL.xml
index 5499d26895321..6cafdd08753c5 100644
--- a/translation/dest/class/he-IL.xml
+++ b/translation/dest/class/he-IL.xml
@@ -1,7 +1,7 @@
כיתות
- למד/י כיתות של תלמידי שחמט עם כלי הכיתות ש-Lichess מעמיד לרשותך.
+ למד/י כיתות של תלמידי שחמט עם כלי הכיתות ש־Lichess מעמיד לרשותך.תכונותהפיקו במהירות שמות משתמשים וסיסמאות בטוחות לתלמידיםעקבו אחר ההתקדמות של התלמידים במשחקים ובחידות
@@ -110,14 +110,14 @@
קיבלת את ההזמנה הזו.סירבת להזמנה הזו.או
- צרו חשבונות Lichess מרובים בו-זמנית
+ צרו חשבונות Lichess מרובים בו־זמניתאת/ה יכול/ה גם %s כדי ליצור חשבונות Lichess מרובים מרשימה של שמות תלמידים.להשתמש בטופס הזהשימו לב שבכיתה יכולים להיות עד %1$s תלמידים. כדי לטפל ביותר תלמידים, %2$s.צרו עוד כיתותשמות התלמידים האמיתיים, אחד בכל שורה%s הוא עכשיו תלמיד בכיתה
- נשלחה הזמנה ל-%s
- ל-%s כבר יש הזמנה בהמתנה לתשובה
+ נשלחה הזמנה ל־%s
+ ל־%s כבר יש הזמנה בהמתנה לתשובה%1$s הוא חשבון של ילד/ה ולא יכול לקבל את ההודעה שלך. עליך לתת להם את קישור ההזמנה באופן ידני: %2$s
diff --git a/translation/dest/coach/fa-IR.xml b/translation/dest/coach/fa-IR.xml
index b8564b76ac806..b115dbf2e943a 100644
--- a/translation/dest/coach/fa-IR.xml
+++ b/translation/dest/coach/fa-IR.xml
@@ -14,7 +14,7 @@
دانشجوها را قبول میکنمدر حال حاضر پذیرای دانشجویان نیستم%s مربی شطرنج دانشجویان است
- نمایه %s در Lichess را ببینید
+ رُخنما %s در Lichess را ببینیدیک پیام خصوصی ارسال کنیددرباره منسابقه بازی
diff --git a/translation/dest/coach/he-IL.xml b/translation/dest/coach/he-IL.xml
index 0ee752227f422..cd46b38638a33 100644
--- a/translation/dest/coach/he-IL.xml
+++ b/translation/dest/coach/he-IL.xml
@@ -1,7 +1,7 @@
- מאמנים ב-lichess
- מאמן ב-lichess
+ מאמנים ב־lichess
+ מאמן ב־lichessהאם את/ה מאמן/ת שחמט מעולה בדרגת %s?אמן/ית לאומי/ת או אחת מדרגות FIDEאשר/י את דרגתך כאן ואנו נבדוק את בקשתך.
diff --git a/translation/dest/coach/pt-BR.xml b/translation/dest/coach/pt-BR.xml
index 1aa6fd3bcd1fe..35cbc97b4a867 100644
--- a/translation/dest/coach/pt-BR.xml
+++ b/translation/dest/coach/pt-BR.xml
@@ -8,7 +8,7 @@
Envie-nos um e-mail para %s e nós analisaremos a sua aplicação.LocalIdiomas
- Pontuação
+ RatingPreço por horaDisponibilidadeAceita alunos
diff --git a/translation/dest/contact/an-ES.xml b/translation/dest/contact/an-ES.xml
index d2597792bf884..c1609c655d3db 100644
--- a/translation/dest/contact/an-ES.xml
+++ b/translation/dest/contact/an-ES.xml
@@ -55,9 +55,7 @@
En bels casos, cuan se chuga contra una cuenta de bot, una partida con puntuación puede que no de puntos si se determina que lo chugador ye abusando d\'o bot pa obtener puntos.Pachina d\'errorSi una pachina te da error, puez reportar-la:
- Quiero retransmitir un torneyoAprende cómo puez anyadir las tuyas propias retransmisions a Lichess
- Tamién puez contactar con l\'equipo de retransmisions sobre transmisions oficials.Apelar per un bloqueyo u una restricción d\'IPMotor u marca de trapaceríaPuez ninviar una apelación a %s.
diff --git a/translation/dest/contact/ar-SA.xml b/translation/dest/contact/ar-SA.xml
index faf9f5de61ba1..3ccce9a7c6d1f 100644
--- a/translation/dest/contact/ar-SA.xml
+++ b/translation/dest/contact/ar-SA.xml
@@ -55,9 +55,7 @@
في بعض الظروف عند اللعب ضد حساب بوت لعبة مصنفة قد لا تمنح نقاط إذا تقرر أن اللاعب يسيء استخدام البوت لنقاط التقييم.صفحة خطأإذا واجهت صفحة خطأ، فيمكنك الإبلاغ عنها:
- أريد بث بطولةتعلم كيفية بث بطولة على Lichess
- بإمكانك أيضاً الاتصال بفريق البث الإذاعي عن البثوث الرسمية.طلب لرفع حظر او تقييد على IPعلامة الغش او استخدام محركيمكنك ارسال طلب الى %s.
diff --git a/translation/dest/contact/be-BY.xml b/translation/dest/contact/be-BY.xml
index 6ae22945e9543..d1cffbb6d4eed 100644
--- a/translation/dest/contact/be-BY.xml
+++ b/translation/dest/contact/be-BY.xml
@@ -55,9 +55,7 @@
У пэўных абставінах, калі гуляючы супраць уліковых запісаў ботаў, рэйтангавая партыя можа не прыводзіць да змены рэйтынгу. Калі ўстаноўлена, што гулец злоўжывае бота дзеля павялячэння рэйтынгу.Старонка памылкіКалі вы траміце на старонку з памылкай, вы можаце паведаміць пра яе:
- Я хачу трансляваць турнірДазнайцеся, як карыстацца трансляцыямі Lichess
- Вы можаце звязацца з камандай трансляцый пра афіцыйныя эфіры.Абскарджанне бана ўліковага запісу ці абмежавання IP-адрасаВыкарыстанне рухавіка або несумленная гульняВы можаце накіраваць апеляцыю праз %s.
diff --git a/translation/dest/contact/bg-BG.xml b/translation/dest/contact/bg-BG.xml
index a210f6e5bb2e8..492dc0ab27f11 100644
--- a/translation/dest/contact/bg-BG.xml
+++ b/translation/dest/contact/bg-BG.xml
@@ -55,9 +55,7 @@
В някои случаи, игри с рейтинг срещу ботове могат да не донесат точки, ако система определи че играчът експлоатира бота за увеличаване на рейтинга си.Страница за грешкатаАко сте се сблъскали с грешна страница, можете да съобщите за нея:
- Искам да излъча турнирНаучете се как да правите излъчвания в Lichess
- Можете също да се свържете с екипа за излъчвания ако се интересувате от официални излъчвания.Жалба за бан или IP ограничениеПрограма или измамаМожете да изпратите жалба до %s.
diff --git a/translation/dest/contact/br-FR.xml b/translation/dest/contact/br-FR.xml
index 1bcd6ec49e5ec..de20a19e202fb 100644
--- a/translation/dest/contact/br-FR.xml
+++ b/translation/dest/contact/br-FR.xml
@@ -28,7 +28,6 @@
Poent renkadur ebet zo bet roetBezit sur ho peus kemeret perzh en ur c\'hrogad renket rak ar c\'hrogadoù a vignoniezh ne cheñchont ket renkadur ar c\'hoarierien.Pajenn fazi
- Fellout a ra din skignañ un tournamantGalv a c\'hallit ober: %s.Arabat nac\'hañ bezañ truchet. Ma fell deoc\'h bezañ aotreet da grouiñ ur gont nevez eo gwelloc\'h deoc\'h anzav ar pezh az peus graet ha kompren pegen fall e oa.Prenañ Lichess
diff --git a/translation/dest/contact/bs-BA.xml b/translation/dest/contact/bs-BA.xml
index e561647bc39b7..2ac01f149c266 100644
--- a/translation/dest/contact/bs-BA.xml
+++ b/translation/dest/contact/bs-BA.xml
@@ -55,9 +55,7 @@
U određenim slučajevima kad igrate protiv bot računa, možda vam ocijenjena igra neće nagraditi poene ako se ustanovi da je igrač zloupotrebljavao bota da bi dobili poene.Stranica u slučaju greškeUkoliko ste dobili stranicu u slučaju greške, možete je prijaviti:
- Želim prenositi turnirNaučite kako napraviti vlastita emitiranja na Lichessu
- Također možete kontaktirati s timom za emitiranja u vezi sa službenim emitiranjima.Žalba na zabranu ili ograničenje IP adreseOznaka za varalice ili za one koji koriste računarMožete poslati žalbu na %s.
diff --git a/translation/dest/contact/ca-ES.xml b/translation/dest/contact/ca-ES.xml
index 3c8d1f80b26ba..92268b7b7d41b 100644
--- a/translation/dest/contact/ca-ES.xml
+++ b/translation/dest/contact/ca-ES.xml
@@ -55,9 +55,7 @@
En alguns casos quan es juga contra un compte de bot, una partida amb puntuació pot ser que no doni punts si es determina que el jugador està abusant del bot per tal d\'obtenir punts.Pàgina d\'errorSi una pàgina et dóna error, la pots reportar:
- Vull retransmetre un torneigAprèn com pots afegir les teves pròpies retransmissions a Lichess
- També podeu contactar l\'equip de retransmissions per les retransmissions oficials.Apel·lació per prohibició o restricció de IPMotor o marca de trampaPots enviar una apel·lació a %s.
diff --git a/translation/dest/contact/ckb-IR.xml b/translation/dest/contact/ckb-IR.xml
index 02dc28ad213bf..e585148e287e2 100644
--- a/translation/dest/contact/ckb-IR.xml
+++ b/translation/dest/contact/ckb-IR.xml
@@ -55,9 +55,7 @@
لە هەندێک بارودۆخدا لەکاتی یاریکردن بەرامبەر ئەکاونتی بۆت، یارییەکی ڕیزبەندی ڕەنگە خاڵت پێ نەدرێت ئەگەر بزارێت کە یاریزانەکە خراپ بۆتەکە بەکاردەهێنێت بۆ خاڵەکانی ڕیزبەندی.لاپەڕەی هەڵەئەگەر ڕووبەڕووی لاپەڕەیەکی هەڵە بوویتەوە، دەکرێ سکاڵا بکەیت:
- دەمەوێت پاڵەوانێتییەک پەخش بکەمفێربە چۆن پەخشی تایبەتی خۆت لە لیچێس دروست بکەیت
- هەروەها دەتوانن پەیوەندی بە تیمی پەخشەوە بکەن سەبارەت بە پەخشی فەرمی.تانەدان بۆ قەدەغەکردن یان سنووردارکردنی IPبەکارهێنانی بزوێنەر یان نیشانەی قۆپیە کردندەتوانی تانەدانەکە بنێریت بۆ %s.
diff --git a/translation/dest/contact/cs-CZ.xml b/translation/dest/contact/cs-CZ.xml
index b9e925cd7bf9e..ad2b3f2ac83f5 100644
--- a/translation/dest/contact/cs-CZ.xml
+++ b/translation/dest/contact/cs-CZ.xml
@@ -55,9 +55,7 @@
Za určitých okolností při hraní proti účtu bota hodnocená hra neudělí žádné body, pokud je zjištěno, že hráč zneužívá bota jen pro změnu hodnocení.Chybová stránkaPokud jste narazili na chybovou stránku, můžete ji nahlásit:
- Chci vysílat turnajNaučte se vytvořit své vlastní vysílání na Lichess
- Můžete také kontaktovat vysílací tým o oficiálním vysílání.Žádost o zákaz nebo IP omezeníOzčnačení za engine nebo podváděníMůžete poslat odvolání na %s.
diff --git a/translation/dest/contact/da-DK.xml b/translation/dest/contact/da-DK.xml
index ea90254a620db..233d404fc67bf 100644
--- a/translation/dest/contact/da-DK.xml
+++ b/translation/dest/contact/da-DK.xml
@@ -55,9 +55,7 @@
Under visse omstændigheder, når du spiller mod en bot-konto, giver et ratet parti måske ikke point, hvis det fastslås, at spilleren misbruger bot\'en for ratingpoint.FejlsideHvis du stødte på en fejlside, kan du anmelde det:
- Jeg ønsker at udsende en turneringLær hvordan du laver dine egne udsendelser på Lichess
- Du kan også kontakte teamet for udsendelser angående officielle udsendelser.Appellere en udelukkelse eller IP-restriktionSkakprogram eller snyde-anmærkningDu kan sende en appel til %s.
diff --git a/translation/dest/contact/de-DE.xml b/translation/dest/contact/de-DE.xml
index 5d989d5269c8f..3c05f71284d0c 100644
--- a/translation/dest/contact/de-DE.xml
+++ b/translation/dest/contact/de-DE.xml
@@ -55,9 +55,7 @@
Wenn ein Spieler gegen einen Bot spielt, kann es unter Umständen passieren, dass ein Sieg in einem gewertetem Spiel keine Punkte einbringt, falls der Spieler den Bot dazu benutzt, Wertungspunkte anzuhäufen.FehlerseiteFalls du eine Fehlerseite entdeckt hast kannst du sie melden:
- Ich möchte ein Turnier übertragenLerne deine eigenen Übertragungen auf Lichess zu machen
- Du kannst auch das Übertragungs-Team bezüglich offizieller Übertragungen kontaktieren.Einspruch gegen einen Bann oder IP-BeschränkungMarkierung für Computerunterstützung/BetrugDu kannst deinen Einspruch an %s senden.
diff --git a/translation/dest/contact/el-GR.xml b/translation/dest/contact/el-GR.xml
index 100212a2e84ab..13fb786e168fe 100644
--- a/translation/dest/contact/el-GR.xml
+++ b/translation/dest/contact/el-GR.xml
@@ -55,9 +55,7 @@
Σε ορισμένες περιπτώσεις, παίζοντας εναντίον ενός λογαριασμού-υπολογιστή ένα βαθμολογημένο παιχνίδι μπορεί να μην αποφέρει πόντους βαθμολογίας εάν ο παίκτης κάνει κατάχρηση αυτού.Σελίδα σφάλματοςΑν εμφανίστηκε σελίδα σφάλματος, μπορείτε να το αναφέρετε:
- Θέλω να αναμεταδώσω ένα γεγονόςΜάθετε πώς να κάνετε τις δικές σας μεταδόσεις στο Lichess
- Μπορείτε επίσης να επικοινωνήσετε με την ομάδα μετάδοσης για επίσημες μεταδόσεις.Θέλω να αποσυρθεί ο περιορισμός/αποκλεισμός της διεύθυνσης IP μουΜηχανή ή απάτηΜπορείτε να ασκήσετε ένσταση στο %s.
diff --git a/translation/dest/contact/en-US.xml b/translation/dest/contact/en-US.xml
index 9036bfeeb4f69..32da03c61f5aa 100644
--- a/translation/dest/contact/en-US.xml
+++ b/translation/dest/contact/en-US.xml
@@ -55,9 +55,7 @@
In certain circumstances when playing against a bot account, a rated game may not award points if it is determined that the player is abusing the bot for rating points.Error pageIf you faced an error page, you may report it:
- I want to broadcast a tournamentLearn how to make your own broadcasts on Lichess
- You can also contact the broadcast team about official broadcasts.Appeal for a ban or IP restrictionEngine or cheat markYou may send an appeal to %s.
diff --git a/translation/dest/contact/eo-UY.xml b/translation/dest/contact/eo-UY.xml
index 06fe62d777ae5..45424296f1d16 100644
--- a/translation/dest/contact/eo-UY.xml
+++ b/translation/dest/contact/eo-UY.xml
@@ -55,9 +55,7 @@
En certaj cirkonstancoj kiam ludanta kontraŭ robotkonto, ranga ludo eble ne aljuĝas poentojn se estas determinite ke la ludanto misuzas la roboton por rangaj poentoj.Erara paĝoSe vi trovas eraran paĝon, vi povas raporti ĝin:
- Mi volas elsendi turnironLerni kiel fari viajn proprajn elsendojn ĉe Lichess
- Vi ankaŭ povas kontakti la elsendan teamon pri oficialaj elsendoj.Apelacio por malpermeso aŭ IP limigoMotoro aŭ trompmarkoVi povas sendi apelacion al %s.
diff --git a/translation/dest/contact/es-ES.xml b/translation/dest/contact/es-ES.xml
index 9c81b75678180..4a10811bb8f41 100644
--- a/translation/dest/contact/es-ES.xml
+++ b/translation/dest/contact/es-ES.xml
@@ -55,9 +55,7 @@
Al jugar contra una cuenta de bot, puede que una partida por puntos no se contabilice si se determina que el jugador abusa del bot para conseguir puntos.Página de errorSi una página te da error, puedes reportarla:
- Quiero transmitir un torneoAprende cómo hacer tus propias emisiones en Lichess
- También puedes ponerte en contacto con el equipo de emisiones acerca de las emisiones oficiales.Apelar por un bloqueo o una restricción de IPMotor o marca de trampaPuedes enviar una apelación a %s.
diff --git a/translation/dest/contact/et-EE.xml b/translation/dest/contact/et-EE.xml
index b6fc69ce4849c..73b02438eba27 100644
--- a/translation/dest/contact/et-EE.xml
+++ b/translation/dest/contact/et-EE.xml
@@ -55,7 +55,6 @@
Teatud juhtumites mängides boti vastu reitingumäng ei anna punkte, kui on märgatud, et mängija kasutab botti ära reitingu tõstmiseks.Vigane lehtKui märkasid vigast lehte, saad teavitada sellest:
- Ma soovin turniiri edastadaÕpi kuidas Lichess\'is ise ülekannet tehaKaeba bännist või IP-piirangustArvuti või pettuse märk
diff --git a/translation/dest/contact/eu-ES.xml b/translation/dest/contact/eu-ES.xml
index 91ec6bfad520c..59913806311f9 100644
--- a/translation/dest/contact/eu-ES.xml
+++ b/translation/dest/contact/eu-ES.xml
@@ -55,9 +55,7 @@
Kasu batzutan robot baten aurka jokatzean, partida batek ez ditu sailkapenerako puntuak ematen jokalaria robotarekin gehiegitan jokatzen ari bada.Errore orrialdeaErrorea orrialdea agertu bazaizu, horren berri eman diezagukezu:
- Txapelketa baten emanaldia egin nahi dutIkasi nola egin emanaldiak Lichessen
- Emanaldien taldearekin harremanetan jarri zaitezke emanaldi ofizialei buruz gehiago jakiteko.Debeku edo IP murriztapen baten aurka egiteaMotore-erabilera edo tranpa markaZure kexa honi bidali diezaiokezu: %s.
diff --git a/translation/dest/contact/fa-IR.xml b/translation/dest/contact/fa-IR.xml
index 288a9577c57ed..4412711bf884b 100644
--- a/translation/dest/contact/fa-IR.xml
+++ b/translation/dest/contact/fa-IR.xml
@@ -13,7 +13,7 @@
بازیابی گذرواژه را تکمیل کنید تا هویتسنجیِ دومِ شما برداشته شودبه پشتیبانی حساب کاربری نیاز دارممی خواهم عنوانم در Lichess نشان داده شود
- برای آن که عنوان شما روی نمایه Lichessتان نشان داده شود، و در میدانهای مسابقه عنوانداران شرکت کنید، به صفحه تاییدِ عنوان سَر بزنید
+ برای آن که عنوان شما روی رُخنمای Lichessتان نشان داده شود، و در میدانهای مسابقه عنوانداران شرکت کنید، به صفحه تاییدِ عنوان سَر بزنیدمی خواهم حساب کاربری ام را ببندمشما میتوانید در این صفحه حساب کاربری خود را ببندیداز طریق رایانامه از ما نخواهید که یک حساب کاربری را ببندیم، ما آن را انجام نخواهیم داد.
@@ -28,7 +28,7 @@
امکان پاک کردن پیشینه بازیها، پیشینه معماها یا درجهبندی وجود ندارد.میخواهم یک کاربر را گزارش کنمبرای گزارش کردنِ یک کاربر، از فرم گزارش استفاده کنید
- همچنین میتوانید با زدن روی دکمه گزارش %s در یک صفحه نمایه، به آن صفحه برسید.
+ همچنین میتوانید با زدن روی دکمه گزارش %s در یک صفحه رُخنما، به آن صفحه برسید.در تالار گفت و گو کاربرها را گزارش نکنید.از ارسال رایانامه به ما برای گزارش خودداری کنید.لطفا پیام مستقیم به مدیران سایت نفرستید.
@@ -36,7 +36,7 @@
میخواهم یک ایراد فنی را گزارش کنمدر قسمت بازخوردِ Lichess در تالار گفت و گوبه عنوان یک مشکلِ وبسایت Lichess روی GitHub
- به عنوان یک مشکلِ اپلیکیشن موبایل Lichess روی GitHub
+ مشکلِ گوشیافزار Lichess در GitHubدر سرورِ دیسکوردِ Lichessلطفاً توصیف کنید که نقصان فنی چگونه است، شما انتظار داشتید به جای آن چه اتفاقی رخ میداد، و گامهایی که نقصان را مجدداً ایجاد میکند را شرح دهید.زدنِ غیرقانونیِ سرباز
@@ -55,11 +55,9 @@
در مواقع مشخص و در بازی مقابل یک حساب کاربری ربات، اگر مشخص شود که بازیکن در حال سوءِ استفاده از ربات برای دریافت امتیاز است ممکن است به بازی امتیازی تعلق نگیرد.صفحه خطااگر با صفحه خطا مواجه شدید، میتوانید آن را گزارش کنید:
- من مایلم که یک دوره مسابقات را پخش کنمیاد بگیرید که چطور پخش زنده خود را در لیچس بسازید
- شما همینطور میتوانید با تیم پخش زنده در مورد پخش های رسمی تماس بگیرید.درخواست بازنگری برای یک ممنوعیت یا محدودیتِ IP
- علامتگذاری استفاده از پردازشگر شطرنج یا تقلب
+ علامتگذاری استفاده از رایانه یا تقلبشما میتوانید یک درخواست بررسی مجدد به %s ارسال کنید.مثبتهای اشتباهی حتماً گاهی اتفاق میافتد، و ما درباره آن متاسفیم.اگر درخواست بازنگری شما مشروع و قانونی باشد، ما در نزدیکترین زمان ممکن ممنوعیت را رفع خواهیم کرد.
diff --git a/translation/dest/contact/fi-FI.xml b/translation/dest/contact/fi-FI.xml
index 4a20167791d3a..491556919bf06 100644
--- a/translation/dest/contact/fi-FI.xml
+++ b/translation/dest/contact/fi-FI.xml
@@ -55,9 +55,7 @@
Joissakin tilanteissa bottia vastaan pelatusta pisteytetystä pelistä ei välttämättä saa pisteitä, jos pelaajan katsotaan käyttävän bottia hyväkseen pisteiden saamiseksi.VirhesivuJos törmäsit virhesivuun, voit raportoida sen:
- Haluan pitää lähetyksen turnauksestaOpi pitämään omia lähetyksiä Lichessissä
- Voit myös ottaa yhteyden lähetystiimiin virallisia lähetyksiä koskien.Valita porttikiellosta tai IP-estostaTietokone- tai huijarimerkinnästäVoit valittaa osoitteeseen %s.
diff --git a/translation/dest/contact/fr-FR.xml b/translation/dest/contact/fr-FR.xml
index bebcf70a158fb..548c9923c8b70 100644
--- a/translation/dest/contact/fr-FR.xml
+++ b/translation/dest/contact/fr-FR.xml
@@ -55,9 +55,7 @@
Dans certains cas, si vous jouez contre un bot, une partie classée ne vous donnera pas de points s\'il est déterminé que vous avez abusé du bot pour obtenir des points.Page d\'erreurSi un message d\'erreur s\'est affiché, vous pouvez le signaler :
- Je souhaite diffuser un tournoiApprenez comment réaliser vos propres diffusions sur Lichess
- Vous pouvez également contacter l\'équipe de diffusion au sujet des diffusions officielles.Demande d\'appel pour un bannissement ou une restriction IPTricherie ou utilisation d\'un programmeVous pouvez soumettre une demande d\'appel à %s.
diff --git a/translation/dest/contact/gl-ES.xml b/translation/dest/contact/gl-ES.xml
index 9088e9cf6d4f4..4349f2d192f0c 100644
--- a/translation/dest/contact/gl-ES.xml
+++ b/translation/dest/contact/gl-ES.xml
@@ -55,9 +55,7 @@
Ó xogar contra unha conta de bot, pode que unha partida puntuada non se contabilice se se determina que o xogador abusa do bot para conseguir puntos.Páxina de erroSe unha páxina dá erro, podes reportala:
- Quero retransmitir un torneoAprende a facer as túas propias retransmisións en Lichess
- Tamén podes poñerte en contacto co equipo de retransmisións para as retransmisións oficiais.Apelar por un bloqueo ou unha restrición do IPMarca de trampa ou de motor de xadrezPodes mandar unha apelación a %s.
diff --git a/translation/dest/contact/gsw-CH.xml b/translation/dest/contact/gsw-CH.xml
index 0e6becb19946b..226a02c26c95a 100644
--- a/translation/dest/contact/gsw-CH.xml
+++ b/translation/dest/contact/gsw-CH.xml
@@ -55,9 +55,7 @@
Under beschtimmte Umschtänd - wänn gäge es \"Bot Konto\" gschpillt wird - chas si, dass kei Pünkt vergeh werded, wänn feschtgschtellt wird, dass de \"Bot\" für d\'Wertig missbrucht wird.FählersiteWänn du e Fählersite entdeckt häsch, chasch sie mälde:
- Ich wott es Turnier überträgeLern wie du - uf Lichess - dini eigeni Überträgig machsch
- Du chasch - für offizielli Überträgige - au s\'Broadcast-Team kontaktiere.Ischpruch gäge en Usschluss oder IP-BeschränkigMarkierig vu Computer Underschtützig oder BetrugDu chasch en Ischpruch a %s sände.
diff --git a/translation/dest/contact/he-IL.xml b/translation/dest/contact/he-IL.xml
index 7b324b85e1f9b..30cf77542ede8 100644
--- a/translation/dest/contact/he-IL.xml
+++ b/translation/dest/contact/he-IL.xml
@@ -35,7 +35,7 @@
רק דיווח על שחקנים באמצעות טופס הדיווח יזכה להתייחסות.אני רוצה לדווח על תקלהבמדור המשוב על לִיצֶ\'ס בפורום
- כבעיה (issue) בעמוד של ליצ׳ס באתר GitHub
+ כבעיה (issue) בעמוד של Lichess באתר GitHubכבעיה (issue) בעמוד של אפליקציית לִיצֶ\'ס בGitHubבשרת הDiscord של ליצ\'סאנא תארו כיצד נראית התקלה, מה ציפיתם שיקרה במקום זאת ואת הצעדים לשחזור התקלה.
@@ -55,9 +55,7 @@
בנסיבות מסויימות כאשר משחק הוא מול בוט, משחק מדורג עשוי לא להעניק נקודות אם ייקבע שהשחקן/ית מנצל/ת את הבוט לצבירת ניקוד.שגיאה בדףאם התמודדת עם שגיאה בדף, את/ה יכול/ה לדווח על זה:
- אני רוצה לשדר טורניר
- למדו כיצד ליצור הקרנות חיות של טורנירים בליצ׳ס
- ניתן גם לכתוב לצוות השידורים שלנו לגבי שידורים רשמיים.
+ למדו כיצד ליצור הקרנות חיות של טורנירים ב־Lichessערעור על איסור או על הגבלה בIPסימן שימוש במנוע או רמאותאת/ה יכול/ה לשלוח ערעור ל%s.
diff --git a/translation/dest/contact/hr-HR.xml b/translation/dest/contact/hr-HR.xml
index 4652c50b908c2..46a4521937b0d 100644
--- a/translation/dest/contact/hr-HR.xml
+++ b/translation/dest/contact/hr-HR.xml
@@ -55,9 +55,7 @@
U određenim situacijama kad igrate na bodove protiv bot računa možda nećete dobiti bodove ako se ustanovi da je igrač zloupotrebljavao bota za dobivanja bodova.Stranica u slučaju greškeUkoliko ste dobili stranicu u slučaju greške, možete je prijaviti:
- Želim prenositi turnirNaučite kako napraviti vlastita emitiranja na Lichessu
- Također možete kontaktirati tim emitiranja u vezi službenih emitiranja.Žalba na zabranu ili ograničenje IP adreseOznaka za varalice ili za one koji koriste računarMožete poslati žalbu na %s.
diff --git a/translation/dest/contact/hu-HU.xml b/translation/dest/contact/hu-HU.xml
index 59354321be696..9e30bbeba89c2 100644
--- a/translation/dest/contact/hu-HU.xml
+++ b/translation/dest/contact/hu-HU.xml
@@ -55,9 +55,7 @@
Bizonyos helyzetekben amikor a játékos bot ellen játszik, az értékelt játszma nem feltétlen oszt pontokat, ha a játékos kikövetkeztethetően visszaél a bottal szemben értékpontok miatt.HibaoldalHa hibaoldallal találkoztál, itt jelentheted:
- Szeretnék közvetíteni egy versenytTudd meg, hogyan indíthatod el a saját közvetítésedet
- Felveheted a kapcsolatot a közvetítő csapattal a hivatalos közvetítésekkel kapcsolatban.Fellebbezés kitiltás vagy IP cím korlátozás miattSakkprogram használat vagy csalásA fellebbezést a %s címre küldheted.
diff --git a/translation/dest/contact/it-IT.xml b/translation/dest/contact/it-IT.xml
index cc24b5de3426a..e266f8c38d533 100644
--- a/translation/dest/contact/it-IT.xml
+++ b/translation/dest/contact/it-IT.xml
@@ -55,9 +55,7 @@
In certe circostanze giocando contro un profilo bot, un gioco valutato potrebbe non ricompensare punti se è determinato che il giocatore stia abusando del bot per i punti di valutazione.Pagina di erroreSe hai riscontrato una pagina di errore, puoi segnalarla:
- Voglio trasmettere un torneoImpara come fare le tue trasmissioni su Lichess
- Puoi anche contattare il team delle dirette riguardo le dirette ufficiali.Reclamo per un ban o una restrizione IPMotore o cheat markPuoi inviare una segnalazione a %s.
diff --git a/translation/dest/contact/ja-JP.xml b/translation/dest/contact/ja-JP.xml
index bb7468022ed1e..1b751f2b2b209 100644
--- a/translation/dest/contact/ja-JP.xml
+++ b/translation/dest/contact/ja-JP.xml
@@ -55,9 +55,7 @@
ボットアカウントとの対戦で、ボットを利用してレーティングを操作していると判断された場合は、レーティングの点が与えられません。エラーページエラーページに出会ったら、以下で報告できます。
- トーナメントを配信したいLichess で独自の配信を行なう方法について
- 公式の配信については配信担当者に連絡することもできます。アクセス禁止や IP 制限への異議申し立て不正行為の赤マーク異議申し立てを %s に送ることができます。
diff --git a/translation/dest/contact/kk-KZ.xml b/translation/dest/contact/kk-KZ.xml
index 7c908615532b3..bf945105f3a3f 100644
--- a/translation/dest/contact/kk-KZ.xml
+++ b/translation/dest/contact/kk-KZ.xml
@@ -55,9 +55,7 @@
Кейде роботқа қарсы бағалы ойындарда ұпай берілмеуі мүмкін. Мысалы, ойыншы өз ұпайларын өсіру мақсатында роботты асыра пайдаланғанда.Ақаулық парақшасыАқаулық парақшасына тап болсаңыз, осында хабарлауыңызға болады:
- Мен жарысты таратқым келедіЛичестегі өз көрсетіліміңізді қалай таратуға болатынын меңгеріп алыңыз
- Сонымен қатар ресми тарату мәселесін тарату тобымен талқыласаңыз болады.Шектеуге не IP шектеуге қарсылық шағымыЕсептеуіш не чит қолдандыСіз өтінішті %s жібере аласыз.
diff --git a/translation/dest/contact/kn-IN.xml b/translation/dest/contact/kn-IN.xml
index 54127ae408a4c..2a9afde215520 100644
--- a/translation/dest/contact/kn-IN.xml
+++ b/translation/dest/contact/kn-IN.xml
@@ -55,9 +55,7 @@
ಕೆಲವು ಸಂದರ್ಭಗಳಲ್ಲಿ ಬೋಟ್ ಖಾತೆಯ ವಿರುದ್ಧ ಆಡುವಾಗ, ಆಟಗಾರನು ರೇಟಿಂಗ್ ಪಾಯಿಂಟ್ಗಳಿಗಾಗಿ ಬೋಟ್ ಅನ್ನು ದುರುಪಯೋಗಪಡಿಸಿಕೊಳ್ಳುತ್ತಿದ್ದಾರೆ ಎಂದು ನಿರ್ಣಯಿಸಿದರೆ ರೇಟ್ ಮಾಡಲಾದ ಆಟವು ಅಂಕಗಳನ್ನು ನೀಡುವುದಿಲ್ಲ.ದೋಷ ಪುಟನೀವು ದೋಷ ಪುಟವನ್ನು ಎದುರಿಸಿದರೆ, ನೀವು ಅದನ್ನು ವರದಿ ಮಾಡಬಹುದು:
- ನಾನು ಪಂದ್ಯಾವಳಿಯನ್ನು ಪ್ರಸಾರ ಮಾಡಲು ಬಯಸುತ್ತೇನೆLichess ನಲ್ಲಿ ನಿಮ್ಮ ಸ್ವಂತ ಪ್ರಸಾರವನ್ನು ಹೇಗೆ ಮಾಡಬೇಕೆಂದು ತಿಳಿಯಿರಿ
- ಅಧಿಕೃತ ಪ್ರಸಾರಗಳ ಕುರಿತು ನೀವು ಪ್ರಸಾರ ತಂಡವನ್ನು ಸಹ ಸಂಪರ್ಕಿಸಬಹುದು.ನಿಷೇಧ ಅಥವಾ IP ನಿರ್ಬಂಧಕ್ಕಾಗಿ ಮನವಿಎಂಜಿನ್ ಅಥವಾ ಮೋಸ ಗುರುತುನೀವು %s ಗೆ ಮನವಿಯನ್ನು ಕಳುಹಿಸಬಹುದು.
diff --git a/translation/dest/contact/ko-KR.xml b/translation/dest/contact/ko-KR.xml
index b7c3dc6d1a07d..38b881b30a2e5 100644
--- a/translation/dest/contact/ko-KR.xml
+++ b/translation/dest/contact/ko-KR.xml
@@ -55,9 +55,7 @@
특정 상황에서 봇 계정을 상대로 플레이할 때, 플레이어가 레이팅을 얻기 위해 부정행위를 하는 것으로 판단될 경우 레이팅 포인트가 부여되지 않을 수 있습니다.에러 페이지에러 페이지가 나온 경우 여기에서 신고해주세요:
- 대회를 방송하고 싶습니다Lichess에서 나만의 방송을 하는 방법을 알아보세요
- 또한 공식 방송에 대해 방송 팀에 문의할 수도 있습니다.차단 또는 IP 제한에 대한 이의를 제기하고 싶습니다엔진 또는 부정행위 표시%s에서 이의를 제기할 수 있습니다.
diff --git a/translation/dest/contact/lb-LU.xml b/translation/dest/contact/lb-LU.xml
index f4c9369168088..5cf27b48e52db 100644
--- a/translation/dest/contact/lb-LU.xml
+++ b/translation/dest/contact/lb-LU.xml
@@ -49,7 +49,6 @@
Vergewësser dech, dass du eng gewäerte Partie gespillt hues. Ongewäerte Partië beaflossen d\'Wäertung net.FeelersäitWann s du op eng Feelersäit gestouss bass, kanns du se mellen:
- Ech wëll een Turnéier iwwerdroenAsproch géint een Bann oder eng IP RestriktiounEngine- oder BedruchsmarkéierungDu kanns däin Asproch un %s schécken.
diff --git a/translation/dest/contact/lt-LT.xml b/translation/dest/contact/lt-LT.xml
index eff2f0c9b7825..3ec7c133009e5 100644
--- a/translation/dest/contact/lt-LT.xml
+++ b/translation/dest/contact/lt-LT.xml
@@ -55,9 +55,7 @@
Tam tikromis aplinkybėmis, jei nustatoma, kad žmogus išnaudoja robotą norėdamas gauti daugiau reitingo taškų, reitinguotas žaidimas prieš roboto paskyrą gali nesuteikti reitingo taškų.Klaidos puslapisJei susidūrėte su klaidos puslapiu galite apie jį pranešti:
- Noriu transliuoti turnyrąIšmokite kurti savo transliacijas per Lichess
- Dėl oficialių transliacijų galite susisiekti su transliacijų komanda.Apeliuoti blokavimą ar IP adreso apribojimąVariklio ar sukčiavimo žymėApeliaciją galite siųsti %s.
diff --git a/translation/dest/contact/lv-LV.xml b/translation/dest/contact/lv-LV.xml
index 7ee61bfea2719..3b400fdb99c4a 100644
--- a/translation/dest/contact/lv-LV.xml
+++ b/translation/dest/contact/lv-LV.xml
@@ -55,9 +55,7 @@
Noteiktos gadījumos, spēlējot pret datorprogrammu, par vērtētām spēlēm nepiešķir punktus, ja ir noteikts, ka spēlētājs ļaunprātīgi izmanto programmu, lai paaugstinātu reitingu.Kļūdas lapaJa saskārāties ar kļūdas lapu, varat par to ziņot:
- Vēlos pārraidīt turnīruUzzini kā veidot savas pārraides Lichess-ā
- Vari arī sazināties ar pārraižu komandu par oficiālajām pārraidēm.Pārsūdzēt liegumu vai IP ierobežojumuDzinēja vai šmaukšanās atzīmeVarat iesniegt lūgumu %s.
diff --git a/translation/dest/contact/nb-NO.xml b/translation/dest/contact/nb-NO.xml
index 4793a1e449889..33275a4871f32 100644
--- a/translation/dest/contact/nb-NO.xml
+++ b/translation/dest/contact/nb-NO.xml
@@ -55,9 +55,7 @@
Dersom det blir slått fast at en spiller misbruker en botkonto for å manipulere ratingpoengene, kan det hende det ikke blir gitt poeng for partiet.FeilsideHvis du støtte på en feilside, kan du rapportere det:
- Jeg vil overføre en turneringLær hvordan du lager overføringer hos Lichess
- Du kan ellers kontakte overføringsgruppen angående offisielle overføringer.Klage ved utestenging eller IP-restriksjonAnmerkning om juks eller maskinbrukDu kan klage til %s.
diff --git a/translation/dest/contact/nl-NL.xml b/translation/dest/contact/nl-NL.xml
index c617a9e472804..73d34f644d870 100644
--- a/translation/dest/contact/nl-NL.xml
+++ b/translation/dest/contact/nl-NL.xml
@@ -55,9 +55,7 @@
Wanneer een speler tegen een bot-account speelt, worden onder bepaalde omstandigheden geen ratingpunten toegekend wanneer blijkt dat de speler de bot misbruikt om ratingpunten te winnen.FoutpaginaAls u te maken kreeg met een foutpagina, kunt u dat melden:
- Ik wil een tornooi uitzendenLees hoe je je eigen uitzendingen op Lichess maakt
- Je kunt ook het uitzendingsteam contacteren over officiële uitzendingen.Vragen om een ban of IP beperkingSchaakcomputer of valsspel markeringU kunt een verzoek sturen naar %s.
diff --git a/translation/dest/contact/nn-NO.xml b/translation/dest/contact/nn-NO.xml
index cb8ed04bbe967..976596bc9f23d 100644
--- a/translation/dest/contact/nn-NO.xml
+++ b/translation/dest/contact/nn-NO.xml
@@ -55,9 +55,7 @@
Dersom det vert slått fast at ein spelar misbrukar ein bot-konto for å manipulera ratingpoeng, kan det hende det ikkje vert gjeven poeng for spelet.FeilsideDersom du støtte på ei feilside kan du rapportere det:
- Eg vil kringkaste ei turneringLær deg korleis du lagar eigne sendingar på Lichess
- Du kan òg ta kontakt med kringkastingsgruppa om det som gjeld offisielle sendingar.Protest ved utestenging eller IP-restriksjonMerknad om juks eller bruk av sjakkcomputerDu kan sende ein appell til %s.
diff --git a/translation/dest/contact/pl-PL.xml b/translation/dest/contact/pl-PL.xml
index 2a898555eeebe..ec53a6acca551 100644
--- a/translation/dest/contact/pl-PL.xml
+++ b/translation/dest/contact/pl-PL.xml
@@ -55,9 +55,7 @@
W pewnych okolicznościach, grając przeciwko botowi, partia rankingowa może nie przynieść punktów, jeśli zostanie rozpoznane, że gracz nadużywa bota do nabijania ich sobie.Strona błęduJeśli znalazłeś się na stronie błędu, możesz to zgłosić:
- Chcę transmitować turniejDowiedz się, jak tworzyć własne transmisje na Lichess
- Możesz również skontaktować się z zespołem nadawczym w sprawie oficjalnych transmisji.Odwołanie od zablokowania konta lub ograniczenia IPSilnik szachowy lub inne oszustwoMożesz wysłać odwołanie do %s.
diff --git a/translation/dest/contact/pt-BR.xml b/translation/dest/contact/pt-BR.xml
index 6d1049360ebd1..fac6ece9bd1e1 100644
--- a/translation/dest/contact/pt-BR.xml
+++ b/translation/dest/contact/pt-BR.xml
@@ -55,9 +55,7 @@
Em certos casos, ao jogar contra uma conta bot, um jogo ranqueado poderá não valer pontos, se for determinado que o jogador está abusando do bot para conseguir pontos.Página de erroSe você encontrou uma página de erro, você pode reportá-la:
- Quero transmitir um torneioAprenda a fazer suas próprias transmissões no Lichess
- Você também pode contatar a equipe de transmissão para saber mais sobre transmissões oficiais.Apelação de banimento ou restrição de IPAssistência de software de xadrezVocê pode enviar uma apelação para %s.
diff --git a/translation/dest/contact/pt-PT.xml b/translation/dest/contact/pt-PT.xml
index d052d6b276448..fa4c4532bd66d 100644
--- a/translation/dest/contact/pt-PT.xml
+++ b/translation/dest/contact/pt-PT.xml
@@ -55,9 +55,7 @@
Em certas circunstâncias, ao jogar contra uma conta bot, uma partida a valer pontos pode não premiar pontos se for determinado que o jogador está abusando do bot para ganhar pontos.Página de erroSe encontras uma página de erro, podes reportá-lo:
- Eu quero transmitir um torneioAprenda a fazer as suas próprias transmissões no Lichess
- Também pode entrar em contato com a equipa de transmissão sobre transmissões oficiais.Apelar a um banimento ou restrição de IPMarcado por fazer batota ou usar a ajuda do computadorPodes enviar um apelo para %s.
diff --git a/translation/dest/contact/ro-RO.xml b/translation/dest/contact/ro-RO.xml
index a234320501449..8d82bbaa6f49b 100644
--- a/translation/dest/contact/ro-RO.xml
+++ b/translation/dest/contact/ro-RO.xml
@@ -55,9 +55,7 @@
În anumite circumstanțe, atunci când se joacă cu un cont de bot, un joc evaluat nu poate acorda puncte dacă se stabilește că jucătorul abuzează de bot pentru a obține puncte de evaluare.Pagina de eroareDacă ai primit o pagină de eroare, o poți raporta:
- Vreau să transmit un turneuÎnvață cum să îți faci propriile transmisiuni pe Lichess
- De asemenea, puteți contacta echipa de difuzare despre emisiunile oficiale.Aplică pentru un ban sau restricție de IPMotor de asistență sau marcaj de trișarePoți trimite o cerere pe %s.
diff --git a/translation/dest/contact/ru-RU.xml b/translation/dest/contact/ru-RU.xml
index 995d67d796873..abe576325af3c 100644
--- a/translation/dest/contact/ru-RU.xml
+++ b/translation/dest/contact/ru-RU.xml
@@ -55,9 +55,7 @@
В рейтинговых играх против ботов в некоторых случаях очки рейтинга не начисляются, если система считает, что игрок эксплуатирует слабости бота для набивания рейтинга.Сообщение об ошибкеЕсли вы столкнулись с сообщением об ошибке, вы можете сообщить об этом:
- Я хочу стримить турнирУзнайте, как создавать свои собственные стримы на Lichess
- Вы также можете связаться с командой поддержки стримов по вопросам ваших стримов.Обжалование бана аккаунта или ограничения IP-адресаОтметка об использовании шахматных движков или читерствеВы можете отправить апелляцию на %s.
diff --git a/translation/dest/contact/si-LK.xml b/translation/dest/contact/si-LK.xml
index 41c2987dc6fd3..acabef12753b1 100644
--- a/translation/dest/contact/si-LK.xml
+++ b/translation/dest/contact/si-LK.xml
@@ -53,7 +53,6 @@
Rating ප්රදානය කර නැතඔබ Rated ක්රීඩාවක් ක්රීඩා කළ බවට වග බලා ගන්න. Casual ක්රීඩා ක්රීඩකයන්ගේ Rating වලට බලපාන්නේ නැත.දෝෂ පිටුව
- මට තරඟාවලියක් විකාශනය කිරීමට අවශ්යයිLichess හි ඔබේම විකාශන කරන්නේ කෙසේදැයි ඉගෙන ගන්නතහනමක් හෝ IP සීමාවක් සඳහා අභියාචනය කරන්නඑන්ජිම හෝ වංචා ලකුණ
diff --git a/translation/dest/contact/sk-SK.xml b/translation/dest/contact/sk-SK.xml
index 908bd87391fb0..654fd9663f87f 100644
--- a/translation/dest/contact/sk-SK.xml
+++ b/translation/dest/contact/sk-SK.xml
@@ -55,9 +55,7 @@
Za určitých okolností, keď hráte proti botovému účtu, nemusia byť za hodnotenú partiu udelené body, ak sa zistí, že hráč zneužíva bota na zisk bodov.Chybová stránkaAk ste narazili na chybovú stránku, môžete ju nahlásiť:
- Chcem vysielať turnajNaučte sa vytvárať vlastné vysielanie na stránke Lichess
- V súvislosti s oficiálnymi prenosmi môžete tiež kontaktovať vysielací tím.Požiadať o zabanovanie hráča alebo obmedzenie IP adresyZnačka motora alebo podvádzaniaMôžete poslať odvolanie na %s.
diff --git a/translation/dest/contact/sl-SI.xml b/translation/dest/contact/sl-SI.xml
index 6061a04f05215..402ad9265fb68 100644
--- a/translation/dest/contact/sl-SI.xml
+++ b/translation/dest/contact/sl-SI.xml
@@ -55,9 +55,7 @@
V določenih okoliščinah pri igranju proti robotskemu računu rejtingirana igra ne sme dodeliti točk, če se ugotovi, da igralec zlorablja robota za rejtingiranje.Stran z napakoČe ste soočeni s stranjo z napako, jo lahko prijavite:
- Želim prenašati turnirNaučite se narediti lastne oddaje na Lichessu
- Glede uradnih oddaj se lahko obrnete tudi na ekipo oddaje.Pritožba na prepoved ali omejitev IPOznaka za goljufa oziroma uporabnika računalniške pomočiPritožbo lahko pošljete na %s.
diff --git a/translation/dest/contact/sq-AL.xml b/translation/dest/contact/sq-AL.xml
index 95ceca72e8cad..5e56ab4f2ee8e 100644
--- a/translation/dest/contact/sq-AL.xml
+++ b/translation/dest/contact/sq-AL.xml
@@ -55,9 +55,7 @@
Në ca rrethana, kur luhet kundër një llogarie robot, një lojë me pikë mund të mos sjellë pikë, nëse përcaktohet se lojtari po abuzon robotin për pikë vlerësimi.Faqe gabimiNëse hasët një faqe gabimi, mund ta raportoni:
- Dua të transmetoj një turneMësoni se si të krijoni transmetimet tuaja në Lichess
- Mundeni edhe të lidheni me ekipin e transmetimeve, rreth transmetimesh zyrtare.Apeloni për dëbim ose kufizim IP-jeProgram ose shenje hilejeMund të dërgoni një apel tek %s.
diff --git a/translation/dest/contact/sv-SE.xml b/translation/dest/contact/sv-SE.xml
index aa11deb932532..150634cbb047b 100644
--- a/translation/dest/contact/sv-SE.xml
+++ b/translation/dest/contact/sv-SE.xml
@@ -55,9 +55,7 @@
När man spelar mot ett bot-konto kan ett rankat parti under vissa omständigheter inte ge några ranking-poäng. Detta om det fastslås att spelaren missbrukar boten för att manipulera sin rating.FelsidaOm du stöter på en felsida, kan du rapportera det:
- Jag vill sända en turneringLär dig hur du gör dina egna sändningar på Lichess
- Du kan också kontakta sändningsteamet om officiella sändningar.Överklaga en avstängning eller IP-begränsningSchackmotor eller fuskstämpelDu kan skicka ett överklagande till %s.
diff --git a/translation/dest/contact/th-TH.xml b/translation/dest/contact/th-TH.xml
index 862495899ca06..a3ead2cbc67fb 100644
--- a/translation/dest/contact/th-TH.xml
+++ b/translation/dest/contact/th-TH.xml
@@ -55,9 +55,7 @@
ในบางสถานการณ์เมื่อเล่นกับบัญชีบอท เกมที่คิดคะแนนอาจไม่ให้คะแนนหากมีการตัดสินว่าผู้เล่นใช้บอทในทางที่ผิดเพื่อให้ได้แต้มคะแนนหน้านี้มีข้อผิดพลาดถ้าหน้าที่คุณเปิดมีปัญหา คุณสามารถรายงานได้
- ฉันต้องการที่จะออกอากาศทัวร์นาเมนต์เรียนรู้การออกอากาศใน Lichess
- คุณก็สามารถติดต่อทีมออกอากาศในเรื่องการออกอากาศแบบเป็นทางการการยื่นอุทธรณ์สำหรับผู้โดนแบนระบุว่าใช้เครื่องจักรหรือโกงอนุญาติให้ยื่นอุทธรณ์แก่ %s
diff --git a/translation/dest/contact/tr-TR.xml b/translation/dest/contact/tr-TR.xml
index a9334712b5eeb..8a23929712809 100644
--- a/translation/dest/contact/tr-TR.xml
+++ b/translation/dest/contact/tr-TR.xml
@@ -55,9 +55,7 @@
Bot hesaplar ile oynanan bazı puanlı oyunlarda, bir oyuncunun puan kazanmak için botu kötüye kullandığı tespit edilirse bu oyuncu oyundan puan alamayabilir.Hata sayfasıBir hata mesajı alırsanız lütfen bize bildirin:
- Bir turnuva yayını yapmak istiyorumLichess üzerinde kendi yayınlarınızı nasıl yapacağınızı öğrenin
- Ayrıca resmi yayınlar hakkında yayın ekibiyle iletişime geçebilirsiniz.Yasaklamaya itiraz etSatranç motoru ya da hile tespit edildiBaşvurunuzu bu adrese gönderebilirsiniz: %s .
diff --git a/translation/dest/contact/uk-UA.xml b/translation/dest/contact/uk-UA.xml
index ab112243897a1..5e63b727b8651 100644
--- a/translation/dest/contact/uk-UA.xml
+++ b/translation/dest/contact/uk-UA.xml
@@ -55,9 +55,7 @@
За певних обставин при грі проти облікового запису бота, гра з рейтингом не може обраховувати очки, якщо система визначить, що гравець зловживає ботом для отримання рейтингових очок.Сторінка помилкиЯкщо ви зіткнулися з повідомленням про помилку, ви можете повідомити про це:
- Я хочу транслювати турнірДізнайтеся, як робити власні трансляції на Lichess
- Також ви можете зв\'язатися з командою проведення трансляцій щодо офіційних етерів.Оскарження бану або обмеження за IP-адресоюВідмітка про використання шахового рушія або нечесну груВи можете надіслати оскарження на %s.
diff --git a/translation/dest/contact/vi-VN.xml b/translation/dest/contact/vi-VN.xml
index 29f857e9455fb..8fdf6392e587d 100644
--- a/translation/dest/contact/vi-VN.xml
+++ b/translation/dest/contact/vi-VN.xml
@@ -55,9 +55,7 @@
Trong một số trường hợp nhất định khi chơi với tài khoản Bot, ván cờ có xếp hạng có thể không trao điểm nếu xác định được rằng người chơi đang lạm dụng Bot để lấy điểm xếp hạng.Trang lỗiNếu bạn gặp một trang lỗi, bạn có thể báo cáo nó:
- Tôi muốn phát sóng một giải đấuTìm hiểu cách thức phát sóng trên Lichess
- Bạn cũng có thể liên hệ đội ngũ phát sóng về các chương trình phát sóng chính thức.Khiếu nại lệnh cấm, hạn chế hoặc chặn IPĐánh dấu gian lận hoặc dùng động cơ máy tínhBạn có thể gửi khiếu nại đến %s.
diff --git a/translation/dest/contact/zh-CN.xml b/translation/dest/contact/zh-CN.xml
index 7a18d0ea98b99..8fe9ae2ea0fbe 100644
--- a/translation/dest/contact/zh-CN.xml
+++ b/translation/dest/contact/zh-CN.xml
@@ -55,9 +55,7 @@
在与机器人账号的对局中,若发现玩家滥用其以获取积分,那么这场对局将不会授予积分。错误页面如果你遇到错误页面,您可以举报:
- 我想直播一个锦标赛学习如何在 Lichess 创建直播
- 就官方直播相关事宜,你还可以与直播团队联系。申请禁令或限制IP引擎或作弊标记你可以向 %s 发出申诉。
diff --git a/translation/dest/contact/zh-TW.xml b/translation/dest/contact/zh-TW.xml
index 987ba11da7037..79deaff877094 100644
--- a/translation/dest/contact/zh-TW.xml
+++ b/translation/dest/contact/zh-TW.xml
@@ -55,9 +55,7 @@
在與機器人帳號的對局中,若發現玩家濫用其以獲取積分,那麼這場對局將不會授予積分。錯誤頁面如果你遇到了錯誤頁面,你可以回報它:
- 我想直播一個錦標賽學習如何在 Lichess 創建直播
- 就官方直播相關事宜,你還可以與直播團隊聯繫。懲處上訴作弊或電腦操作記號您可以將上訴寄到%s
diff --git a/translation/dest/coordinates/bg-BG.xml b/translation/dest/coordinates/bg-BG.xml
index b7bfc7ef62d61..395bbfa3d6b42 100644
--- a/translation/dest/coordinates/bg-BG.xml
+++ b/translation/dest/coordinates/bg-BG.xml
@@ -13,6 +13,7 @@
Имате 30 секунди да намерите колкото се може повече полета!Давайте до колкото си поискате, няма ограничение за време!Покажи координатите
+ Координати на всяко полеПокажи фигуритеЗапочни упражнениетоНамери полето
diff --git a/translation/dest/coordinates/el-GR.xml b/translation/dest/coordinates/el-GR.xml
index e54ae270562ee..22ec4892dd5cb 100644
--- a/translation/dest/coordinates/el-GR.xml
+++ b/translation/dest/coordinates/el-GR.xml
@@ -13,6 +13,7 @@
Έχετε 30 δευτερόλεπτα για να διαλέξτε σωστά όσα τετράγωνα γίνεται!Πάρτε όσο χρόνο θέλετε, δεν υπάρχει χρονικό όριο!Εμφάνιση συντεταγμένων
+ Συντεταγμένες σε κάθε τετράγωνοΕμφάνιση κομματιώνΈναρξη εξάσκησηςΕύρεση τετραγώνου
diff --git a/translation/dest/coordinates/tr-TR.xml b/translation/dest/coordinates/tr-TR.xml
index 245d1aa591abc..93c4deaff8294 100644
--- a/translation/dest/coordinates/tr-TR.xml
+++ b/translation/dest/coordinates/tr-TR.xml
@@ -13,6 +13,7 @@
30 saniye içinde kaç tane kare bulabilirsen!İstediğin kadar oyna, süre sınırı yok!Koordinatları göster
+ Her karede koordinatlarTaşları gösterAntrenmana başlaKareleri bul
diff --git a/translation/dest/coordinates/uk-UA.xml b/translation/dest/coordinates/uk-UA.xml
index 2aa8a13ef823a..aa1b48441ed20 100644
--- a/translation/dest/coordinates/uk-UA.xml
+++ b/translation/dest/coordinates/uk-UA.xml
@@ -13,6 +13,7 @@
Ви маєте 30 секунд для того, щоб відмітити якнайбільше полів!Витрачайте стільки часу, скільки забажаєте - жодних лімітів!Відображати координати
+ Координати на кожному поліПоказувати фігуриРозпочати тренуванняЗнайти поле
diff --git a/translation/dest/dgt/he-IL.xml b/translation/dest/dgt/he-IL.xml
index 42197b15671e2..bdc43cc689206 100644
--- a/translation/dest/dgt/he-IL.xml
+++ b/translation/dest/dgt/he-IL.xml
@@ -1,48 +1,48 @@
לוח DGT
- ליצ׳ס ו-DGT
+ Lichess ו־DGTהדרישות עבור לוח DGT
- ההגבלות של לוח ה-DGT
- העמוד הזה מאפשר לך לחבר את לוח ה-DGT שברשותך ל-Lichess ולהשתמש בו כדי לשחק.
- כדי לחבר את לוח ה-DGT האלקטרוני שלך יש להתקין את %s.
+ ההגבלות של לוח ה־DGT
+ העמוד הזה מאפשר לך לחבר את לוח ה־DGT שברשותך ל־Lichess ולהשתמש בו כדי לשחק.
+ כדי לחבר את לוח ה־DGT האלקטרוני שלך יש להתקין את %s.ניתן להוריד את התוכנה כאן: %s.אם %1$s מותקן על המחשב הזה, ניתן לבדוק את החיבור שלך אליו על ידי %2$s.פתיחת הקישור הזה
- אם %1$s מותקן במכשיר אחר או בנמל (port) אחר, תצטרכו להגדיר את כתובת ה-IP והנמל פה ב%2$s.
+ אם %1$s מותקן במכשיר אחר או בנמל (port) אחר, תצטרכו להגדיר את כתובת ה־IP והנמל פה ב%2$s.הגדרות התצורהעמוד המשחק צריך להיות פתוח בדפדפן שלכם. הוא לא חייב להופיע על המסך – ניתן למשל למזער אותו. אולם אם תסגרו אותו, המשחק יפסיק לעבוד.הלוח יתחבר באופן אוטומטי לכל המשחקים בתהליך או לכל משחק חדש שתתחילו. בקרוב, יהיה ניתן לבחור אילו מבין המשחקים האלה לשחק באמצעות הלוח.קטגוריות הזמן למשחקים לא מדורגים: קצב קלאסי, מהיר ומשחקי התכתבות.
- קטגוריות הזמן למשחקים מדורגים: התכתבות, קצב קלאסי וחלק מהקצבים המהירים, כולל 15+10 ו-20+0
+ קטגוריות הזמן למשחקים מדורגים: התכתבות, קצב קלאסי וחלק מהקצבים המהירים, כולל 15+10 ו־20+0כשאתם מוכנים, סדרו את הלוח שלהם ולחצו על %s.אם לא זוהה מהלךתחילה, בדקו שעשיתם את המהלך של היריב שלכם גם על הלוח שלהם. לאחר מכן, החזירו את המהלך שלכם ושחקו אותו שוב.
- כמוצא אחרון, ערכו את הלוח בדיוק כפי שהוא מוצג בליצ׳ס, ואז %s
+ כמוצא אחרון, ערכו את הלוח בדיוק כפי שהוא מוצג ב־Lichess, ואז %sטענו את העמוד מחדשDGT - תצורה
- החיבור לליצ׳ס
+ החיבור ל־Lichessיש לך תו OAuth שמתאים למשחק באמצעות לוח DGT.הערך ׳%s׳ התווסף לתפריט שלמעלה, תחת הקטגוריה ׳שחקו׳.לא נוצר תו OAuth מתאים.
- החיבור ללוח ה-DGT
+ החיבור ללוח ה־DGTלחצו כדי ליצור אחד
- הקישור ל-WebSocket של %s
- השתמשו ב-%1$s אלא אם %2$s מופעל במכשיר אחר או בנמל (port) אחר.
+ הקישור ל־WebSocket של %s
+ השתמשו ב־%1$s אלא אם %2$s מופעל במכשיר אחר או בנמל (port) אחר.הקראת מהלכיםכדי שתוכלו להתמקד בלוח, ניתן להקריא את המהלכים ששוחקו.הפעילו הקראההקול של הקרייןהכריזו על כל המהלכים
- בחרו ב-YES כדי להקריא את כל המהלכים. בחרו ב-NO כדי להקריא רק את מהלכי יריבך.
+ בחרו ב־YES כדי להקריא את כל המהלכים. בחרו ב־NO כדי להקריא רק את מהלכי יריבך.פורמט הקראת המסעים
- SAN זהו הסטנדרט בליצ׳ס: Nf6.
+ SAN זהו הסטנדרט ב־Lichess: Nf6.
UCI נפוץ במנועי שחמט: g8f6.מילות מפתחמילות המפתח הן בפורמט JSON. הן משמשות כדי לתרגם את המהלכים והתוצאות לשפה שלך. ברירת המחדל היא אנגלית, אך ניתן לשנות אותה כרצונכם.פתרון תקלותVerbose logging
- כדי לראות את ההודעות ב-Console לחצו Command + Option + C (Mac) or Control + Shift + C (Windows, Linux, Chrome OS)
+ כדי לראות את ההודעות ב־Console לחצו Command + Option + C (Mac) or Control + Shift + C (Windows, Linux, Chrome OS)שחקו עם לוח DGTהגדרות תצורה
diff --git a/translation/dest/emails/he-IL.xml b/translation/dest/emails/he-IL.xml
index e153c3075c180..19feea7bbe702 100644
--- a/translation/dest/emails/he-IL.xml
+++ b/translation/dest/emails/he-IL.xml
@@ -15,6 +15,6 @@
אנו מאחלים לכלים שלך תמיד למצוא את דרכם למלך של יריביך!%s, התחבר/י ל־lichess.org(אם לחיצה אינה עובדת, נסו הדבקה לתוך הדפדפן!)
- זו הודעת שירות בקשר לשימושך ב-%s.
- כדי ליצור איתנו קשר, השתמשו ב-%s.
+ זו הודעת שירות בקשר לשימושך ב־%s.
+ כדי ליצור איתנו קשר, השתמשו ב־%s.
diff --git a/translation/dest/emails/uk-UA.xml b/translation/dest/emails/uk-UA.xml
index 63683d9620763..da23be5613fb1 100644
--- a/translation/dest/emails/uk-UA.xml
+++ b/translation/dest/emails/uk-UA.xml
@@ -5,16 +5,16 @@
Якщо ви не реєструвалися на Lichess, просто проігноруйте це повідомлення.%s, скидання вашого паролю lichess.orgМи отримали запит на скидання пароля для вашого облікового запису.
- Якщо запит виконано вами, натисніть на посилання нижче. Якщо ні, проігноруйте цей лист.
+ Якщо цей запит виконали ви, перейдіть за посиланням нижче. Якщо ні, проігноруйте цей лист.Підтвердьте нову поштову адресу, %sМи отримали запит на зміну вашої поштової адреси.
- Для підтвердження наявності вами доступу до цієї пошти, натисніть на посилання нижче:
+ Щоб підтвердити ваш доступ до цієї пошти, перейдіть за посиланням нижче:Ласкаво просимо на lichess.org, %s
- Ви успішно зареєстрували свій обліковий запис на сайті https://lichess.org.
+ Ви успішно зареєструвалися на https://lichess.org.
-Ось посилання на Ваш профіль: %1$s. Ви зможете налаштувати його за посиланням: %2$s.
+Ось посилання на ваш профіль: %1$s. Ви зможете налаштувати його за посиланням: %2$s.
-Отримуйте задоволення, і хай Ваші фігури завжди знаходять шлях до короля суперника!
+Отримуйте задоволення, і хай ваші фігури завжди знаходять шлях до короля суперника!Увійдіть до lichess.org, %s(Клік по посиланню не працює? Спробуйте вставити його в адресний рядок!)Це службовий лист, пов\'язаний із використанням %s.
diff --git a/translation/dest/faq/ca-ES.xml b/translation/dest/faq/ca-ES.xml
index f5990aca3c54f..d1d6ee6c5ea36 100644
--- a/translation/dest/faq/ca-ES.xml
+++ b/translation/dest/faq/ca-ES.xml
@@ -167,7 +167,7 @@ Mostrem la icona vermella per a avisar-te quan això ocorre. Sovint pots permetr
3. Cliqueu Galetes i Permisos del lloc
4. Desplaceu-se cap avall i cliqueu Reproducció automàtica de contingut multimèdia
5. Afegiu lichess.org a Permet
- Refrenar-me de jugar?
+ Refrenar-me de jugar?trastorn de salut mental independentaparences personalitzades de Lichessmenys opcions de joc
diff --git a/translation/dest/faq/ckb-IR.xml b/translation/dest/faq/ckb-IR.xml
index ac11ec97edefb..b7bf6a7f62d82 100644
--- a/translation/dest/faq/ckb-IR.xml
+++ b/translation/dest/faq/ckb-IR.xml
@@ -140,5 +140,5 @@
کرتە لە ئایکۆنی قفڵەکە بکە کە لەتەنیشت ئەدرەسی lichess.org لە بەستەرەکەدایە لە وێبگەڕەکەت.
دواتر دیاری بکە گەر دەتەوێ ئاگادارکردنەوەکانی لیچێست بۆ بێت یاخود نا.
- خۆم لە یاریکردن بوەستێنم?
+ خۆم لە یاریکردن بوەستێنم?
diff --git a/translation/dest/faq/da-DK.xml b/translation/dest/faq/da-DK.xml
index d486c5260fb60..f1270ab4467e3 100644
--- a/translation/dest/faq/da-DK.xml
+++ b/translation/dest/faq/da-DK.xml
@@ -167,7 +167,7 @@ Vi viser det røde ikon for at advare dig, når dette sker. Ofte kan du udtrykke
3. Klik på Cookies og Website-tilladelser
4. Rul ned og klik på Media autoplay
5. Tilføj lichess.org til Tillad
- Forhindre mig selv i at spille?
+ Forhindre mig selv i at spille?selvstændig psykisk lidelseLichess-brugerstilefærre lobby-puljer
diff --git a/translation/dest/faq/el-GR.xml b/translation/dest/faq/el-GR.xml
index c283799233072..2dc5b5b81f037 100644
--- a/translation/dest/faq/el-GR.xml
+++ b/translation/dest/faq/el-GR.xml
@@ -166,6 +166,6 @@
3. Κάντε κλικ στην επιλογή Cookies και άδειες ιστοσελίδας
4. Κάντε κύλιση προς τα κάτω και κάντε κλικ στην αυτόματη αναπαραγωγή πολυμέσων
5. Προσθέστε το lichess.org στο επιτρέπω
- Να σταματήσω τον εαυτό μου από το να παίζει;
+ Να σταματήσω τον εαυτό μου από το να παίζει;αυτόνομη κατάσταση ψυχικής υγείας
diff --git a/translation/dest/faq/fa-IR.xml b/translation/dest/faq/fa-IR.xml
index a300a82cc021b..77a9c5508767a 100644
--- a/translation/dest/faq/fa-IR.xml
+++ b/translation/dest/faq/fa-IR.xml
@@ -67,7 +67,7 @@
به طور کلی، نام های کاربری نباید: توهین آمیز، جعل هویت شخص دیگری یا تبلیغاتی باشند. میتوانید درباره %1$s بیشتر بخوانید.دستورالعملهاآیا میتوانم نام کاربری خود را تغییر دهم؟
- خیر، نام کاربری به دلایل فنی و عملی قابل تغییر نیست. نامهای کاربری در جاهای مختلف ثبت شده اند: پایگاههای داده، گزارشها و در نظر مردم. می توانید یک بار حروف بزرگ را تنظیم کنید.
+ خیر، نامهای کاربری به دلیلهای فنی و عملی تغییرپذیر نیستند. نامهای کاربری در جاهای زیادی ثبت شدهاند: دادگانها، برونبُردها، گزارشها و در حافظه مردم. میتوانید یک بار کوچکی-بزرگی حرفها را تنظیم کنید.غنائم منحصر به فردبرای به دست آوردنش، hiimgosu خود را به چالش کشید تا تمام بازی های %s با استفاده از جنون برنده شود.یک مسابقه گلولهای ساعتی
diff --git a/translation/dest/faq/fi-FI.xml b/translation/dest/faq/fi-FI.xml
index 8608c3ab2c1b2..c071e10a972bc 100644
--- a/translation/dest/faq/fi-FI.xml
+++ b/translation/dest/faq/fi-FI.xml
@@ -163,7 +163,7 @@ Tällöin sinulle ilmoitetaan asiasta näyttämällä punainen kuvake. Usein voi
3. Valitse Evästeet ja sivuston käyttöoikeudet
4. Vieritä alas ja valitse Median automaattinen toisto
4. Lisää lichess.org listalle \"Salli\"
- Estää itseäni pelaamasta?
+ Estää itseäni pelaamasta?erilliseksi mielenterveyshäiriöksiLichessin käyttäjäkohtaiset tyylitaulassa vähemmän pelivaihtoehtoja
diff --git a/translation/dest/faq/gl-ES.xml b/translation/dest/faq/gl-ES.xml
index 641a78bd2cbcb..a38d21920a71e 100644
--- a/translation/dest/faq/gl-ES.xml
+++ b/translation/dest/faq/gl-ES.xml
@@ -166,7 +166,7 @@ Amosamos a icona vermella para avisarte cando isto ocorre. A miúdo podes permit
3. Fai clic en Cookies e Permisos do Sitio
4. Vai cara abaixo e pulsa Reprodución automática
5. Engade lichess.org a Permitir
- Deixar de xogar?
+ Deixar de xogar?enfermidade mental independentetemas personalizados de Lichessmenos emparellamentos rápidos
diff --git a/translation/dest/faq/gsw-CH.xml b/translation/dest/faq/gsw-CH.xml
index 206b2a52ef464..deb6f5e85adec 100644
--- a/translation/dest/faq/gsw-CH.xml
+++ b/translation/dest/faq/gsw-CH.xml
@@ -168,7 +168,7 @@ Das roti Symbol macht dich druf ufmerksam, dass das passiert. Oft chann mer lich
3. Klick \"Cookies and Site Permissions\"
4. Scroll abwärts und klick \"Media autoplay\"
5. \"Lichess.org\" zum Erlaube bi-füege
- Mich sälber vum Schpille abhalte?
+ Mich sälber vum Schpille abhalte?eigene, geischtige G\'sundheitszueschtandLichess Benutzerstilweniger Lobby-Pools
diff --git a/translation/dest/faq/he-IL.xml b/translation/dest/faq/he-IL.xml
index 3cb3afa0aed8e..0ac3111abef1c 100644
--- a/translation/dest/faq/he-IL.xml
+++ b/translation/dest/faq/he-IL.xml
@@ -17,10 +17,10 @@
האם ישנם אתרים המבוססים על ליצ\'ס?כן. ליצ\'ס אכן עורר השראה לאתרי קוד פתוח אחרים המשתמשים באתר שלנו %1$s, %2$s, או %3$s.באילו קיצורי מקלדת ניתן להשתמש?
- בחלק מהעמודים בליצ׳ס ישנם קיצורי מקלדת שאפשר להשתמש בהם. לחצו על מקש ה-׳?׳ בלוח למידה, בלוח הניתוחים, בחידה או במשחק כדי לקבל רשימה של קיצורי המקלדת הזמינים.
+ בחלק מהעמודים ב־Lichessישנם קיצורי מקלדת שאפשר להשתמש בהם. לחצו על מקש ה־׳?׳ בלוח למידה, בלוח הניתוחים, בחידה או במשחק כדי לקבל רשימה של קיצורי המקלדת הזמינים.משחק הוגןמתי אני זכאי/ת להחזר דירוג אוטומטי מהפסד לרמאים?
- דקה לאחר סימון שחקן/ית, 40 המשחקים המדורגים האחרונים מ-3 הימים האחרונים נבחנים. אם היית היריב/ה של השחקן/ית במשחקים הללו, איבדת דירוג (בגלל הפסד או תיקו) והדירוג שלך לא היה זמני, תקבל/י החזר דירוג. ההחזר מחושב על סמך דירוג השיא שלך והתקדמות הדירוג שלך לאחר המשחק.
+ דקה לאחר סימון שחקן/ית, 40 המשחקים המדורגים האחרונים מ־3 הימים האחרונים נבחנים. אם היית היריב/ה של השחקן/ית במשחקים הללו, איבדת דירוג (בגלל הפסד או תיקו) והדירוג שלך לא היה זמני, תקבל/י החזר דירוג. ההחזר מחושב על סמך דירוג השיא שלך והתקדמות הדירוג שלך לאחר המשחק.
(לדוגמה, אם הדירוג שלך עלה מאוד לאחר המשחקים האלה, יתכן שלא תקבל/י החזר או רק החזר חלקי). ההחזר לעולם לא יעלה על 150 נקודות.מה נעשה לשחקנים שעוזבים משחקים מבלי להיכנע?אם יריבך מבטל משחקים או עוזב אותם לעיתים קרובות, הוא \"יושעה ממשחקים\", מה שאומר שיאסר עליו באופן זמני לשחק. זה לא יצוין באופן פומבי בפרופיל שלו. אם התנהגות זו תמשיך, אורך ההשעיה יעלה - והתנהגות ממושכת מסוג זה עלולה להוביל לסגירת החשבון שלו לצמיתות.
@@ -41,7 +41,7 @@
ליצ\'ס תומך בשחמט רגיל וב%1$s.8 סוגי שחמטמהו הפסד מאית החייל הממוצע (ACPL)?
- הפסד מאית החייל הוא יחידת מידה המשמשת בשחמט כייצוג ליתרון. מאית חייל שווה ל-1/100 מחייל. לכן 100 מאיות חייל = חייל 1. ערכים אלה אינם ממלאים תפקיד רשמי במשחק אך הם מועילים לשחקנים, וחיוניים בשחמט מחשבים, לצורך הערכת עמדות.
+ הפסד מאית החייל הוא יחידת מידה המשמשת בשחמט כייצוג ליתרון. מאית חייל שווה ל־1/100 מחייל. לכן 100 מאיות חייל = חייל 1. ערכים אלה אינם ממלאים תפקיד רשמי במשחק אך הם מועילים לשחקנים, וחיוניים בשחמט מחשבים, לצורך הערכת עמדות.
המהלך הממוחשב הטוב ביותר יאבד אפס מאיות חייל, אך מהלכים פחותים יביאו לעמדה נחותה אשר מיוצגת כאובדן מאיות חייל.
ניתן להשתמש בערך זה כאינדיקטור לאיכות המשחק. ככל שפחות מאיות חייל מופסדות בכל מהלך, כך המשחק יותר מדויק.
@@ -72,7 +72,7 @@
חזרה משולשת מתייחסת ל%1$s, לא תורות. החזרות אינן חייבות להתקיים ברצף.עמדותחזרנו על עמדה שלוש פעמים. מדוע המשחק לא נפסק בתיקו?
- כדי להכריז על תיקו מפאת חזרה על עמדות, אחד השחקנים חייב לדרוש את זה. ניתן לעשות זאת על ידי לחיצה על הכפתור המוצג, או על ידי הצעת תיקו טרם ביצוע המהלך אשר יחזור על העמדה בפעם השלישית. דרישה לתיקו עקב כלל זה לא תלויה בהסכמת היריב. ניתן גם %1$s ליצ׳ס כדי לדרוש תיקו לאחר חזרה משולשת באופן אוטומטי. בנוסף, לאחר חזרה על אותה העמדה חמש פעמים המשחק יסתיים בתיקו בלי צורך בפעולה מצד אחד השחקנים.
+ כדי להכריז על תיקו מפאת חזרה על עמדות, אחד השחקנים חייב לדרוש את זה. ניתן לעשות זאת על ידי לחיצה על הכפתור המוצג, או על ידי הצעת תיקו טרם ביצוע המהלך אשר יחזור על העמדה בפעם השלישית. דרישה לתיקו עקב כלל זה לא תלויה בהסכמת היריב. ניתן גם %1$s Lichess כדי לדרוש תיקו לאחר חזרה משולשת באופן אוטומטי. בנוסף, לאחר חזרה על אותה העמדה חמש פעמים המשחק יסתיים בתיקו בלי צורך בפעולה מצד אחד השחקנים.לקבוע את תצורתחשבונותאילו תארים יש בLichess?
@@ -81,14 +81,14 @@
אימות כשחקן/ית עם תואר בלִיצֶ\'ס נותן גישה לטורנירי זירה לשחקנים כאלה (Titled Arenas).
-יש בליצ׳ס גם את תואר הכבוד %2$s.
+יש ב־Lichessגם את תואר הכבוד %2$s.תארי אמן של מדינות רבותטופס האימות
- האם אני יכול/ה לקבל את דרגת ״אמן ליצ׳ס״ (LM)?
+ האם אני יכול/ה לקבל את דרגת ״אמן Lichess״ (LM)?לא.
- הדרגה הלא רשמית הזו היא לשם כבוד וקיימת ב-Lichess בלבד.
+ הדרגה הלא רשמית הזו היא לשם כבוד וקיימת ב־Lichess בלבד.
-אנו מעניקים אותה לשחקנים ראויים לציון שמפגינים אזרחות טובה ב-Lichess, על פי שיקול דעתנו. אם את/ה זכאי/ת לדרגה זו, תקבל/י מאיתנו הודעה בנידון עם אפשרות לאשר או לדחות את ההצעה.
+אנו מעניקים אותה לשחקנים ראויים לציון שמפגינים אזרחות טובה ב־Lichess, על פי שיקול דעתנו. אם את/ה זכאי/ת לדרגה זו, תקבל/י מאיתנו הודעה בנידון עם אפשרות לאשר או לדחות את ההצעה.
נא לא לבקש את דרגת LM.מה יכול להיות שם המשתמש שלי?
@@ -97,7 +97,7 @@
האם אני יכול/ה לשנות את שם המשתמש שלי?לא, לא ניתן לשנות את שם המשתמש מסיבות פרקטיות וטכניות. שמות משתמש מופיעים במקומות רבים כגון מסדי נתונים, דוחות ומסמכים מיוצאים. הם גם צרובים במוחם של אנשים. ניתן להחליף בין אותיות גדולות ואותיות קטנות פעם אחת.גביעים ייחודיים
- הגביע הזה הוא ייחודי בהיסטוריה של ליצ׳ס, אף אחד מלבד %1$s לא יזכה בו.
+ הגביע הזה הוא ייחודי בהיסטוריה של Lichess, אף אחד מלבד %1$s לא יזכה בו.כדי להשיג אותו, הימגוסו אתגר את עצמו להיכנס ל\'אטרף\' ולנצח בכל המשחקים של %s.טורניר הBullet השעתיZugAddict שידר במשך שעתיים וניסה ללא הצלחה להביס מחשב ברמה 8 במשחק 1+0. Thibault אמר שאם יצליח לעשות זאת בזמן המשדר, הוא יקבל גביע ייחודי. לאחר שעה, הוא הביס את Stockfish וקוימה ההבטחה.
@@ -105,7 +105,7 @@
באיזו מערכת דירוג Lichess משתמש?הדירוג מחושב באמצעות שיטת Glicko-2 שפותחה על ידי מארק גליקמן. זו שיטת דירוג מאוד פופולארית שגופי שחמט רבים עושים בה שימוש (FIDE היא יוצאת מן הכלל ומשתמשת בשיטת Elo).
-שיטות גליקו מסתמכות על מקדמי ודאות. כששחקן נרשם לליצ׳ס, דירוגו יכול לנוע בין 500 ל־2500 ברמת ודאות של 95 אחוזים, כאשר הדירוג ההתחלתי הוא 1500. בתחילה מקדם הוודאות הוא נמוך, ולכן משחק בודד יכול לשנות את הדירוג אף במאות נקודות. אולם ככל שנצברים משחקים הוודאות עולה והשינוי ממשחק למשחק קטן.
+שיטות גליקו מסתמכות על מקדמי ודאות. כששחקן נרשם ל־Lichess, דירוגו יכול לנוע בין 500 ל־2500 ברמת ודאות של 95 אחוזים, כאשר הדירוג ההתחלתי הוא 1500. בתחילה מקדם הוודאות הוא נמוך, ולכן משחק בודד יכול לשנות את הדירוג אף במאות נקודות. אולם ככל שנצברים משחקים הוודאות עולה והשינוי ממשחק למשחק קטן.
נקודה נוספת הדורשת הבהרה היא שככל שעובר זמן מבלי שהשחקן היה פעיל רמת הוודאות קטנה ולכן שוב יגדל השינוי בדירוג ממשחק למשחק. זאת, כדי שהדירוג יהיה מותאם לשינוי ביכולתו של השחקן לאורך זמן.מדוע מופיע סימן שאלה (?) ליד הדירוג שלי?
@@ -113,16 +113,16 @@
השחקן לא השלים מספיק משחקים מדורגים נגד %1$s בקטגוריית הדירוג.יריבים ברמה דומההשחקן לא שיחק מספיק משחקים בזמן האחרון. כתלות במספר המשחקים ששיחקת, יתכן שכעבור שנה של חוסר פעילות הדירוג יהפוך שוב לזמני.
- באופן קונקרטי, הדירוג זמני אם הסטייה בו גדולה מ-110. זוהי רמת הוודאות שלנו באשר לדירוגך. כלל שהסטייה יותר נמוכה, דירוגך יציב יותר.
+ באופן קונקרטי, הדירוג זמני אם הסטייה בו גדולה מ־110. זוהי רמת הוודאות שלנו באשר לדירוגך. כלל שהסטייה יותר נמוכה, דירוגך יציב יותר.איך דירוג וטבלאות דירוג עובדים?כדי להעפיל ל%1$s עליך:טבלת הדירוגלשחק לפחות 30 משחקים מדורגים בקטגוריית הדירוגלשחק בקטגוריית דירוג זו לפחות משחק מדורג אחד בשבוע האחרון
- להיות בעל סטייה בדירוג הנמוכה מ-%1$s בשח סטנדרטי ונמוכה מ-%2$s בגרסאות אחרות
+ להיות בעל סטייה בדירוג הנמוכה מ־%1$s בשח סטנדרטי ונמוכה מ־%2$s בגרסאות אחרותלהיות בעשירייה המובילה לדירוג זה.הדרישה השנייה היא כדי שרק שחקנים פעילים יופיעו בטבלאות האלופים.
- מדוע הדירוגים באתר גבוהים בהשוואה לארגונים ואתרים אחרים כגון FIDE, USCF ו-ICC?
+ מדוע הדירוגים באתר גבוהים בהשוואה לארגונים ואתרים אחרים כגון FIDE, USCF ו־ICC?אין זה נכון לחשוב על דירוג כמספר מוחלט או להשוות אותו למקביליו בארגונים אחרים. לארגונים שונים שחקנים ברמות שונות ושיטות שונות לקביעת הדירוג (Elo, Glicko-2, Glicko או גרסאות שלהן). לגורמים האלה השפעה מכרעת על הדירוג.
עדיף לחשוב על דירוג כמונח יחסי. לכל אוכלוסיית שחקנים בארגון או אתר מסוים, הדירוג ינבא מי ינצח, יפסיד או ישיג תיקו, ובאיזו תדירות. להגיד: ״הדירוג שלי הוא X״ זה חסר משמעות כל עוד אין שחקנים אחרים אליהם הדירוג מושווה.
@@ -130,7 +130,7 @@
הפעילו את מצב זן ב%1$s או על ידי הקשה על %2$s במהלך משחק.הגדרות התצוגההפסדתי משחק עקב בעיות תקשרות/ניתוק. האם ניתן לקבל את נקודות הדירוג שלי בחזרה?
- לצערנו, איננו יכולים להחזיר נקודות דירוג שאבדו עקב תקלת רשת או ניתוק, בין אם היא אצלך או אצלנו (על אף שאצלנו מתרחשות תקלות כאלה רק לעיתים נדירות). כאשר מבוצעת הפעלה מחדש של ליצ׳ס וכתוצאה מכך נגמר לך הזמן, אנו מבטלים את המשחק כדי למנוע הפסד לא הוגן.
+ לצערנו, איננו יכולים להחזיר נקודות דירוג שאבדו עקב תקלת רשת או ניתוק, בין אם היא אצלך או אצלנו (על אף שאצלנו מתרחשות תקלות כאלה רק לעיתים נדירות). כאשר מבוצעת הפעלה מחדש של Lichess וכתוצאה מכך נגמר לך הזמן, אנו מבטלים את המשחק כדי למנוע הפסד לא הוגן.כיצד...להפעיל או לחסום התראות קופצות?צפה בחלון הקופץ המכיל מידע על האתר
@@ -142,17 +142,17 @@
להפעיל ניגון אוטומטי של צלילים?רוב דפדפני האינטרנט לא מאפשרים ניגון צלילים בעמודים חדשים כדי להגן על המשתמשים. כך, לא כל אתר קיקיוני יכול להפציץ אותנו בפרסומות קוליות. בדרך כלל ההגבלה הזאת מבוטלת ברגע שאנו לוחצים על משהו בתוך האתר. בחלק מהדפדפנים, הזזת הכלים בלוח לא נחשבת לחיצה, ואז יהיה עליהם ללחוץ במקום ריק על הלוח כדי לאפשר הפעלת צלילים. תאלצו לעשות זאת כל פעם שאתם מתחילים משחק.
-אנו מציגים סמליל אדום כדי להודיע לכם כשזה קורה. ברוב המקרים, ניתן לאפשר לדפדפן להפעיל צלילים ב-lichess.org כברירת מחדל ובכך לחסוך לחיצות מיותרות על הלוח. עקבו אחר ההוראות הבאות על פי הדפדפן שלכם.
+אנו מציגים סמליל אדום כדי להודיע לכם כשזה קורה. ברוב המקרים, ניתן לאפשר לדפדפן להפעיל צלילים ב־lichess.org כברירת מחדל ובכך לחסוך לחיצות מיותרות על הלוח. עקבו אחר ההוראות הבאות על פי הדפדפן שלכם.מחשבים
- 1. היכנסו ל-lichess.org
-2. לחצו על Ctrl-i ב-Linux או Windows או על cmd ב-MacOS
+ 1. היכנסו ל־lichess.org
+2. לחצו על Ctrl-i ב־Linux או Windows או על cmd ב־MacOS
3. לחצו על הלשונית ״הרשאות״ (Permissions)
-4. אפשרו הפעלת צלילים (Audio) וסרטונים (Video) ב-lichess.org
- 1. היכנסו ל-lichess.org
+4. אפשרו הפעלת צלילים (Audio) וסרטונים (Video) ב־lichess.org
+ 1. היכנסו ל־lichess.org
2. לחצו על סמליל המנעול בשורת החיפוש
3. לחצו על ״הגדרות האתר״
4. אפשרו הפעלת צלילים
- 1. היכנסו ל-lichess.org
+ 1. היכנסו ל־lichess.org
2. לחצו על Safari בתפריט החיפוש
3. לחצו על ״הגדרות עבור lichess.org״
4. אפשרו הפעלה אוטומטית באופן גורף
@@ -161,13 +161,13 @@
3. לחצו על ״עוגיות והרשאות״
4. גללו למטה ולחצו על ״הפעלה אוטומטית של מדיה״
5. הוסיפו את lichess.org לרשימת האתרים המורשים
- למנוע מעצמי להמשיך לשחק?
+ למנוע מעצמי להמשיך לשחק?מצב נפשי
- האפשרות של תוספים חיצוניים ל-Lichess
+ האפשרות של תוספים חיצוניים ל־Lichessפחות אפשרויות משחק בלובילעיתים קרובות אנו מקבלים הודעות ממשתמשים שמבקשים שנעזור להם להפחית את תדירות המשחק שלהם.
-איננו חוסמים משתמשים למעט במצבים של הפרת תנאי השימוש. אנו ממליצים על התקנים חיצוניים, לרבות %1$s, %2$s ו-%3$s. אם אתם רוצים להמשיך לשחק אך לא להתפתות ליצור משחקים קצרים, בדקו את %4$s. הנה אחד עם %5$s.
+איננו חוסמים משתמשים למעט במצבים של הפרת תנאי השימוש. אנו ממליצים על התקנים חיצוניים, לרבות %1$s, %2$s ו־%3$s. אם אתם רוצים להמשיך לשחק אך לא להתפתות ליצור משחקים קצרים, בדקו את %4$s. הנה אחד עם %5$s.
חלק מהשחקנים מרגישים שהם מתמכרים למשחק. למעשה, ארגון הבריאות העולמי מגדיר התמכרות למשחק כ%6$s, המתאפיין בחוסר שליטה על תדירות המשחק ופיתוח של תלות בו על אף השפעותיו השליליות. אם אתם מזהים את הדפוס הזה אצלכם, אנו ממליצים להיוועץ בבן משפחה או באיש מקצוע.
diff --git a/translation/dest/faq/hu-HU.xml b/translation/dest/faq/hu-HU.xml
index 779b846f73e88..f21faa85f1911 100644
--- a/translation/dest/faq/hu-HU.xml
+++ b/translation/dest/faq/hu-HU.xml
@@ -144,4 +144,31 @@ Kattints a lakat ikonra a böngésző címsorában, a lichess.org mellett.
Utána válaszd ki, hogy engedélyezed vagy tiltod az Lichess értesítéseit.Engedélyezed hangok automatikus lejátszását?
+ A legtöbb böngésző a felhasználók védelme érdekében megakadályozhatja a hang lejátszását a frissen betöltött oldalakon. Képzeld el, milyen lenne, ha minden weboldal azonnal hanghirdetésekkel bombázhatna...
+
+A piros némító ikon akkor jelenik meg, ha a böngésző megakadályozta a lichess.org hangjainak lejátszását. Általában ez a korlátozás feloldódik, amint rákattintasz valamire. Egyes mobilböngészőkben egy bábu érintéssel történő húzása nem számít kattintásnak. Ebben az esetben minden játék kezdetén meg kell érintened a táblát, hogy engedélyezd a hangok lejátszását.
+
+A piros ikont azért mutatjuk, hogy figyelmeztessünk, amikor ez történik. Sok esetben lehetséges külön engedélyezni a lichess.org számára a hangok lejátszását. Itt találod az erre vonatkozó utasításokat néhány népszerű böngésző legújabb verziójához.
+ asztali
+ 1. Nyisd meg a lichess.org weboldalt
+2. Használd a Ctrl-i billentyűkombinációt Linuxon és Windowson vagy a cmd-i billentyűkombinációt MacOS-en
+3. Nyisd meg az Engedélyek oldalt
+4. Engedélyezd a videó- és hanglejátszást a lichess. org oldalon
+ 1. Nyisd meg a lichess.org weboldalt
+2. Kattints a lakat ikonra a címsor mellett
+3. Kattints az Oldalbeállításokra
+4. Engedélyezd a hangok lejátszását
+ 1. Nyisd meg a lichess.org weboldalt
+2. Kattints a Safari-ra a menüsorban
+3. Nyisd meg a lichess.org weboldalra vonatkozó beállításokat
+4. Engedélyezd a mindenre vonatkozó automatikus lejátszást
+ 1. Kattints a három pontra a jobb felső sarokban a menü megnyitásához
+2. Nyisd meg a Beállításokat
+3. Nyisd meg a Sütik és oldalengedélyek menüpontot
+4. Görgess lejjebb és nyisd meg a Média automatikus lejátszása menüpontot
+5. Add hozzá a lichess.org weboldalt az engedélyezéshez
+ Hagyjam abba a játékot?
+ mentális betegség
+ Lichess egyéni stílusok
+ kevesebb lobbival
diff --git a/translation/dest/faq/it-IT.xml b/translation/dest/faq/it-IT.xml
index 79961de8653d9..25bc1ee539b00 100644
--- a/translation/dest/faq/it-IT.xml
+++ b/translation/dest/faq/it-IT.xml
@@ -167,6 +167,6 @@ Ti mostriamo l\'icona rossa di muto per avvisarti quando questo succede. Spesso
3. Clicca su Cookies e autorizzazioni del sito
4. Scendi nella pagina e clicca su Riproduzione automatica di contenuti multimediali
5. Aggiungi lichess.org agli autorizzati
- Smettere di giocare?
+ Smettere di giocare?Stili utente di lichess
diff --git a/translation/dest/faq/lb-LU.xml b/translation/dest/faq/lb-LU.xml
index c963825bb3f42..370c21362ebb6 100644
--- a/translation/dest/faq/lb-LU.xml
+++ b/translation/dest/faq/lb-LU.xml
@@ -73,6 +73,6 @@
Wéi...Notifikatiouns-Popups aktivéieren an desaktivéieren?Desktop
- Mech selwer vum s`Spillen ofhalen?
+ Mech selwer vum s`Spillen ofhalen?Lichess-Benotzerstiler
diff --git a/translation/dest/faq/nn-NO.xml b/translation/dest/faq/nn-NO.xml
index 332c39e471fbe..00d5799f46d45 100644
--- a/translation/dest/faq/nn-NO.xml
+++ b/translation/dest/faq/nn-NO.xml
@@ -167,7 +167,7 @@ Vi viser det raude ikonet for å gje ei åtvaring når dette skjer. Ofte kan du
3. Klikk informasjonskapslar og rettar
4. Rull ned og klikk Media autospel
5. Legg til lichess.org for å tillate
- Stoppa meg frå å spela?
+ Stoppa meg frå å spela?eigen mental tilstandLichess brukarstilarfærre lobbysamlingar
diff --git a/translation/dest/faq/ru-RU.xml b/translation/dest/faq/ru-RU.xml
index f578d68749329..9c39de0323734 100644
--- a/translation/dest/faq/ru-RU.xml
+++ b/translation/dest/faq/ru-RU.xml
@@ -167,7 +167,7 @@
3. Щелкните Cookies и разрешения сайта
4. Прокрутите вниз и щёлкните автовоспроизведение Media
5. Добавьте lichess.org для разрешения
- Как воздерживаться от игр?
+ Как воздерживаться от игр?отдельное психическое расстройствопользовательские CSS-стили Lichessменьшее количество вариантов в Зале ожидания
diff --git a/translation/dest/faq/sk-SK.xml b/translation/dest/faq/sk-SK.xml
index f326fc3dea041..92ad5b4cdc0d4 100644
--- a/translation/dest/faq/sk-SK.xml
+++ b/translation/dest/faq/sk-SK.xml
@@ -145,7 +145,7 @@ Najlepšie je považovať rating za „relatívne“ čísla (na rozdiel od „a
Kliknite na ikonu zámku vedľa adresy lichess.org v paneli URL vášho prehliadača.
Potom vyberte, či chcete povoliť alebo blokovať upozornenia od Lichess.
- Ako mám prestať hrať?
+ Ako mám prestať hrať?samostatný stav duševného zdraviaPoužívateľské štýly Lichessmenej prednastavených partií na domovskej stránke
diff --git a/translation/dest/faq/sq-AL.xml b/translation/dest/faq/sq-AL.xml
index 739749c21ee5a..1f46a897a69d2 100644
--- a/translation/dest/faq/sq-AL.xml
+++ b/translation/dest/faq/sq-AL.xml
@@ -167,7 +167,7 @@ Ikonën e kuqe jua shfaqim për t’ju sinjalizuar, kur ndodh kjo. Shpesh, mund
3. Klikoni Leje Cookie-sh dhe Sajti
4. Shkoni më poshtë dhe klikoni “Vetëluajtje mediash”
5. Shtoni lichess.org te Lejoje
- Të ndal veten nga loja?
+ Të ndal veten nga loja?Marrim rregullisht mesazhe nga përdorues ku na kërkohet t’i ndihmojmë të reshtin së luajturi tej mase.
Teksa Lichess-i nuk dëbon, apo bllokon lojtarë, hiq cenime të Kushteve të Shërbimit, rekomandojmë përdorim mjetesh të jashtme për kufizim sjelljeje të tepruar të luajturi. Disa nga sugjerimet e rëndomta për bllokues sajtesh përfshijnë %1$s, %2$s dhe %3$s. Nësedoni të vazhdoni të përdorni sajtin, por pa qenë të joshur nga kontrolle të shpejtë kohe, mund t’ju interesojnë edhe %4$s, ja një me %5$s.
diff --git a/translation/dest/insight/es-ES.xml b/translation/dest/insight/es-ES.xml
index d678781bc1e3a..61f14dbe68159 100644
--- a/translation/dest/insight/es-ES.xml
+++ b/translation/dest/insight/es-ES.xml
@@ -5,7 +5,7 @@
Las valoraciones de %s están protegidasLo sentimos, no puedes ver las valoraciones de %s.Generar valoraciones para %s.
- ¡Procesando datos solo para ti!
+ ¡Procesando datos sólo para ti!¿Tal vez solicitar que cambien su %s?ajustes de valoraciones
diff --git a/translation/dest/keyboardMove/he-IL.xml b/translation/dest/keyboardMove/he-IL.xml
index d828c0265ee68..8ea62d5e189f2 100644
--- a/translation/dest/keyboardMove/he-IL.xml
+++ b/translation/dest/keyboardMove/he-IL.xml
@@ -2,8 +2,8 @@
פקודות קלט מקלדתביצוע מהלך
- הזזת כלי מ-e2 ל-e4
- הזזת פרש ל-c3
+ הזזת כלי מ־e2 ל־e4
+ הזזת פרש ל־c3הצרחה קטנההצרחה גדולההכתרת רגלי c8 למלכה
diff --git a/translation/dest/lag/he-IL.xml b/translation/dest/lag/he-IL.xml
index 2c27d3cca6962..de0abc8658181 100644
--- a/translation/dest/lag/he-IL.xml
+++ b/translation/dest/lag/he-IL.xml
@@ -1,12 +1,12 @@
- האם יש לאג בליצ׳ס?
+ האם יש לאג ב־Lichess?מדידה מתבצעת...לא. והרשת שלך עובדת סבבה.לא. והרשת שלך לא עובדת כראוי.כן. זה יתוקן בקרוב!ועכשיו, התשובה הארוכה! לאג במשחק נגרם משני ערכים לא קשורים אחד לשני (ככל שהם נמוכים יותר כך יותר טוב):
- זמן התגובה של שרתי ליצ׳ס
+ זמן התגובה של שרתי Lichessהזמן שלוקח למהלך להתעדכן בשרת. הוא זהה לכולם, ורק תלוי בשרתים שלנו. הוא נהיה יותר ארוך ככל שיש יותר שחקנים, אבל המפתחים שלנו עושים את המיטב כדי לגרום לו להיות נמוך כמה שיותר. הוא בדרך כלל נשאר מתחת לעשירית שנייה.הרשת שבין ליצ\'ס למכשיר שלךהזמן שלוקח למכשיר שלך לשלוח את המהלך ללִיצֶ\'ס ולקבל את התשובה בחזרה. הוא תלוי במרחק שלך לצרפת (שם נמצאים השרתים שלנו) ובחיבור שלך לאינטרנט. מפתחי לִיצֶ\'ס לא יכולים לתקן לך את האינטרנט, ולכן לא יכולים לגרום לפרמטר זה להיות יותר מהיר.
diff --git a/translation/dest/learn/he-IL.xml b/translation/dest/learn/he-IL.xml
index 9038e8b792fae..bd03587edfa3a 100644
--- a/translation/dest/learn/he-IL.xml
+++ b/translation/dest/learn/he-IL.xml
@@ -14,7 +14,7 @@
הקישו על הצריח כדי להזיזו לכוכב!אספו את כל הכוכבים!ככל שתמעט/י במסעים, תרבה/י בנקודות!
- השתמש/י ב-2 צריחים
+ השתמש/י ב־2 צריחים
כדי לזרז את העניינים!יפה, את/ה שולט/ת בצריחים.הרץ
diff --git a/translation/dest/oauthScope/he-IL.xml b/translation/dest/oauthScope/he-IL.xml
index 6b0052c54e280..5940ae2ba238d 100644
--- a/translation/dest/oauthScope/he-IL.xml
+++ b/translation/dest/oauthScope/he-IL.xml
@@ -1,6 +1,6 @@
- תו גישה אישי חדש ל-API
+ תו גישה אישי חדש ל־APIהתו נותן לאנשים אחרים גישה להשתמש בחשבונך.בחרו בזהירות מה ניתן לעשות בשמכם בחשבונכם.תיאור התו
@@ -31,7 +31,7 @@
יצירה ועדכון של מנוע חיצונייצירה של התחברות מאובטחת לאתרים (עם גישה מלאה)!שימוש בכלים של מנהלים (במסגרת ההרשאות שלך)
- תווי גישה אישיים ל-API
+ תווי גישה אישיים ל־APIניתן לבקש בקשות OAuth מבלי לעבור %s.authorization code flowלחלופין, %s שתוכלו להשתמש בו ישירות לצורך בקשות API.
@@ -39,16 +39,16 @@
שמרו על התווים האלה בזהירות רבה! הם כמו סיסמאות. היתרון בשימוש בתווים על פני סיסמאות הוא שניתן לבטל אותם או לייצר רבים מהם.הנה %1$s ופה ניתן למצוא %2$s.דוגמה ליישומון של תווים אישיים
- תיעוד ה-API
+ תיעוד ה־APIתו גישה חדש
- תווי גישה ל-API
+ תווי גישה ל־APIנוצר %sהיה בשימוש לאחרונה %sכבר שיחקת משחקים!הערה לשימוש מתכנתים בלבד:
- ניתן למלא מראש את הטופס הזה על ידי שינויי ה-query parameters של הקישור (URL).
+ ניתן למלא מראש את הטופס הזה על ידי שינויי ה־query parameters של הקישור (URL).לדוגמה: %sמגדיר את ההיקף (scope) של %1$s ושל %2$s ויוצר תיאור לתו הגישה.
- ניתן למצוא את קטעי הקוד של הגדרות ההיקף (scope codes) בקוד ה-HTML של הטופס.
+ ניתן למצוא את קטעי הקוד של הגדרות ההיקף (scope codes) בקוד ה־HTML של הטופס.תוכלו לתת למשתמשים שלכם את הקישורים האלה שמולאו מראש כדי לעזור להם לקבל את התווים בהיקף המתאים.
diff --git a/translation/dest/onboarding/bg-BG.xml b/translation/dest/onboarding/bg-BG.xml
index 3ea04e700dfa8..b734e9dde265e 100644
--- a/translation/dest/onboarding/bg-BG.xml
+++ b/translation/dest/onboarding/bg-BG.xml
@@ -1,2 +1,10 @@
-
+
+ Добре дошли!
+ Добре дошли в lichess.org!
+ Това е страницата на Вашия профил.
+ А сега какво? Ето няколко предложения:
+ Научете правилата на шахмата
+ Участвайте в турнири.
+ Учете се с помощта на %1$s и %2$s.
+
diff --git a/translation/dest/onboarding/de-DE.xml b/translation/dest/onboarding/de-DE.xml
index a903f81ba50a5..3245c3c8ff04d 100644
--- a/translation/dest/onboarding/de-DE.xml
+++ b/translation/dest/onboarding/de-DE.xml
@@ -6,7 +6,7 @@
Wird ein Kind dieses Konto verwenden? Vielleicht möchtest du den %s aktivieren.Was nun? Hier sind ein paar Vorschläge:Schachregeln lernen
- Verbessere dein Schach mit Taktikaufgaben.
+ Verbessere dein Schach mit Taktik-Aufgaben.Spiele gegen die künstliche Intelligenz.Spiele gegen Gegner aus der ganzen Welt.Folge deinen Freunden auf Lichess.
diff --git a/translation/dest/onboarding/fa-IR.xml b/translation/dest/onboarding/fa-IR.xml
index 28e40a9bc6d0f..002690c486ab5 100644
--- a/translation/dest/onboarding/fa-IR.xml
+++ b/translation/dest/onboarding/fa-IR.xml
@@ -2,7 +2,7 @@
خوش آمدید!به لیچس خوش آمدید!
- این صفحه نمایهتان است.
+ این صفحه رُخنمایتان است.آیا یک کودک قرار است از این حساب استفاده کند؟ شاید بخواهید %s را فعال کنید.حالا چی؟ اینها پیشنهاد ماست:قوانین شطرنج را یاد بگیرید
diff --git a/translation/dest/onboarding/he-IL.xml b/translation/dest/onboarding/he-IL.xml
index 4c7d4b381b487..671684fcad327 100644
--- a/translation/dest/onboarding/he-IL.xml
+++ b/translation/dest/onboarding/he-IL.xml
@@ -1,7 +1,7 @@
ברוכים הבאים!
- ברוכים הבאים ל-lichess.org!
+ ברוכים הבאים ל־lichess.org!זה עמוד הפרופיל שלך.אם החשבון הזה מיועד לילד/ה, מומלץ להפעיל את %s.מה עכשיו? הנה כמה הצעות:
@@ -9,9 +9,9 @@
השתפרו על ידי פתירת חידות שחמט.שחקו נגד בינה מלאכותית.שחקו נגד יריבים מרחבי העולם.
- עקבו אחר חבריכם בליצ׳ס.
+ עקבו אחר חבריכם ב־Lichess.שחקו בטורנירים.למדו מ%1$s ומ%2$s.
- התאימו את ליצ׳ס להעדפותיכם.
+ התאימו את Lichess להעדפותיכם.שוטטו ברחבי האתר ותהנו :)
diff --git a/translation/dest/patron/fa-IR.xml b/translation/dest/patron/fa-IR.xml
index 73ca6bf6362f3..377cdd521f152 100644
--- a/translation/dest/patron/fa-IR.xml
+++ b/translation/dest/patron/fa-IR.xml
@@ -48,7 +48,7 @@
لطفاً توجه داشته باشید که فقط برگه کمک مالی بالا، جایگاه حامی را به ارمغان میآورد.آیا برخی ویژگیها فقط برای پشتیبانها قابل دسترس است؟نه، زیرا Lichess برای همیشه و برای همه، کاملا رایگان است. قول میدهیم.
-با این حال، حامیان با بالهای معرکهای که در نمایهشان نشان داده میشود، حق پُز دادن دارند.
+با این حال، حامیان با بالهای معرکهای که در رُخنمایشان نشان داده میشود، حق پُز دادن دارند.مقایسه جزئیاتِ ویژگیها را مشاهده کنیدپشتیبانِ Lichess برای یک ماه
@@ -75,7 +75,7 @@
مقدارتراکنشِ شما تکمیل شد، و یک رسید برای کمک مالی شما برایتان ایمیل شد.شما هماکنون یک حساب دائمی پشتیبان دارید.
- به صفحه نمایهتان سَر بزنید!
+ به صفحه رُخنمایتان سَر بزنید!شما هماکنون یک پشتیبانِ مادامالعمرِ Lichess هستید!شما هماکنون برای یک ماه یک پشتیبانِ Lichess هستید!طی یک ماه، دوباره برای شما بدهکاری ثبت نخواهد شد، و حساب کاربری Lichess شما به یک حساب کاربری معمولی برگردانده خواهد شد.
diff --git a/translation/dest/patron/he-IL.xml b/translation/dest/patron/he-IL.xml
index 0c6ff10760da2..e4b806e55a786 100644
--- a/translation/dest/patron/he-IL.xml
+++ b/translation/dest/patron/he-IL.xml
@@ -36,7 +36,7 @@
התומכים המהוללים שהופכים את לִיצֶ\'ס לאפשרילאן הכסף הולך?בראש ובראשונה, לשרתים חזקים.
-לאחר מכן אנחנו משלמים למפתח במשרה מלאה: %s, המייסד של ליצ׳ס.
+לאחר מכן אנחנו משלמים למפתח במשרה מלאה: %s, המייסד של Lichess.צפו במפרט ההוצאות הכלכליותהאם לִיצֶ\'ס הוא ארגון ללא מטרות רווח באופן רשמי?כן, הנה מסמך היצירה (בצרפתית)
@@ -45,7 +45,7 @@
או שאפשר %s.
ליצור קשר עם התמיכה שלנוהאם יש אמצעים אחרים לתרום?
- ליצ׳ס רשום ל-%s.
+ Lichess רשום ל־%s.אנחנו מקבלים גם העברות בנקאיותלידיעתכם: רק טופס התרומה שלעיל מקנה את כנפי התורם/ת.האם יש יתרונות ששמורים רק עבור תומכים?
diff --git a/translation/dest/perfStat/he-IL.xml b/translation/dest/perfStat/he-IL.xml
index 5c37ed7c60906..a5cf9b1c1c119 100644
--- a/translation/dest/perfStat/he-IL.xml
+++ b/translation/dest/perfStat/he-IL.xml
@@ -6,7 +6,7 @@
לא ניתן לקבוע דירוג אמין, מפני שלא שוחקו מספיק משחקים מדורגים.התקדמות לאורך %s המשחקים האחרונים:סטיית תקן בדירוג: %s.
- ערך נמוך יותר אומר שהדירוג יציב יותר. מעל %1$s הדירוג נחשב זמני. כדי להיכלל במדרג השחקנים, ערך זה צריך להיות מתחת ל-%2$s (שחמט רגיל) או %3$s (וריאנטים).
+ ערך נמוך יותר אומר שהדירוג יציב יותר. מעל %1$s הדירוג נחשב זמני. כדי להיכלל במדרג השחקנים, ערך זה צריך להיות מתחת ל־%2$s (שחמט רגיל) או %3$s (וריאנטים).סך כל המשחקיםמשחקים מדורגיםמשחקי טורניר
diff --git a/translation/dest/perfStat/uk-UA.xml b/translation/dest/perfStat/uk-UA.xml
index 4bdfdf6053bdd..ebf84c15bbc9b 100644
--- a/translation/dest/perfStat/uk-UA.xml
+++ b/translation/dest/perfStat/uk-UA.xml
@@ -10,7 +10,7 @@
Всього ігорРейтингові ігриТурнірні ігри
- Ігри з берсерком
+ Партії з берсеркомПроведено часу у гріСередній рейтинг суперниківПеремог
diff --git a/translation/dest/preferences/af-ZA.xml b/translation/dest/preferences/af-ZA.xml
index d6341b22921f3..096e34e2f04b5 100644
--- a/translation/dest/preferences/af-ZA.xml
+++ b/translation/dest/preferences/af-ZA.xml
@@ -48,7 +48,7 @@
Maak skuiwe met jou stemBeperk pyltjies tot geldige skuiweSê \"Good game, well played\" (Goeie spel, mooi gespeel) met \'n nederlaag of gelykop
- Jou voorkeure is gestoor.
+ Jou voorkeure is gestoor.Roll die muis op die bord om skuiwe te herspeelDaaglikse e-pos met \'n lys van jou korrespondensiespelleUitsending het begin
diff --git a/translation/dest/preferences/an-ES.xml b/translation/dest/preferences/an-ES.xml
index 5b13f7a482407..9a3320e239d43 100644
--- a/translation/dest/preferences/an-ES.xml
+++ b/translation/dest/preferences/an-ES.xml
@@ -51,7 +51,7 @@
Indica los movimientos con a tuya vozFlechas enta los movimientos validosDecir \"Buena partida, bien chugada\" en caso de redota u empaz
- Las tuyas preferencias s\'han alzau.
+ Las tuyas preferencias s\'han alzau.Fe servir la rodeta d\'o rate pa reproducir chugadasCorreu electronico diario de notificación con as tuyas partidas per correspondienciaUn presentador ye en vivo
diff --git a/translation/dest/preferences/ar-SA.xml b/translation/dest/preferences/ar-SA.xml
index 8b19eb1fa61d1..b87ad4315e74e 100644
--- a/translation/dest/preferences/ar-SA.xml
+++ b/translation/dest/preferences/ar-SA.xml
@@ -51,7 +51,7 @@
الإدخال يتحرك بصوتكسحب الأسهم في اتجاهات صالحةقُل \"مباراة جيدة، لعبت بشكل جيد\" عند الهزيمة أو التعادل
- تم حفظ تفضيلاتك.
+ تم حفظ تفضيلاتك.مرر على الرقعة لإعادة عرض التحركاتالبريد الإلكتروني اليومي يدرج ألعاب المراسلة الخاصة بكالبث مباشر الآن
diff --git a/translation/dest/preferences/az-AZ.xml b/translation/dest/preferences/az-AZ.xml
index 87bc2f780af0e..b1b929f6a8e81 100644
--- a/translation/dest/preferences/az-AZ.xml
+++ b/translation/dest/preferences/az-AZ.xml
@@ -41,5 +41,5 @@
Gedişləri klaviatura ilə daxil etEtibarlı gedişlər üçün oxları göstərMəğlub olduqda və ya heç-heçə etdikdə \"Yaxşı oyun idi, yaxşı oynadın\" deyin
- Tərcihləriniz saxlanıldı.
+ Tərcihləriniz saxlanıldı.
diff --git a/translation/dest/preferences/be-BY.xml b/translation/dest/preferences/be-BY.xml
index ba61c5fbce8a3..ecbd353404f3d 100644
--- a/translation/dest/preferences/be-BY.xml
+++ b/translation/dest/preferences/be-BY.xml
@@ -51,7 +51,7 @@
Уводзьце хады вашым голасамМаляваць стрэлки толькі да магчымых хадоўКазаць \"Good game, well played\" пасля паразы або нічыі
- Вашы налады былі захаваныя.
+ Вашы налады былі захаваныя.Гартайце колцам мышцы на дошцы, каб прагледзець хадыШтодзённае апавяшчэнне па пошце з пералікам вашых гульняў па ліставанніСтрымер вядзе трансляцыю
diff --git a/translation/dest/preferences/bg-BG.xml b/translation/dest/preferences/bg-BG.xml
index 0084c9945ad30..2d710e8dceb23 100644
--- a/translation/dest/preferences/bg-BG.xml
+++ b/translation/dest/preferences/bg-BG.xml
@@ -51,7 +51,7 @@
Избирайте ходове с гласа сиОграничи стрелките да показват само допустими ходовеИзпратете в чата \"Good game, well played\" след загуба или реми
- Вашите предпочитания бяха записани.
+ Вашите предпочитания бяха записани.За да прегледате ходовете, превъртете колелцето на мишката над дъскатаЕжедневен имейл със списък на Вашите кореспондентски игриСтриймър започва да излъчва
diff --git a/translation/dest/preferences/bn-BD.xml b/translation/dest/preferences/bn-BD.xml
index 0b5c913946cc9..684f75e79fdfd 100644
--- a/translation/dest/preferences/bn-BD.xml
+++ b/translation/dest/preferences/bn-BD.xml
@@ -39,5 +39,5 @@
দুই বর্গে রাজা সরানদাবার নৌকার উপর দিয়ে রাজাকে সরানকী-বোর্ডের সাথে নিবেশ সরান
- আপনার পচ্ছন্দগুলি সংরক্ষিত করা হয়েছে.
+ আপনার পচ্ছন্দগুলি সংরক্ষিত করা হয়েছে.
diff --git a/translation/dest/preferences/br-FR.xml b/translation/dest/preferences/br-FR.xml
index e00f7c2132b8c..861354235dfca 100644
--- a/translation/dest/preferences/br-FR.xml
+++ b/translation/dest/preferences/br-FR.xml
@@ -42,7 +42,7 @@
O tiplasañ ar roue deus div garrezennDiblasañ ar roue war an tour evit rokañAozañ an touchennaoueg evit c\'hoari gantañ
- Savetaet eo bet ho tibaboù.
+ Savetaet eo bet ho tibaboù.Un tournamant a vo a-benn nebeutMerdeerKlevet ar c\'hloc\'h
diff --git a/translation/dest/preferences/bs-BA.xml b/translation/dest/preferences/bs-BA.xml
index dd786e9a02ba5..ff9932647f09d 100644
--- a/translation/dest/preferences/bs-BA.xml
+++ b/translation/dest/preferences/bs-BA.xml
@@ -50,7 +50,7 @@
Unesite poteze glasomSkačite strelice na važeće potezeKažite \"Dobra partija, dobro odigrano\" nakon poraza ili remija
- Vaše postavke su sačuvane.
+ Vaše postavke su sačuvane.Pomaknite kotačić miša na ploči da biste ponovili potezeDnevne obavijesti e-poštom sa spiskom Vaših dopisnih partijaStrimer ide uživo
diff --git a/translation/dest/preferences/ca-ES.xml b/translation/dest/preferences/ca-ES.xml
index b963276ae9556..ae3c012b5f429 100644
--- a/translation/dest/preferences/ca-ES.xml
+++ b/translation/dest/preferences/ca-ES.xml
@@ -51,7 +51,7 @@
Introduïu moviments amb la vostra veuApuntar fletxes a jugades legalsDir “Bona partida, ben jugat!” quan perds o fas taules
- Les teves preferències s\'han desat.
+ Les teves preferències s\'han desat.Desplaça\'t amb la rodeta pel tauler per reproduir jugadesCorreu electrònic diari de notificació amb les vostres partides per correspondènciaUn streamer que seguiu ha començat una transmissió
diff --git a/translation/dest/preferences/ckb-IR.xml b/translation/dest/preferences/ckb-IR.xml
index df23d1ea3ceb8..0c40882e50bd5 100644
--- a/translation/dest/preferences/ckb-IR.xml
+++ b/translation/dest/preferences/ckb-IR.xml
@@ -50,7 +50,7 @@
فرمانی جوڵە بکە بە دەنگتخەتەکان بە ئاراستەیەکی دروستدا ڕابکێشەلە کاتی شکست یان یەکسانبووندا بڵێ \"یارییەکی باش، بە باشی یاریت کرد\"
- هەڵبژاردنەکانت هەڵگیراون.
+ هەڵبژاردنەکانت هەڵگیراون.بۆ دووبارەکردنەوەی جوڵەکان، تختەی شەتڕەنجەکە بەرەو سەر و خوار بجوڵێنەئیمەیڵی ڕۆژانە کە نامە ناردنەکەت لە یاریەکاندا دەخاتە ڕووکەسێک دەچێتە پەخشی ڕاستەوخۆ
diff --git a/translation/dest/preferences/cs-CZ.xml b/translation/dest/preferences/cs-CZ.xml
index 12ed32aee33ad..e110cb43b7893 100644
--- a/translation/dest/preferences/cs-CZ.xml
+++ b/translation/dest/preferences/cs-CZ.xml
@@ -51,7 +51,7 @@
Zadávání tahů hlasemPřichytit šipky k platným tahůmŘekněte \"Good game, well played\" (překlad: \"Dobrá hra, pěkně zahráno\") po porážce nebo remíze
- Vaše nastavení bylo uloženo.
+ Vaše nastavení bylo uloženo.Rolováním na šachovnici přehrát tahyDenní e-mailové oznámení se seznamem vašich korespondenčních herStreamer vysílá živě
diff --git a/translation/dest/preferences/cv-CU.xml b/translation/dest/preferences/cv-CU.xml
index 24460615902db..51eb619b690e3 100644
--- a/translation/dest/preferences/cv-CU.xml
+++ b/translation/dest/preferences/cv-CU.xml
@@ -26,7 +26,7 @@
Куҫӑма ҫирӗплетессиКуҫӑн мар вӑйӑсемВӑрах тата чикӗсӗр
- Улӑштарни упраннӑ.
+ Улӑштарни упраннӑ.БраусӑрХатӗр
diff --git a/translation/dest/preferences/cy-GB.xml b/translation/dest/preferences/cy-GB.xml
index 9062ec2106747..26705c85d7015 100644
--- a/translation/dest/preferences/cy-GB.xml
+++ b/translation/dest/preferences/cy-GB.xml
@@ -39,6 +39,6 @@
Symud y Teyrn dau sgwarGollwng y Teyrn ar ben y CastellMewnbynnu symudiadau efo\'r allweddfwrdd
- Cadwyd eich dewisiadau.
+ Cadwyd eich dewisiadau.Porwr
diff --git a/translation/dest/preferences/da-DK.xml b/translation/dest/preferences/da-DK.xml
index d9aa316a7b817..3e3702f3a11ad 100644
--- a/translation/dest/preferences/da-DK.xml
+++ b/translation/dest/preferences/da-DK.xml
@@ -51,7 +51,7 @@
Angiv træk med din stemmeMarkér lovlige træk med pileSig \"Good game, well played\" (Godt parti, godt spillet) ved nederlag eller remis
- Dine præferencer er blevet gemt.
+ Dine præferencer er blevet gemt.Brug musens scrollhjul på brættet for at afspille trækDaglig e-mailnotifikation med dine korrespondance-spilStreamer går live
diff --git a/translation/dest/preferences/de-DE.xml b/translation/dest/preferences/de-DE.xml
index 548d823aa9e0f..208a3d69dcc17 100644
--- a/translation/dest/preferences/de-DE.xml
+++ b/translation/dest/preferences/de-DE.xml
@@ -51,7 +51,7 @@
Züge per Spracheingabe eingebenPfeile markieren immer mögliche ZügeSage \"Good game, well played\" (Gute Partie, gut gespielt) nach einer Niederlage oder einem Remis
- Deine Einstellungen wurden gespeichert.
+ Deine Einstellungen wurden gespeichert.Auf dem Brett scrollen, um Züge durchzugehenTägliche E-Mail-Benachrichtigung, die deine Fernschachpartien auflistetStreamer ist live
diff --git a/translation/dest/preferences/el-GR.xml b/translation/dest/preferences/el-GR.xml
index 6e0c4d2c60e12..bfd6c8a077c14 100644
--- a/translation/dest/preferences/el-GR.xml
+++ b/translation/dest/preferences/el-GR.xml
@@ -50,7 +50,7 @@
Εισαγωγή κινήσεων με τη φωνή σαςΑγκύρωση βελών σε έγκυρες κινήσειςΑποστολή «Good game, well played» (Ωραίο παιχνίδι, καλά παιγμένο) μετά από ήττα ή ισοπαλία
- Οι προτιμήσεις σας αποθηκεύτηκαν.
+ Οι προτιμήσεις σας αποθηκεύτηκαν.Κυλίστε τον δρομέα πάνω στη σκακιέρα για να ξαναδείτε κινήσειςΝα δέχομαι ημερήσια ειδοποίηση ηλεκτρονικού ταχυδρομείου για τα παιχνίδια διά αλληλογραφίας μουStreamer εκπέμπει ζωντανά
diff --git a/translation/dest/preferences/en-US.xml b/translation/dest/preferences/en-US.xml
index dd179f111c5bd..e9c0b05c84aa5 100644
--- a/translation/dest/preferences/en-US.xml
+++ b/translation/dest/preferences/en-US.xml
@@ -51,7 +51,7 @@
Input moves with your voiceSnap arrows to valid movesSay \"Good game, well played\" upon defeat or draw
- Your preferences have been saved.
+ Your preferences have been saved.Scroll on the board to replay movesDaily mail notification listing your correspondence gamesStreamer goes live
diff --git a/translation/dest/preferences/eo-UY.xml b/translation/dest/preferences/eo-UY.xml
index 91a5abf9c3d0d..5f0a80a4bbcac 100644
--- a/translation/dest/preferences/eo-UY.xml
+++ b/translation/dest/preferences/eo-UY.xml
@@ -51,7 +51,7 @@
Enigi movojn per via voĉoMontri per sagoj nur validajn movojnSkribi \"Good game, well played\" post malvenko aŭ egalvenko
- Viaj preferoj estis konservitaj.
+ Viaj preferoj estis konservitaj.Uzi rulumilon sur la tabelo por ripeti movojnTage retpoŝta sciigo listante viajn korespondajn partiojnFilmprezentisto iĝas vive
diff --git a/translation/dest/preferences/es-ES.xml b/translation/dest/preferences/es-ES.xml
index e2f5b3623478a..d82970c8dc5cd 100644
--- a/translation/dest/preferences/es-ES.xml
+++ b/translation/dest/preferences/es-ES.xml
@@ -51,7 +51,7 @@
Realiza movimientos con tu vozAdherir flechas a movimientos válidosDecir \"Good game, well played\" (Buena partida, bien jugada) al perder o empatar
- Tus preferencias se han guardado.
+ Tus preferencias se han guardado.Usa la rueda de desplazamiento sobre el tablero para volver a mostrar los movimientosNotificación diaria por correo listando tus partidas por correspondenciaEl presentador está en vivo
diff --git a/translation/dest/preferences/et-EE.xml b/translation/dest/preferences/et-EE.xml
index 5cfe227c309cf..be2b2b7eb8221 100644
--- a/translation/dest/preferences/et-EE.xml
+++ b/translation/dest/preferences/et-EE.xml
@@ -47,7 +47,7 @@
Sisesta käigud klaviatuurilLiiguta nooled kehtivate käikude juurdeÜtle kaotuse või viigi korral \"Good game, well played\" (Hea mäng, hästi mängitud)
- Teie eelistused on salvestatud.
+ Teie eelistused on salvestatud.Käikude kordamiseks keri laualIgapäevane e-kiri, mis sisaldab pooleliolevaid kirjavahetusmängeStriimija alustab otseülekannet
diff --git a/translation/dest/preferences/eu-ES.xml b/translation/dest/preferences/eu-ES.xml
index 805cacbb4642b..c4f5875657e42 100644
--- a/translation/dest/preferences/eu-ES.xml
+++ b/translation/dest/preferences/eu-ES.xml
@@ -51,7 +51,7 @@
Egin jokaldiak zure ahotsarekinMarraztutako geziak legezko jokaldietara mugatuTxateam \"Good game, well played\" esan partida galdu edo berdintzean
- Zure ezarpenak ondo gorde dira.
+ Zure ezarpenak ondo gorde dira.Mugitu taula gainean jokaldiak ikustekoJaso posta elektronikoz zure posta-bidezko partiden jakinarazpenen zerrenda eguneroStreamerra zuzenean dago
diff --git a/translation/dest/preferences/fa-IR.xml b/translation/dest/preferences/fa-IR.xml
index c93fe8f6d08cd..6b4cc5992640e 100644
--- a/translation/dest/preferences/fa-IR.xml
+++ b/translation/dest/preferences/fa-IR.xml
@@ -51,7 +51,7 @@
حرکات را با صدای خود وارد کنیدچسبیدن پیکانها به حرکتهای ممکنگفتن \"بازی خوبی بود، خوب بازی کردی\" در هنگام باخت یا تساوی
- تغییرات شما ذخیره شده است
+ تغییرات شما ذخیره شده استاسکرول کردن روی صفحه برای مشاهده مجدد حرکتهاایمیل های روزانه که بازی های شبیه شما را به صورت لیست درمیآورنداستریمر شروع به فعالیت کرد
diff --git a/translation/dest/preferences/fi-FI.xml b/translation/dest/preferences/fi-FI.xml
index 4dab92f06f389..10b162beb1126 100644
--- a/translation/dest/preferences/fi-FI.xml
+++ b/translation/dest/preferences/fi-FI.xml
@@ -51,7 +51,7 @@
Syötä siirtosi puheellaMerkitse mahdolliset siirrot nuolillaSano \"Good game, well played\" (suom. \"Hyvä peli, hyvin pelattu\") tasapelin tai tappion jälkeen
- Asetuksesi on tallennettu.
+ Asetuksesi on tallennettu.Vierittämällä laudan yllä voit katsoa siirtoja uudelleenPäivittäinen sähköposti-ilmoitus, jossa listataan kirjeshakkipelisiStriimaaja aloittaa striimin
diff --git a/translation/dest/preferences/fo-FO.xml b/translation/dest/preferences/fo-FO.xml
index a93e2a7cd6adf..3280ea6c3dcdf 100644
--- a/translation/dest/preferences/fo-FO.xml
+++ b/translation/dest/preferences/fo-FO.xml
@@ -41,5 +41,5 @@
Skriva leikirnar við lyklaborðinumVís lógligar leikir við pílumSig \"Gott talv, væl telvað,\" tá ið tú vinnur ella telvar javnt
- Tínar stillingar eru goymdar.
+ Tínar stillingar eru goymdar.
diff --git a/translation/dest/preferences/fr-FR.xml b/translation/dest/preferences/fr-FR.xml
index 73ebb3822f8b5..f38445a6d3cc5 100644
--- a/translation/dest/preferences/fr-FR.xml
+++ b/translation/dest/preferences/fr-FR.xml
@@ -50,8 +50,8 @@
Saisir les coups au clavierUtiliser la reconnaissance vocale pour déplacer les piècesRestreindre les flèches aux coups valides
- Dire \"Good game, well played\" c.-à.-d. \"Bonne partie, bien joué\", en cas de défaite ou de nulle
- Vos préférences ont été sauvegardées.
+ Dire \"Bonne partie, bien jouée\" en cas de défaite ou de nulle
+ Vos préférences ont été sauvegardées.Parcourez les coups avec la molette de la souris sur l\'échiquierEmail quotidien de la liste de vos parties par correspondanceLe diffuseur passe en direct
diff --git a/translation/dest/preferences/ga-IE.xml b/translation/dest/preferences/ga-IE.xml
index bda4761544a13..34ddebba76d90 100644
--- a/translation/dest/preferences/ga-IE.xml
+++ b/translation/dest/preferences/ga-IE.xml
@@ -47,7 +47,7 @@
Bogann ionchur leis an méarchlárSnap saigheada chuig bearta dlithiúilAbair \"Cluiche maith, Grma\" ar aon cluiche cailte nó cothroma
- Sábháladh do chuid sainroghanna.
+ Sábháladh do chuid sainroghanna.Scrollaigh ar an gclár chun bearta a athimirtRíomhphost laethúil ag liostú do chluichí comhfhreagraisSraoilleán ag craoladh beo
diff --git a/translation/dest/preferences/gd-GB.xml b/translation/dest/preferences/gd-GB.xml
index 322060234891e..cd34280054959 100644
--- a/translation/dest/preferences/gd-GB.xml
+++ b/translation/dest/preferences/gd-GB.xml
@@ -16,5 +16,5 @@
Nuair a bhios < 30 diog a thìde air fhàgailDearbhadh a\' ghluasaidGeamannan co-sgrìobhaidh
- Chaidh na roghainnean agad a shàbhaladh.
+ Chaidh na roghainnean agad a shàbhaladh.
diff --git a/translation/dest/preferences/gl-ES.xml b/translation/dest/preferences/gl-ES.xml
index 9c85f14c7bc8f..0ce24861ccdff 100644
--- a/translation/dest/preferences/gl-ES.xml
+++ b/translation/dest/preferences/gl-ES.xml
@@ -51,7 +51,7 @@
Introdución de xogadas coa vozAdherir frechas a movementos válidosDicir \"Good game, well played\" (Boa partida, ben xogada) ao perder ou empatar
- As túas preferencias foron gardadas.
+ As túas preferencias foron gardadas.Usar a roda do rato para amosar os movementosNotificación diaria por email coas túas partidas por correspondenciaUn presentador comeza unha transmisión en directo
diff --git a/translation/dest/preferences/gsw-CH.xml b/translation/dest/preferences/gsw-CH.xml
index d41f64212685e..b22876d55c232 100644
--- a/translation/dest/preferences/gsw-CH.xml
+++ b/translation/dest/preferences/gsw-CH.xml
@@ -51,7 +51,7 @@
Züg per SprachigabMöglichi Züg werded mit Pfil azeigtSäg \"guet gschpillt\" nach ere Niderlag oder bi me Remis
- Dini Ischtellige sind gschpeicheret.
+ Dini Ischtellige sind gschpeicheret.Mit em Muszeiger uf em Brätt, chasch mit em Musrad all Züg vor- und zrugg scrolleTäglichi E-Mail-Benachrichtigung, wo Dini Fernschachpartie uflischtetDe Streamer gaht live
diff --git a/translation/dest/preferences/he-IL.xml b/translation/dest/preferences/he-IL.xml
index 26dcc85739804..9fa30f03c2ea3 100644
--- a/translation/dest/preferences/he-IL.xml
+++ b/translation/dest/preferences/he-IL.xml
@@ -38,7 +38,7 @@
לחצו על מקש <ctrl> בזמן הקידום כדי להשבית זמנית את ההכתרה האוטומטיתכאשר מבצעים קדם-מהלךהכרז על תיקו בחזרה משולשת באופן אוטומטי
- כשהזמן הנותר קטן מ-30 שניות
+ כשהזמן הנותר קטן מ־30 שניותאישור המהלכיםניתן לביטול במהלך המשחק באמצעות תפריט הלוחבמשחקים בהתכתבות
@@ -51,7 +51,7 @@
ביצוע מהלכים באמצעות דיבורהתאמת החצים למסעים חוקייםכתבו ״Good game, well played\" בצ׳אט לאחר הפסד או תיקו (בתרגום חופשי: משחק יפה, שיחקת טוב)
- העדפותיך נשמרו.
+ העדפותיך נשמרו.גלול על גבי הלוח כדי להראות מהלכים קודמיםהודעת מייל יומית עם רשימת המשחקים שלך בהתכתבותמשדר עולה לשידור חי
@@ -62,8 +62,8 @@
הזמנות למשחקיםטורניר מתחיל בקרובאוזל הזמן במשחק התכתבות
- התראות פעמון בליצ׳ס
- התראה למכשיר גם כשאינך מחובר/ת לליצ׳ס
+ התראות פעמון ב־Lichess
+ התראה למכשיר גם כשאינך מחובר/ת ל־Lichessדפדפןמכשירהשמע צליל עבור התראות פעמון
diff --git a/translation/dest/preferences/hi-IN.xml b/translation/dest/preferences/hi-IN.xml
index 1a396b76c5174..595cc550da9fe 100644
--- a/translation/dest/preferences/hi-IN.xml
+++ b/translation/dest/preferences/hi-IN.xml
@@ -49,7 +49,7 @@
कंप्यूटर कीबोर्ड के साथ इनपुट करेंमान्य चाल के लिए स्नैप तीरहार या ड्रॉ पर \"अच्छा खेल, अच्छा खेला\" कहें
- आपकी प्राथमिकताएं सेव कर ली गई हैं
+ आपकी प्राथमिकताएं सेव कर ली गई हैंपिछली चालें पुनः देखने के लिए बोर्ड पर स्क्राल करेंआपके पत्राचार खेलों को सूचीबद्ध करने वाली दैनिक मेल अधिसूचना
diff --git a/translation/dest/preferences/hr-HR.xml b/translation/dest/preferences/hr-HR.xml
index 4af87974f3d95..17e45ae488cfd 100644
--- a/translation/dest/preferences/hr-HR.xml
+++ b/translation/dest/preferences/hr-HR.xml
@@ -48,7 +48,7 @@
Omogući unošenje poteza tipkovnicomCrtaj strelice za planiranje budućih potezaReci \"Dobra partija, odlićno odigrano\" kad izgubiš ili odigraš remi
- Tvoje promjene su spremljene.
+ Tvoje promjene su spremljene.Pomakni kotačić miša iznad ploče za pregled potezaDnevna obavijest putem pošte s popisom vaših dopisnih igaraStreamer ide uživo
diff --git a/translation/dest/preferences/hu-HU.xml b/translation/dest/preferences/hu-HU.xml
index a5fb439067aa9..edcaea29cc509 100644
--- a/translation/dest/preferences/hu-HU.xml
+++ b/translation/dest/preferences/hu-HU.xml
@@ -50,7 +50,7 @@
Lépj a hangod segítségévelNyilak illesztése a szabályos lépésekhez\"Good game, well played\" üzenet küldése döntetlen vagy vereség esetén
- Beállítások elmentve.
+ Beállítások elmentve.Lépések visszajátszása görgetésselNapi email a folyamatban lévő levelezős játszmákrólEgy streamer műsort ad
diff --git a/translation/dest/preferences/hy-AM.xml b/translation/dest/preferences/hy-AM.xml
index 974fe22eecd53..3dea25e3bc800 100644
--- a/translation/dest/preferences/hy-AM.xml
+++ b/translation/dest/preferences/hy-AM.xml
@@ -48,7 +48,7 @@
Քայլերի ներմուծումը ձայնի միջոցովՍլաքներով ցույց տալ միայն թույլատրելի քայլերըՊարտությունից կամ ոչ-ոքիից հետո զրուցարանում գրել. «Good game, well played»
- Ձեր նախընտրությունները պահպանված են
+ Ձեր նախընտրությունները պահպանված ենՔայլերը դիտելու համար մկնիկի անիվը պտտեք խաղատախտակի վրաՍտուդիայի հրավերՆամակագրական խաղին առնչվող թարմացումներ
diff --git a/translation/dest/preferences/ia-IA.xml b/translation/dest/preferences/ia-IA.xml
index 9410d9dee0774..4a73b8b10bf24 100644
--- a/translation/dest/preferences/ia-IA.xml
+++ b/translation/dest/preferences/ia-IA.xml
@@ -41,5 +41,5 @@
Entrata de movimentos con le clavieroRestringer le sagittas al movimentos valideDicer \"Good game, well played\" (Bon partita, ben jocate) post defaite o partita nulle
- Tu preferentias ha essite salveguardate.
+ Tu preferentias ha essite salveguardate.
diff --git a/translation/dest/preferences/id-ID.xml b/translation/dest/preferences/id-ID.xml
index 183b01b8bd692..960c4ce754b0a 100644
--- a/translation/dest/preferences/id-ID.xml
+++ b/translation/dest/preferences/id-ID.xml
@@ -48,7 +48,7 @@
Melangkah dengan menggunakan keyboardArahkan panah ke arah yang benarUcapkan \"Good game, well played\" apabila kalah atau seri
- Pengaturan telah disimpan.
+ Pengaturan telah disimpan.Gulir pada papan untuk mengulang gerakanEmail harian yang berisi daftar permainan korespondensi andaStreamer memulai siaran
diff --git a/translation/dest/preferences/is-IS.xml b/translation/dest/preferences/is-IS.xml
index 06200c32b3d63..8a277f82b2bd1 100644
--- a/translation/dest/preferences/is-IS.xml
+++ b/translation/dest/preferences/is-IS.xml
@@ -40,5 +40,5 @@
Færa kóng á hrókinnLeika með lyklaborðinuSegja \"Good game, well played\" sjálfkrafa eftir tapi eða jafntefli
- Stillingar þínar voru vistaðar
+ Stillingar þínar voru vistaðar
diff --git a/translation/dest/preferences/it-IT.xml b/translation/dest/preferences/it-IT.xml
index 6b2170903c626..6b15a77374e0b 100644
--- a/translation/dest/preferences/it-IT.xml
+++ b/translation/dest/preferences/it-IT.xml
@@ -51,7 +51,7 @@
Muovi con la tua voceCollega le frecce a mosse valideDi\' \"Good game, well played\" alla sconfitta o al pareggio
- Le tue preferenze sono state salvate.
+ Le tue preferenze sono state salvate.Scorri sulla scacchiera per riprodurre le mosseNotifica di posta giornaliera che elenca le tue partite per corrispondenzaLo streamer va in diretta
diff --git a/translation/dest/preferences/ja-JP.xml b/translation/dest/preferences/ja-JP.xml
index 8245c48a65467..4e8ab20b829b6 100644
--- a/translation/dest/preferences/ja-JP.xml
+++ b/translation/dest/preferences/ja-JP.xml
@@ -51,7 +51,7 @@
手を声で入力可能な手を矢印で表示負けかドローの際に「Good game, well played」と言う
- 設定が保存されました。
+ 設定が保存されました。ボード上スクロールで手を再現通信戦の対局をリストにした毎日のメール通知配信を始めた時
diff --git a/translation/dest/preferences/jbo-EN.xml b/translation/dest/preferences/jbo-EN.xml
index a4e34ee89c6fa..b5ed492650dab 100644
--- a/translation/dest/preferences/jbo-EN.xml
+++ b/translation/dest/preferences/jbo-EN.xml
@@ -26,5 +26,5 @@
masno nunkeilo tadji be lo badydi\'ulujnunmu\'ujarco tu\'a lo nunmu\'u se pi\'o lo batkyfoi
- lo selnei be do pu se rejgau
+ lo selnei be do pu se rejgau
diff --git a/translation/dest/preferences/ka-GE.xml b/translation/dest/preferences/ka-GE.xml
index 9ea212c14df23..fb70f038efb18 100644
--- a/translation/dest/preferences/ka-GE.xml
+++ b/translation/dest/preferences/ka-GE.xml
@@ -33,5 +33,5 @@
როქის მეთოდიმეფის ორი უჯრით გადაადგილებამეფის ეტლზე მიტანა
- თქვენი პარამეტრები დამახსოვრებულია.
+ თქვენი პარამეტრები დამახსოვრებულია.
diff --git a/translation/dest/preferences/kk-KZ.xml b/translation/dest/preferences/kk-KZ.xml
index b3ee50191b005..cf6e06eca8585 100644
--- a/translation/dest/preferences/kk-KZ.xml
+++ b/translation/dest/preferences/kk-KZ.xml
@@ -50,7 +50,7 @@
Қадамды дауыспен жасауНұсқағыш тек заңды жүрістерге ғана жабысадыЖеңіліс не тепе-теңдіктен кейін \"Жақсы ойын, қызық болды\" деп айту
- Баптауыңыз сақталды.
+ Баптауыңыз сақталды.Тақта бетінде тіңтуір айналдырумен жүрістерді қайта көрсетуХат-хабарлы ойындарыңыз туралы күнде поштаңызға ескертпе жіберуСтрим басталды
diff --git a/translation/dest/preferences/kmr-TR.xml b/translation/dest/preferences/kmr-TR.xml
index f28fbcc9a3c50..7cda724860db8 100644
--- a/translation/dest/preferences/kmr-TR.xml
+++ b/translation/dest/preferences/kmr-TR.xml
@@ -39,5 +39,5 @@
Şahê du çarçik bide hereketkirinŞahê bi ser kelehê de kaş bikeHemlekirina bi textenivîsê aktîv bike
- Tercîhên te hate qeydkirin.
+ Tercîhên te hate qeydkirin.
diff --git a/translation/dest/preferences/kn-IN.xml b/translation/dest/preferences/kn-IN.xml
index 3c4fde2808905..533a7e3cbe205 100644
--- a/translation/dest/preferences/kn-IN.xml
+++ b/translation/dest/preferences/kn-IN.xml
@@ -50,7 +50,7 @@
ನಿಮ್ಮ ಧ್ವನಿಯೊಂದಿಗೆ ಇನ್ಪುಟ್ ಚಲಿಸುತ್ತದೆಮಾನ್ಯ ಚಲನೆಗಳಿಗೆ ಬಾಣಗಳನ್ನು ಸ್ನ್ಯಾಪ್ ಮಾಡಿಸೋಲು ಅಥವಾ ಡ್ರಾ ಆದ ಮೇಲೆ \"ಒಳ್ಳೆಯ ಆಟ, ಚೆನ್ನಾಗಿ ಆಡಿದೆ\" ಎಂದು ಹೇಳಿ
- ನಿಮ್ಮ ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ಉಳಿಸಲಾಗಿದೆ.
+ ನಿಮ್ಮ ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ಉಳಿಸಲಾಗಿದೆ.ಚಲನೆಗಳನ್ನು ಮರುಪಂದ್ಯ ಮಾಡಲು ಬೋರ್ಡ್ ಮೇಲೆ ಸ್ಕ್ರಾಲ್ ಮಾಡಿನಿಮ್ಮ ಪತ್ರವ್ಯವಹಾರದ ಆಟಗಳನ್ನು ಪಟ್ಟಿ ಮಾಡುವ ದೈನಂದಿನ ಇಮೇಲ್ಸ್ಟ್ರೀಮರ್ ಲೈವ್ ಆಗುತ್ತದೆ
diff --git a/translation/dest/preferences/ko-KR.xml b/translation/dest/preferences/ko-KR.xml
index 4f65a1d37574e..f8702febe718d 100644
--- a/translation/dest/preferences/ko-KR.xml
+++ b/translation/dest/preferences/ko-KR.xml
@@ -50,7 +50,7 @@
음성으로 기물 이동적법한 움직임에만 화살표를 그림패배하거나 무승부 시 \"Good game, well played\"라고 말합니다.
- 설정이 저장되었습니다.
+ 설정이 저장되었습니다.보드에서 스크롤을 해서 수를 앞 뒤로 이동매일 일간 게임의 목록을 보여주는 알림 메일을 받기스트리머가 생방송 시작
diff --git a/translation/dest/preferences/la-LA.xml b/translation/dest/preferences/la-LA.xml
index fa166682833d1..584a0d5f3eebf 100644
--- a/translation/dest/preferences/la-LA.xml
+++ b/translation/dest/preferences/la-LA.xml
@@ -40,5 +40,5 @@
Regem movere in secundum quadrumRegem super turrim movere\"Bene lusimus illum lusum\" dicere te victum vel ludu ancipe
- Praeposititiones tuae conservatae sunt.
+ Praeposititiones tuae conservatae sunt.
diff --git a/translation/dest/preferences/lb-LU.xml b/translation/dest/preferences/lb-LU.xml
index a757841d27a21..664ccb09baf87 100644
--- a/translation/dest/preferences/lb-LU.xml
+++ b/translation/dest/preferences/lb-LU.xml
@@ -50,7 +50,7 @@
Zich per Sproocherkennung aginnFeiler können just legal Zich weisenNo Defaite oder Remis \"Good game, well played\" (Gudd Partie, gudd gespillt) soen
- Deng Astellungen goufen gespäichert.
+ Deng Astellungen goufen gespäichert.Scroll iwwer d\'Briet fir Zich nozespillenDeegleg Email mat Lëscht vun KorrespondenzpartienStreamer geet live
diff --git a/translation/dest/preferences/lt-LT.xml b/translation/dest/preferences/lt-LT.xml
index f01344945512c..bb0fc26af08ae 100644
--- a/translation/dest/preferences/lt-LT.xml
+++ b/translation/dest/preferences/lt-LT.xml
@@ -50,7 +50,7 @@
Įvesti ėjimus balsuRodykles užfiksuoti ties leistinais ėjimaisNepamirškite nugalėti ar po lygiųjų pasakyti, \"Gera partija, ačiū\"
- Jūsų nuostatos buvo išsaugotos.
+ Jūsų nuostatos buvo išsaugotos.Sukite ratuką ant lentos norėdami dar kartą pamatyti ėjimusKasdieniame laiške pateikti korespondensinių žaidimų išrašusTransliuotojas pradeda transliaciją
diff --git a/translation/dest/preferences/lv-LV.xml b/translation/dest/preferences/lv-LV.xml
index d660f87ef3f9d..100f8eb087c06 100644
--- a/translation/dest/preferences/lv-LV.xml
+++ b/translation/dest/preferences/lv-LV.xml
@@ -48,7 +48,7 @@
Ievadīt gājienus ar tastatūruPievilkt bultas pie iespējamiem gājieniemSūtīt \"Good game, well played\" (angļ. val. \"Laba partija, labi nospēlēta\") pēc uzvaras vai neizšķirta
- Jūsu uzstādījumi ir saglabāti.
+ Jūsu uzstādījumi ir saglabāti.Ritiniet peli virs galdiņa, lai skatītu spēles gaituE-pasta ziņojums reizi dienā par jūsu korespondencšaha spēlēmStraumētājs sāk tiešraidi
diff --git a/translation/dest/preferences/mk-MK.xml b/translation/dest/preferences/mk-MK.xml
index 81307c0455d5d..ba6967208357d 100644
--- a/translation/dest/preferences/mk-MK.xml
+++ b/translation/dest/preferences/mk-MK.xml
@@ -41,5 +41,5 @@
Помести го кралот две полињаПомести го кралот врз топотВнеси потези со тастатура
- Вашите поставки се зачувани.
+ Вашите поставки се зачувани.
diff --git a/translation/dest/preferences/ml-IN.xml b/translation/dest/preferences/ml-IN.xml
index 681172a51087b..f2f584348857c 100644
--- a/translation/dest/preferences/ml-IN.xml
+++ b/translation/dest/preferences/ml-IN.xml
@@ -37,5 +37,5 @@
രാജാവിനെ രണ്ടു കാലങ്ങൾ നീക്കുകതേരിനു മുകളിൽ രാജാവിനെ വയ്ക്കുകകീബോർഡ് മുഖേന നീക്കങ്ങൾ നൽകുക
- നിങ്ങളുടെ ക്രമീകരണങ്ങൾ സേവ് ചെയ്തു.
+ നിങ്ങളുടെ ക്രമീകരണങ്ങൾ സേവ് ചെയ്തു.
diff --git a/translation/dest/preferences/mn-MN.xml b/translation/dest/preferences/mn-MN.xml
index d8dac8949b237..6a4e1b2f27fdf 100644
--- a/translation/dest/preferences/mn-MN.xml
+++ b/translation/dest/preferences/mn-MN.xml
@@ -40,7 +40,7 @@
Ноёноо хоёр нүүхНоёноо тэрэгрүүгээ нүүхГарнаас нүүдэл оруулах
- Таны шинэчлэгдсэн тохиргоо хадгалагдлаа.
+ Таны шинэчлэгдсэн тохиргоо хадгалагдлаа.СаналуудТэмцээн удахгүй эхэллээ яараарай!!
diff --git a/translation/dest/preferences/mr-IN.xml b/translation/dest/preferences/mr-IN.xml
index 9a1fd1ef41f13..c04efc0e0619b 100644
--- a/translation/dest/preferences/mr-IN.xml
+++ b/translation/dest/preferences/mr-IN.xml
@@ -51,7 +51,7 @@
तुमच्या आवाजाने इनपुट द्या बाण फक्त वैध चालींसाठीच मर्यादितपराभवानंतर किंवा बरोबरीनंतर \"चांगला खेळ झाला, उत्तम खेळला\" असे म्हणा
- तुमची प्राधान्ये जतन केली गेली आहेत.
+ तुमची प्राधान्ये जतन केली गेली आहेत.चाली परत बघण्यासाठी पटावर स्क्रोल करातुमच्या दीर्घकालीन खेळांची यादी असलेली दैनिक ई-मेल सुचनाजेव्हा स्ट्रीमर प्रसरण सुरू करतो
diff --git a/translation/dest/preferences/nb-NO.xml b/translation/dest/preferences/nb-NO.xml
index 41be5e71246d9..05b6b8df90fb5 100644
--- a/translation/dest/preferences/nb-NO.xml
+++ b/translation/dest/preferences/nb-NO.xml
@@ -51,7 +51,7 @@
Gi trekk med stemmenPiler viser gyldige trekkSi «Good game, well played» («Godt parti, bra spilt») etter tap eller remis
- Innstillingene dine er lagret.
+ Innstillingene dine er lagret.Bruk musehjulet for å spille av trekkDaglig oversikt over fjernsjakkpartiene dine tilsendt på e-postStrømmer begynner å strømme
diff --git a/translation/dest/preferences/ne-NP.xml b/translation/dest/preferences/ne-NP.xml
index 4c5e2fbd32b52..93f75907789b2 100644
--- a/translation/dest/preferences/ne-NP.xml
+++ b/translation/dest/preferences/ne-NP.xml
@@ -37,5 +37,5 @@
राजा दुई कदम चाल्नेराजा हात्तीमा चाल्नेकिबोर्डबाट चाल चलौं
- तपाइका प्राथमिकता सेभ गरिएको छ।
+ तपाइका प्राथमिकता सेभ गरिएको छ।
diff --git a/translation/dest/preferences/nl-NL.xml b/translation/dest/preferences/nl-NL.xml
index 656afb815ea72..f75f736952286 100644
--- a/translation/dest/preferences/nl-NL.xml
+++ b/translation/dest/preferences/nl-NL.xml
@@ -51,7 +51,7 @@
Voer zetten in met je stemGeldige zetten markeren met pijlenZeg \"Goede partij, goed gespeeld\" bij verlies of remise
- Uw voorkeuren werden opgeslagen.
+ Uw voorkeuren werden opgeslagen.Scroll op het bord om zetten opnieuw af te spelenDagelijkse e-mailmeldingen met de lijst van jouw correspondentiepartijenStreamer gaat live
diff --git a/translation/dest/preferences/nn-NO.xml b/translation/dest/preferences/nn-NO.xml
index 74fded53c6cc9..a7cc65359eee0 100644
--- a/translation/dest/preferences/nn-NO.xml
+++ b/translation/dest/preferences/nn-NO.xml
@@ -51,7 +51,7 @@
Oppgje trekk med røystaMarker lovlege trekk med pilerSei \"Bra parti, godt spela\" etter nederlag eller remis
- Preferansane dine er lagra.
+ Preferansane dine er lagra.Rull (\"scroll med musehjulet\") ned på brettet for å spela trekk omattDagleg e-postmelding med ei liste av fjernsjakkpartia dineStrøyminga er i gang
diff --git a/translation/dest/preferences/or-IN.xml b/translation/dest/preferences/or-IN.xml
index 394bf17625e61..4eaa4870b2678 100644
--- a/translation/dest/preferences/or-IN.xml
+++ b/translation/dest/preferences/or-IN.xml
@@ -10,6 +10,6 @@
ଅଧିକ ସମୟ ଦିଅନ୍ତୁଖେଳ ଆଚରଣଆପଣଙ୍କ ସ୍ୱର ସହିତ ଇନପୁଟ୍ ଚଳନ
- ଆପଣଙ୍କ ଅଗ୍ରାଧିକାର ସଞ୍ଚୟ ହୋଇଛି।
+ ଆପଣଙ୍କ ଅଗ୍ରାଧିକାର ସଞ୍ଚୟ ହୋଇଛି।ଆପଣଙ୍କ ଖେଳଗୁଡ଼ିକୁ ତାଲିକାଭୁକ୍ତ କରୁଥିବା ଦୈନିକ ମେଲ୍ ବିଜ୍ଞପ୍ତି
diff --git a/translation/dest/preferences/pl-PL.xml b/translation/dest/preferences/pl-PL.xml
index 9c7adac0e1388..ded862bd60012 100644
--- a/translation/dest/preferences/pl-PL.xml
+++ b/translation/dest/preferences/pl-PL.xml
@@ -51,7 +51,7 @@
Wykonywanie posunięć za pomocą głosuWyrównuj strzałki do legalnych ruchówNapisz \"Good game, well played\" po przegranej lub remisie
- Twoje ustawienia zostały zapisane.
+ Twoje ustawienia zostały zapisane.Przewiń myszką, aby powtórzyć ruchyCodzienne powiadomienia mailowe z listą Twoich partii korespondencyjnychStreamer jest na żywo
diff --git a/translation/dest/preferences/pt-BR.xml b/translation/dest/preferences/pt-BR.xml
index 4c14848d3fd03..ae78fbbec1751 100644
--- a/translation/dest/preferences/pt-BR.xml
+++ b/translation/dest/preferences/pt-BR.xml
@@ -51,7 +51,7 @@
Mova as peças com sua vozInsira setas para movimentos válidosDiga \"Bom jogo, bem jogado\" após a derrota ou empate
- Suas preferências foram salvas.
+ Suas preferências foram salvas.Use o scroll do mouse no tabuleiro para ir passando as jogadasEmail diário listando seus jogos por correspondênciaStreamer começou uma transmissão ao vivo
diff --git a/translation/dest/preferences/pt-PT.xml b/translation/dest/preferences/pt-PT.xml
index db7eb38e82285..2ef5ddbd5f3f4 100644
--- a/translation/dest/preferences/pt-PT.xml
+++ b/translation/dest/preferences/pt-PT.xml
@@ -51,7 +51,7 @@
Insira movimentos com a sua vozAlinhar as setas para sítios para onde as peças se podem moverDizer \"Good game, well played\" (Bom jogo, bem jogado) após uma derrota ou empate
- As tuas preferências foram guardadas.
+ As tuas preferências foram guardadas.Rolar no tabuleiro para repetir os movimentosNotificações diárias por email listando seus jogos por correspondênciaStreamer começou uma transmissão ao vivo
diff --git a/translation/dest/preferences/ro-RO.xml b/translation/dest/preferences/ro-RO.xml
index 92955249e5c59..7898c0013df79 100644
--- a/translation/dest/preferences/ro-RO.xml
+++ b/translation/dest/preferences/ro-RO.xml
@@ -51,7 +51,7 @@
Execută mișcările cu voceaTrage săgețile la mutările valideSpune \"Joc bun, bine jucat\" la înfrângere sau la remiză
- Preferințele tale au fost salvate
+ Preferințele tale au fost salvateDerulează pe tablă pentru a rejuca mutărileNotificare zilnică prin email cu lista jocurilor prin corespondențăUn streamer e live
diff --git a/translation/dest/preferences/ru-RU.xml b/translation/dest/preferences/ru-RU.xml
index ebc856b2585fd..5b86dccc79b85 100644
--- a/translation/dest/preferences/ru-RU.xml
+++ b/translation/dest/preferences/ru-RU.xml
@@ -51,7 +51,7 @@
Вводить ходы голосомПоказывать стрелками только допустимые ходыПисать в чат “Good game, well played” после поражения или ничьей
- Ваши настройки сохранены.
+ Ваши настройки сохранены.Прокручивайте колесо мыши над доской, чтобы смотреть ходыЕжедневно присылать на почту список ваших игр по перепискеСтример начинает трансляцию
diff --git a/translation/dest/preferences/sk-SK.xml b/translation/dest/preferences/sk-SK.xml
index fcd635fe77711..88d27e7122cb2 100644
--- a/translation/dest/preferences/sk-SK.xml
+++ b/translation/dest/preferences/sk-SK.xml
@@ -51,7 +51,7 @@
Zadávanie ťahov pomocou hlasuZobraziť šípky pri možných ťahochNapíš \"Good game, well played\" (v preklade: Dobrá partia, pekne zahrané) po prehre alebo remíze
- Vaše nastavenia boli uložené.
+ Vaše nastavenia boli uložené.Rolovaním po šachovnici prehrávať ťahyDenný mailový výpis Vašich korešpondenčných partiíStreamer začal vysielať
diff --git a/translation/dest/preferences/sl-SI.xml b/translation/dest/preferences/sl-SI.xml
index 3283d38e3441b..f7704bbbb51de 100644
--- a/translation/dest/preferences/sl-SI.xml
+++ b/translation/dest/preferences/sl-SI.xml
@@ -48,7 +48,7 @@
Vnos potez z vašim glasomPostavi puščice po veljavnih potezahReci \"Dobra igra, dobro odigrano\" ob porazu ali remiju
- Nastavitve so bile shranjene.
+ Nastavitve so bile shranjene.Pomaknite se po plošči za predvajanje potezDnevno obvestilo po pošti z naštevanjem vaših korespondenčnih igerStreamer je začel oddajati v živo
diff --git a/translation/dest/preferences/sq-AL.xml b/translation/dest/preferences/sq-AL.xml
index 1401b230ab43b..ee96c27abd571 100644
--- a/translation/dest/preferences/sq-AL.xml
+++ b/translation/dest/preferences/sq-AL.xml
@@ -48,7 +48,7 @@
Jepni lëvizje përmes tastiereKryeni lëvizje përmes zërit tuajShkruaj “Lojë e mirë, bukur luajtët” pas barazimit ose humbjes
- Parapëlqimet tuaja u ruajtën.
+ Parapëlqimet tuaja u ruajtën.Rrëshqitni nëpër tabelë që të riluhen lëvizjeNjoftim i përditshëm me email, që paraqet lojërat tuaja me korrespondencëMesazh i ri te Të marrë
diff --git a/translation/dest/preferences/sr-SP.xml b/translation/dest/preferences/sr-SP.xml
index efe53d28d4a1e..567fae577d043 100644
--- a/translation/dest/preferences/sr-SP.xml
+++ b/translation/dest/preferences/sr-SP.xml
@@ -40,5 +40,5 @@
Помери краља на топаУноеси потезе са тастатуромКажи \"Добра партија, добро одиграно\" након пораза или нерешеног
- Ваше преференце су сачуване.
+ Ваше преференце су сачуване.
diff --git a/translation/dest/preferences/sv-SE.xml b/translation/dest/preferences/sv-SE.xml
index 945cef100860f..a9705ec3cd09f 100644
--- a/translation/dest/preferences/sv-SE.xml
+++ b/translation/dest/preferences/sv-SE.xml
@@ -51,7 +51,7 @@
Gör drag med din röstDra pilar för giltiga dragSäg \"Bra parti, väl spelat\" vid förlust eller remi
- Dina inställningar har sparats.
+ Dina inställningar har sparats.Bläddra på tavlan för att spela upp rörelserDaglig e-postavisering som listar dina korrespondensspelStrömmen går igång
diff --git a/translation/dest/preferences/ta-IN.xml b/translation/dest/preferences/ta-IN.xml
index 8b037fb448f8d..c5c7b1b2a0c47 100644
--- a/translation/dest/preferences/ta-IN.xml
+++ b/translation/dest/preferences/ta-IN.xml
@@ -8,5 +8,5 @@
ஆட்டக்காரரின் மதிப்பீட்டைக் காட்டுசெஸ் கடிகாரம்கூடுதல் நேரம் வழங்கு
- உங்கள் விருப்பங்களை சேமிக்கப்பட்டுள்ளது.
+ உங்கள் விருப்பங்களை சேமிக்கப்பட்டுள்ளது.
diff --git a/translation/dest/preferences/th-TH.xml b/translation/dest/preferences/th-TH.xml
index 3bfbe4eef68cb..434dda66972e7 100644
--- a/translation/dest/preferences/th-TH.xml
+++ b/translation/dest/preferences/th-TH.xml
@@ -51,7 +51,7 @@
เดนหมากโดยใข้เสียงของคุณลูกศรสแน็ปเพื่อการเดินที่ถูกต้องส่งคำว่า \"Good game, well played\" เมี่อแพ้หรือเสมอ
- การตั้งค่าของคุณถูกบันทึกแล้ว
+ การตั้งค่าของคุณถูกบันทึกแล้วเลื่อนกระดานลงเพื่อดูตาเดินที่ผ่านมาอีเมลรายวันแสดงรายการเกมยาวนานของคุณสตรีมเมอร์ไลฟ์สด
diff --git a/translation/dest/preferences/tk-TM.xml b/translation/dest/preferences/tk-TM.xml
index 6dd16aea7b7dc..7473854899530 100644
--- a/translation/dest/preferences/tk-TM.xml
+++ b/translation/dest/preferences/tk-TM.xml
@@ -36,5 +36,5 @@
Şany 2 göçüm süýşüriňŞany ruha tarap süýşüriňGöçümleri klawiatura bilen düz
- Ileri tutmalaryňyz huşda saklandy.
+ Ileri tutmalaryňyz huşda saklandy.
diff --git a/translation/dest/preferences/tl-PH.xml b/translation/dest/preferences/tl-PH.xml
index d5bd227032b11..5f1d0936e0dd9 100644
--- a/translation/dest/preferences/tl-PH.xml
+++ b/translation/dest/preferences/tl-PH.xml
@@ -36,5 +36,5 @@
Galawin ang hari ng dalawang kwadradoIgalaw ang Hari sa rookMaglagay ng mga galaw sa keyboard
- Ang iyong mga kagutuhan ay nai-save na.
+ Ang iyong mga kagutuhan ay nai-save na.
diff --git a/translation/dest/preferences/tp-TP.xml b/translation/dest/preferences/tp-TP.xml
index 3d131d148fa0e..7a108dc3b9767 100644
--- a/translation/dest/preferences/tp-TP.xml
+++ b/translation/dest/preferences/tp-TP.xml
@@ -45,7 +45,7 @@
ilo sitelen la sina sitelen e palimi sitelen e palisa lon supa musi la, o pali ala pali e ni: palisa li nasin tawa tawa ken taso?mi pini ike anu pini pi anpa ala e musi la, o toki \"musi pona, sina pona\" (toki Inli)
- wile sina li awen.
+ wile sina li awen.ilo sike li tawa la o lukin sin e tawailo
diff --git a/translation/dest/preferences/tr-TR.xml b/translation/dest/preferences/tr-TR.xml
index 83c17bba2eda5..a33957d940037 100644
--- a/translation/dest/preferences/tr-TR.xml
+++ b/translation/dest/preferences/tr-TR.xml
@@ -51,7 +51,7 @@
Hamleleri sesinizle sağlayınSadece mümkün hamlelere ok çizBeraberlik veya yenilgiyle biten maçların sonunda \"İyi oyundu, güzel oynadın\" mesajı gönder
- Tercihleriniz kaydedildi.
+ Tercihleriniz kaydedildi.Hamleleri tekrar görmek için fare tekerleğini tahta üzerinde kaydırınGünlük yazışmalı oyunlarınızı listeleyen posta bildirimi alınCanlı yayın başladığında
diff --git a/translation/dest/preferences/uk-UA.xml b/translation/dest/preferences/uk-UA.xml
index 24e500454b5bf..7a8291bba845f 100644
--- a/translation/dest/preferences/uk-UA.xml
+++ b/translation/dest/preferences/uk-UA.xml
@@ -51,7 +51,7 @@
Введення ходів за допомогою голосуСтрілки лише для можливих ходівПисати в чат \"Хороша гра, добре зіграно\" після поразки або нічиєї
- Ваші налаштування збережено.
+ Ваші налаштування збережено.Прокрутіть колесом миші на дошці, для того щоб відтворити ходиЩоденне сповіщення на електронну пошту зі списком ваших заочних ігорСтример почав трансляцію
diff --git a/translation/dest/preferences/ur-PK.xml b/translation/dest/preferences/ur-PK.xml
index a485ba64af9c3..382b35673203f 100644
--- a/translation/dest/preferences/ur-PK.xml
+++ b/translation/dest/preferences/ur-PK.xml
@@ -40,5 +40,5 @@
بادشاہ کو رخ پر منتقل کریںکی بورڈ کے ذریعے چالیں داخل کریںچالیں اپنی آواز سے داخل کریں
- آپ کے اندراج محفوظ کر دیے گئے ہیں
+ آپ کے اندراج محفوظ کر دیے گئے ہیں
diff --git a/translation/dest/preferences/uz-UZ.xml b/translation/dest/preferences/uz-UZ.xml
index 4aa03b9f9ab0f..9703a668c9811 100644
--- a/translation/dest/preferences/uz-UZ.xml
+++ b/translation/dest/preferences/uz-UZ.xml
@@ -47,7 +47,7 @@
Yurish klaviatura orqali amalga oshiriladiIshonchli yurishlarga oʻqlarni tortingMagʻlubiyatga uchraganingizda \"Yaxshi oʻyin, yaxshi oʻnaldi\" deb ayting
- Sizning sozlashlaringiz saqlandi.
+ Sizning sozlashlaringiz saqlandi.Lichess ichidagi qo‘ng‘iroqli xabarLichessdan tashqarida bo‘lganingizdagi qurilma xabariBrauzer
diff --git a/translation/dest/preferences/vi-VN.xml b/translation/dest/preferences/vi-VN.xml
index dc800554dd2c6..8128df9b7c181 100644
--- a/translation/dest/preferences/vi-VN.xml
+++ b/translation/dest/preferences/vi-VN.xml
@@ -1,6 +1,6 @@
- Sửa giao diện
+ Tuỳ chỉnhHiển thịQuyền riêng tưThông báo
@@ -51,7 +51,7 @@
Đầu vào nước đi với giọng nói của bạnTự kéo mũi tên vào ô của nước đi hợp lệTự động nhắn \"Good game, well played\" (Ván cờ hay, chơi hay lắm) sau khi hòa hoặc thua
- Tùy chọn của bạn đã được lưu
+ Tùy chọn của bạn đã được lưuCuộn con chuột trên bàn cờ để xem lại nước điEmail thông báo hàng ngày sẽ bao gồm cả các ván cờ qua thưStreamer đang phát trực tiếp
diff --git a/translation/dest/preferences/zh-CN.xml b/translation/dest/preferences/zh-CN.xml
index a925739d739c5..a3767d5edbf89 100644
--- a/translation/dest/preferences/zh-CN.xml
+++ b/translation/dest/preferences/zh-CN.xml
@@ -51,7 +51,7 @@
用语音输入着法将箭头吸附到有效着法上输棋、和棋后自动发送:“厉害,玩得不错!”
- 你的设置已保存。
+ 你的设置已保存。在棋盘上滚动鼠标滚轮以回退每日发送邮件通知你正在进行的通讯棋局主播开始直播
diff --git a/translation/dest/preferences/zh-TW.xml b/translation/dest/preferences/zh-TW.xml
index d092dee1a5713..1472a6e1187c9 100644
--- a/translation/dest/preferences/zh-TW.xml
+++ b/translation/dest/preferences/zh-TW.xml
@@ -50,7 +50,7 @@
用語音輸入著法將右鍵標示箭頭鎖定到合法棋步輸棋或和棋後自動發送 \"Good game, well played\"。
- 已儲存您的設定。
+ 已儲存您的設定。在騎盤上使用滑鼠滾輪以重新顯示過去棋步每日以電郵列出您當前的長期對局追蹤的直播主開始直播
diff --git a/translation/dest/puzzle/he-IL.xml b/translation/dest/puzzle/he-IL.xml
index d0b8200974503..18cf16d0285e4 100644
--- a/translation/dest/puzzle/he-IL.xml
+++ b/translation/dest/puzzle/he-IL.xml
@@ -32,7 +32,7 @@
חידות לפי פתיחותהפתיחות הנפוצות שלך במשחקים מדורגיםהשתמשו ב״חיפוש בעמוד״ בדפדפן כדי למצוא את הפתיחה המועדפת עליכם!
- השתמשו ב-ctrl+F כדי למצוא את הפתיחה המועדפת עליכם!
+ השתמשו ב־ctrl+F כדי למצוא את הפתיחה המועדפת עליכם!זה לא המהלך!נסו משהו אחר.דירוג: %s
diff --git a/translation/dest/puzzleTheme/fa-IR.xml b/translation/dest/puzzleTheme/fa-IR.xml
index 0500fcff9d51c..a23be5023a9af 100644
--- a/translation/dest/puzzleTheme/fa-IR.xml
+++ b/translation/dest/puzzleTheme/fa-IR.xml
@@ -123,5 +123,5 @@
یک ذره از همه چیز. شما نمی دانید چه چیزی پیش روی شماست، بنابراین شما باید برای هر چیزی آماده باشید! دقیقا مثل بازی های واقعی.بازیهای بازیکندنبال معماهای ایجادشده از بازیهای خودتان یا بازیهای سایر بازیکنان، بگردید.
- این معماها به صورت عمومی هستند و می توانند از %s بارگیری شوند.
+ این معماها به صورت همگانی هستند و میتوانید از %s بارگیریدشان.
diff --git a/translation/dest/puzzleTheme/he-IL.xml b/translation/dest/puzzleTheme/he-IL.xml
index 3bfdb138dbca7..0c441b103dbb3 100644
--- a/translation/dest/puzzleTheme/he-IL.xml
+++ b/translation/dest/puzzleTheme/he-IL.xml
@@ -3,13 +3,13 @@
רגלי מתקדםאחד מהחיילים שלך עמוק בקווי היריב, אולי מאיים להיות מוכתר.יתרון
- נצל/י את ההזדמנות כדי להשיג יתרון מכריע. (הערכת יתרון בין 2.0 ל-6.0)
+ נצל/י את ההזדמנות כדי להשיג יתרון מכריע. (הערכת יתרון בין 2.0 ל־6.0)המט של אנסטסיהפרש, יחד עם צריח או מלכה, לוכדים את המלך היריב בין דופן הלוח לבין כלי מכוחותיו.מט ערביפרש וצריח לוכדים יחד את המלך היריב בפינת הלוח.תקיפה של ו2 או ו7
- מיקוד איומים על הרגלי ב-ו2 או ו7, כמו למשל בפתיחת \"Fried Liver\".
+ מיקוד איומים על הרגלי ב־ו2 או ו7, כמו למשל בפתיחת \"Fried Liver\".משיכההחלפת כלים או הקרבה שמעודדות או מכריחות כלי יריב לנדוד למשבצת שמאפשרת טקטיקת המשך.מט שורה אחורית (״מתחת למים״)
@@ -29,7 +29,7 @@
מט קוזיומלכה מבצעת מט למלך סמוך, ששתי משבצות הבריחה שלו חסומות על ידי כלים מכוחותיו.שוויון
- חזרו למשחק מעמדת הפסד, והבטיחו תיקו או עמדה מאוזנת. (הערכת יתרון קטנה מ-2.0)
+ חזרו למשחק מעמדת הפסד, והבטיחו תיקו או עמדה מאוזנת. (הערכת יתרון קטנה מ־2.0)תקיפת צד המלךתקיפת המלך של היריב, לאחר שהצריח לצד המלך.פינוי
@@ -107,7 +107,7 @@
מוטיב המשלב כלי חשוב מאוים, זז ומאפשר איום או הכאה של כלי חשוב פחות מאחוריו, ההפך מריתוק.מט חנקמט על ידי פרש בו המלך היריב לא מסוגל לזוז כי הוא מוקף (או חנוק) על ידי כלים מכוחותיו.
- משחקי סופר רב-אמנים
+ משחקי סופר רב־אמניםפאזלים ממשחקים של השחקנים הטובים בעולם.כלי לכודכלי לא יכול להימנע מהכאה בגלל צמצום מסעים אפשריים.
@@ -123,5 +123,5 @@
קצת מהכל. לא תדעו למה לצפות. עליכם להיות מוכנים להכל! בדיוק כמו משחקים אמיתיים.המשחקים שליחפשו חידות אשר נוצרו ממשחקים שלכם או של שחקנים אחרים.
- החידות האלו הן נחלת הכלל, וניתן להוריד אותן מ-%s.
+ החידות האלו הן נחלת הכלל, וניתן להוריד אותן מ־%s.
diff --git a/translation/dest/site/af-ZA.xml b/translation/dest/site/af-ZA.xml
index 7d5e2587694c4..cd34be7ec700b 100644
--- a/translation/dest/site/af-ZA.xml
+++ b/translation/dest/site/af-ZA.xml
@@ -462,9 +462,6 @@ rekenaar analise, kletskamer en deelbare URL te kry.
Kies \'n baie veilige naam vir die toernooi.Enige iets ongepaste kan maak dat jou rekening gesluit word.Laat leeg om die toernooi na \'n noemenswaardige speler te vernoem.
- Ons stel voor om hierdie uit te los.
- As jy die aansluitings vereistes verstel, sal jou toernooi minder spelers hê.
- Wys gevorderde instellingsMaak die toernooi privaat, en beperk toegang met \'n wagwoordSluit aanOntrek
@@ -504,8 +501,6 @@ rekenaar analise, kletskamer en deelbare URL te kry.
As geen, los oopProfielVerander profiel
- Noem naam
- VanBiografieLand of streekDankie!
@@ -548,9 +543,7 @@ rekenaar analise, kletskamer en deelbare URL te kry.
RedeWat makeer?Kul
- BeledigBoelie
- Gradering manipulasieAnderPlak skakel na die spel(le) en verduidelik wat skort met die lid se gedrag. Moenie net sê hulle kroek nie, maar verduidelik hoe daardie gevolgtrekking bereik is. Jou verslag sal vinniger geantwoord word as dit in Engels geskryf is.Verskaf asseblief ten minste een skakel na \'n spel waar hulle gekroek het.
@@ -585,6 +578,7 @@ rekenaar analise, kletskamer en deelbare URL te kry.
StadigIn die bordBuite die bord
+ Al die blokkies van die bordOp stadig spelleAltydNooit
diff --git a/translation/dest/site/an-ES.xml b/translation/dest/site/an-ES.xml
index 8ae5a036de183..485754a139d24 100644
--- a/translation/dest/site/an-ES.xml
+++ b/translation/dest/site/an-ES.xml
@@ -461,9 +461,6 @@
Tría un nombre muito seguro pa lo torneyo.Cualsequier comportamiento minimament inadecuau podría comportar que se zarre la tuya cuenta.Si lo deixas en blanco, lo torneyo recebirá lo nombre d\'un Gran Mayestro a l\'azar.
- Se recomienda deixar como ye.
- Si imposas condicions de dentrada, lo torneyo tendrá menos chugadors.
- Amostrar configuración abanzadaFer lo torneyo privau y restrinchir l\'acceso con una clauUnir-seAbandonar
@@ -503,8 +500,6 @@
Si no aplica, deixa-lo en blancoPerfilEditar perfil
- Nombre
- ApellidoDefine lo tuyo estiloEstiloI hai un achuste pa amagar toz es estilos d\'usuario en tot lo puesto web.
@@ -550,9 +545,7 @@
MotivoQué ocurre?Trapa
- InsultoAcoso
- Manipulación d\'a puntuaciónAtroApega lo vinclo a la(s) partida(s) y explica-nos qué i hai de malo en o comportamiento d\'este usuario. No digas simplament \"fa trapazas\"; explica-nos cómo has arribau a esta conclusión. Lo tuyo reporte será procesau mas rapido si ye escrito en anglés.Per favor, da-nos a lo menos un vinclo a una partida en que s\'han feito trapazas.
diff --git a/translation/dest/site/ar-SA.xml b/translation/dest/site/ar-SA.xml
index d179135d643be..0a37d5238723e 100644
--- a/translation/dest/site/ar-SA.xml
+++ b/translation/dest/site/ar-SA.xml
@@ -74,8 +74,8 @@
رفع سلسلة الحركاترفع الى التسلسل الرئيسياحذف من هنا
- أعلى
- وسع التفريع
+ أعلى
+ وسع التفريعفرض التسلسلانسخ التفريع بصيغة PGNالتقلة
@@ -599,9 +599,6 @@
اختر اسماً ملائماً لهذه البطولة.أي شيء غير مناسب ولو حتى قليلاً يمكن أن يعرّض حسابك للإغلاق.أترك الحقل فارغاً وسيتم تسمية البطولة باسم غراند ماستر عشوائي.
- نوصي بعدم تغيير هذه الخيارات.
- إذا حددت شروطَ دخولٍ للبطولة فقد يكون لديك لاعبون أقل.
- إظهار الإعدادات المتقدمةجعل البطولة خاصة، وتقييد الوصول بكلمة مرورإشتركانسحاب
@@ -641,8 +638,6 @@
إذا لم يوجد، أتركه فارغًاالملف الشخصيحرر الملف الشخصي
- الاسم الأول
- اسم العائلةاختيار الشارةالشارةيستخدم هذا الإعداد لإخفاء جميع شارات المستخدمين في الموقع.
@@ -693,9 +688,7 @@
السببما الأمر؟غش
- إهانةإزعاج
- تلاعب بالتقييمأخرىالصق رابط المباراة (المباريات) واشرح بالتفصيل المشكلة في تصرف هذا المستحدم. لا تقل فقط \"انهم يغشون\"، ولكن اشرح لنا سبب استنتاجك. سيكون الرد أسرع إن كتبت بالإنكليزية.برجاء تقديم رابط واحد علي الأقل لمباراة حدث فيها غش.
diff --git a/translation/dest/site/av-DA.xml b/translation/dest/site/av-DA.xml
index e35a04cf186fe..905602d7db3a3 100644
--- a/translation/dest/site/av-DA.xml
+++ b/translation/dest/site/av-DA.xml
@@ -459,9 +459,6 @@
Бище турниралъе расги хӀинкъи гьечӀеб цӀар.Бокьараб, дагьаб рекъечӀеб гӀамалалъцин дур аккаунт къаялде бачине бегьула.РакӀалда гьечӀого цо гроссмейстерасул цӀар турниралда лъезе, чӀобого те.
- Нижеца гӀакълу кьола гьел хъвагеян.
- Дуца турниралде лъугьине шартӀал чӀезаруни, турниралда рукӀаралдаса дагьал чагӀи рукӀине руго.
- ЦеретӀурал рекъезариял рихьизеТурнирги къараб гьабе паролалъ гӀорхъиги чӀвайЖувазеНахъе ине
@@ -500,8 +497,6 @@
ГьечӀеб батани, чӀобого теДур гьумерДур гьумер хисизе
- ЦӀар
- Хъизамалъул цӀарГӀумрухъвайБаркала!Социалиял медиабазул бухьенал
@@ -543,9 +538,7 @@
ГӀиллаЩиб ккараб?ХӀилла
- ХӀакъир гьавиИришгъат гьави
- Рейтингалъулъ рекӀкӀ гьабиЦогидабХӀаял(з)де бухьен лъе цинги гьев хӀалесул хьвада-чӀвадиялда щиб мекъи бугебали бице. ЦохӀо \"гьес рекӀкӀ гьабунилан\" абуге, дуда кин гьедин ккараб бице. Дур гӀарзаялъухъ жеги хехго балагьила гьеб ингилис мацӀалъ хъван батани.РекӀкӀ гьабураб цо хӀаялдениги бухьен кье.
diff --git a/translation/dest/site/az-AZ.xml b/translation/dest/site/az-AZ.xml
index aa8b00f750138..407e3b592022f 100644
--- a/translation/dest/site/az-AZ.xml
+++ b/translation/dest/site/az-AZ.xml
@@ -461,9 +461,6 @@
Turnir üçün çox etibarlı bir ad seçin.Hər hansı uyğunsuz bir ad, hesabınızın bağlanmasına yol aça bilər.Turnirə görkəmli bir şahmatçının adını vermək üçün boş buraxın.
- Bunlara toxunmamağınızı məsləhət görürük.
- Giriş tələbləri qoyulsa, turnirə daha az oyunçu qoşulacaq.
- Ətraflı tənzimləmələrTurniri özəl et və şifrə qoyaraq müraciəti məhdudlaşdırQoşulTərk et
@@ -502,8 +499,6 @@
Əgər yoxdursa, boş qoyunProfilProfili redaktə et
- Ad
- SoyadÖzü haqqındaTəşəkkürlər!Sosial media linkləri
@@ -544,9 +539,7 @@
SəbəbProblem nədir?Hiylə
- TəhqirTrol
- Reytinq manipulyasiyasıDigərOyunun və ya oyunların linkini yapışdırın və bu istifadəçinin davranışında nəyin səhv olduğunu izah edin. Yalnız \"hiylə edirlər\" deməyin, necə bu nəticəyə gəldiyinizi bizə deyin. İngilis dilində yazıldığı təqdirdə hesabat daha sürətli işlənəcəkdir.Lütfən ən azı bir hiyləli oyun linki daxil edin.
diff --git a/translation/dest/site/be-BY.xml b/translation/dest/site/be-BY.xml
index 7263c6b562e2b..667b640344e45 100644
--- a/translation/dest/site/be-BY.xml
+++ b/translation/dest/site/be-BY.xml
@@ -513,9 +513,6 @@
Абярыце назву для турніру (бяспечную, калі ласка).Усё, што нават крыху апынецца недарэчным, можа прывесці да блакіроўкі.Пакіньце пустым, каб назваць турнір у гонар выпадковага гросмайстра.
- Лепей тут нічога не чапаць.
- Калі вы задасце ўмовы ўваходу, то не ўсе гульцы змогуць далучыцца да вашага турніру.
- Паказаць дадатковыя наладыЗрабіць турнір прыватным і абмяжаваць доступ паролемДалучыццаАдмовіцца ад удзелу
@@ -554,8 +551,6 @@
Калі няма, пакіньце пустымПрофільРэдагаваць профіль
- Імя
- ПрозвішчаБіяграфіяКраіна або рэгіёнДзякуй!
@@ -600,9 +595,7 @@
ПрычынаШто здарылася?Несумленная гульня
- АбразаТроль
- Махінацыі з рэйтынгамІншаеПакіньце ніжэй спасылку на гульню (ці гульні) і патлумачце, што вас непакоіць у паводзінах гэтага карыстальніка. Не пішыце нешта кшталту «ён чмут!» – патлумачце, як вы прыйшлі да гэтага выніку. Мы хутчэй разбярэмся ў сітуацыі, калі вы напішаце нам па-англійску.Калі ласка, дадайце спасылку хаця б на адну гульню, дзе былі парушаны правілы.
diff --git a/translation/dest/site/bg-BG.xml b/translation/dest/site/bg-BG.xml
index 0aab48b2f21ff..c5247a1059963 100644
--- a/translation/dest/site/bg-BG.xml
+++ b/translation/dest/site/bg-BG.xml
@@ -70,7 +70,10 @@
Повиши вариациятаНаправи основна линияИзтриване от тук
+ Скрий вариациите
+ Покажи вариациитеПокажи като вариация
+ Копирай PGN на вариациятаХодВариант на загубаВариант на победа
@@ -463,9 +466,6 @@
Изберете много безопасно име за турнира.Нещо дори и леко неуместно може да доведе до затваряне на вашия акаунт.Ако оставите празно името, тогава турнирът ще бъде кръстен на случайно избран гросмайстор.
- Препоръчваме да не пипате тези.
- Ако сте задали условия за влизане, вашият турнир ще има по-малко играчи.
- Показване на разширените настройкиОграничи достъпа до турнира с паролаВключи сеНапусни
@@ -504,8 +504,7 @@
При липса оставете празноПрофилРедактирай профила
- Име
- Презиме
+ Истинско имеИзберете вашето емоджиЕмоджиЖивотопис
@@ -550,9 +549,7 @@
ПричинаКакъв е случаят?Измама
- ОбидаВредител
- Манипулиране на рейтингаДругоПоставете линк към играта и обяснете какъв е проблемът с поведението на този потребител. Не казвайте единствено, че мами, но ни кажете как сте стигнали до този извод. Вашият доклад ще бъде обработен по-бързо, ако е написан на английски.Моля дай поне един линк до измамна игра.
@@ -587,6 +584,7 @@
БавноНа дъскатаИзвън дъската
+ Всички полета на дъскатаПри бавни игриВинагиНикога
@@ -696,6 +694,7 @@
Предходен клонСледващ клонПревключи между предходна/следваща вариация
+ изиграй избраният ходНов турнирШахматният турнир включва различни времеви контроли и вариантиИграй в състезания по бърз шахмат! Участвай в разписаните състезания или създай свое собствено. Bullet, Blitz, Classical, Chess960, King of the Hill, Threecheck и още възможности предоставящи безкрайна шахматна забава.
@@ -738,6 +737,7 @@
С приятелиС всекиДетски режим
+ Детският режим е включен.В името на безопасността. В детския режим цялата комуникация в сайта е изключена. Включете детския режим, за да защитите вашите деца и ученици от другите потребители.В детския режим логото на Lichess става %s, за да сте сигурни в безопасността на своите деца.Вашата сметка се управлява. Попитайте учителя си по шахмат за вдигане на детския режим.
@@ -777,6 +777,12 @@
ПрозраченТема на устройствотоURL адрес на фоновия образ:
+ Дъска
+ Размер
+ Прозрачност
+ Яркост
+ Цветови тон
+ Възстановяване на стандартните цветоветеДизайн на фигуриВграждане в уебсайта виПотребителското име е заето. Опитайте с друго име.
diff --git a/translation/dest/site/bn-BD.xml b/translation/dest/site/bn-BD.xml
index cd4f8c1b74ac5..c7275b006cbc1 100644
--- a/translation/dest/site/bn-BD.xml
+++ b/translation/dest/site/bn-BD.xml
@@ -462,9 +462,6 @@
টুর্নামেন্টের জন্য একটি নিরাপদ নাম পছন্দ করুন।এমনকি সামান্য অনুপযুক্ত কিছুও আপনার অ্যাকাউন্ট বন্ধ করতে পারে।কোন গ্র্যান্ডমাস্টারের নামে টুর্নামেন্টের নাম দিতে চাইলে খালি রাখুন।
- এটা টাচ না করার জন্য পরামর্শ দেয়া হচ্ছে।
- যদি আপনি এন্ট্রি করার শর্ত ঠিক করে দেন, তাহলে টুর্নামেন্টে তুলনামূলকভাবে কম খেলোয়ার পাওয়া যাবে।
- এডভান্সড সেটিংসে যানপাসওয়ার্ড দিয়ে টুর্নামেন্টটি গোপনীয় এবং সিমাবদ্ধ করেদিনযোগ দিনউঠিয়ে নিন
@@ -504,8 +501,6 @@
যদি কিছুই না হয়, খালি রাখুনপরিচিতিপরিচিতি সম্পাদনা
- প্রথম নাম
- শেষ নামআপনার ফ্লেয়ার সেট করুনফ্লেয়ারপুরো সাইট জুড়ে সমস্ত ব্যবহারকারীর ফ্লেয়ার লুকানোর জন্য একটি সেটিং রয়েছে.
@@ -552,9 +547,7 @@
কারণসম্পূর্ণ ঘটনার বিবরণ দেনচিটিং করছে
- অপমান করেছেব্যঙ্গ করছে
- রেটিং ইচ্ছাকৃতভাবে পরিবর্তনঅন্য কোনো কারণএখানে সেই খেলাটির link দেন এবং বলুন ওই ব্যক্তি ব্যবহারে কি অসুবিধা ছিল ?অনুগ্রহ করে একটা চিটেড গেমের লিংক দিন।
diff --git a/translation/dest/site/br-FR.xml b/translation/dest/site/br-FR.xml
index fed8ba0a12f54..4f939093bf77a 100644
--- a/translation/dest/site/br-FR.xml
+++ b/translation/dest/site/br-FR.xml
@@ -539,9 +539,6 @@
Choazit un anv dereat-tre evit an tournamant.Un draig ha ne vefe ket dereat a vefe trawalc\'h evit ma serrfemp ho kont.Laoskit goullo evit envel an tournamant diouzh anv ur c\'hoarier echedoù brudet.
- Gwelloc\'h eo deoc\'h chom hep kemm anezhe.
- Ma c\'houlennit strishadurioù evit mont-tre e vo nebeutoc\'h a c\'hoarierien o kemer perzh en ho tournamant.
- Diskouez an arventennoù kempleshoc\'hGallout a rit krouiñ un tournamant prevez oc\'h ouzhpennañ ur ger-tremenKemer perzhDilezel
@@ -580,8 +577,6 @@
Ma n\'eus ket, laoskit goulloProfilAozañ ar profil
- Anv
- Anv familhDiwar ho pennTrugarez!Liammoù ar mediaoù sokial
@@ -624,9 +619,7 @@
AbegPeseurt kudenn zo?Trucherezh
- KunujennTroll
- Itrikañ renkadurAllPegit liamm ar c\'hrogad(où) ha displegit ar pezh a ya a-dreuz gant emzalc\'h oc\'h enebour. Lâret \"o truchañ emañ\" ne vo ket trawalc\'h, ret eo displegañ mat. Buanoc\'h e pledimp ganti ma skrivit e saozneg.Roit d\'an nebeutañ ul liamm hag a gas d\'ur c\'hrogad trucherezh ennañ.
diff --git a/translation/dest/site/bs-BA.xml b/translation/dest/site/bs-BA.xml
index 84aee50ac97c7..efb475ac6e1c8 100644
--- a/translation/dest/site/bs-BA.xml
+++ b/translation/dest/site/bs-BA.xml
@@ -494,9 +494,6 @@ računarsku analizu, mogućnost dopisivanja i link za slanje drugima.
Odaberite vrlo siguran naziv za turnir.Sve što je imalo neprikladno može dovesti do trajnog zatvaranja vašeg profila.Ako ostavite prazno, turnir će se nazvati po slučajno odabranom šahovskom igraču.
- Preporučujemo da ne dirate ove opcije.
- Ako postavite uslov za učestvovanje, vaš turnir će imati manje igrača.
- Pogledajte napredne postavkeUčinite turnir privatnim i ograničite pristup lozinkomPridružite seOdustanite
@@ -535,8 +532,6 @@ računarsku analizu, mogućnost dopisivanja i link za slanje drugima.
Ako nemate rejting, ostavite polje praznoProfilUredite profil
- Ime
- PrezimeBiografijaHvala!Linkovi na društvene mreže
@@ -579,9 +574,7 @@ računarsku analizu, mogućnost dopisivanja i link za slanje drugima.
RazlogU čemu je problem?Varanje
- VrijeđanjeProvokacija
- Manipuliranje rejtingomOstaloZalijepite link na partiju ili partije u pitanju i objasnite što nije bilo u redu sa ponašanjem korisnika. Nemojte samo reći \"varao je\", nego objasnite kako ste došli do tog zaključka. Vaša prijava će biti brže obrađena ukoliko je napišete na engleskom jeziku.Molimo navedite barem jedan link na partiju u kojoj je igrač varao.
diff --git a/translation/dest/site/ca-ES.xml b/translation/dest/site/ca-ES.xml
index 3940f593b8bea..0077c45da2526 100644
--- a/translation/dest/site/ca-ES.xml
+++ b/translation/dest/site/ca-ES.xml
@@ -70,8 +70,8 @@
Promoure variantConvertir en línia principalEsborrar des d\'aquí
- Amagar variacions
- Expandir variacions
+ Amagar variacions
+ Expandir variacionsForçar variantCopia el PGN de la variacióMoviment
@@ -467,9 +467,6 @@
Trieu un nom segur per al torneig.Qualsevol comportament mínimament inadequat podria implicar el tancament del teu compte.Deixar en blanc per nombrar el torneig amb un Gran Mestre a l\'atzar.
- No recomanem canviar aquestes preferències.
- Si s\'estableixen les condicions d\'entrada, el torneig tindrà menys jugadors.
- Configuració avançadaFes el torneig privat, i restringeix l\'accés amb clau d\'entradaInscriu-t\'hiAbandona
@@ -509,8 +506,7 @@
Si no en tens, deixa-ho buitPerfilEdita el perfil
- Nom
- Cognoms
+ Nom realDefineix el teu estilIconaExisteix una configuració per amagar els estils dels jugadors a tot el lloc web.
@@ -557,9 +553,7 @@
RaóQuin és el problema?Trampós
- InsultTroll
- Manipulació de la puntuacióAltresEnganxa l\'enllaç de la partida (o partides) i explica el comportament negatiu d\'aquest usuari. No et limitis a dir que \"fa trampes\", i explica com has arribat a aquesta conclusió. El teu informe serà processat més ràpidament si l\'escrius en anglès.Si us plau, proporcioneu com a mínim un enllaç a un joc on s\'han fet trampes.
@@ -594,6 +588,7 @@
LentDins del taulerFora del tauler
+ Totes les caselles del taulerEn els jocs lentsSempreMai
diff --git a/translation/dest/site/ckb-IR.xml b/translation/dest/site/ckb-IR.xml
index 31055d425193a..3960e1dd1bcf0 100644
--- a/translation/dest/site/ckb-IR.xml
+++ b/translation/dest/site/ckb-IR.xml
@@ -465,9 +465,6 @@
ناوێکی گونجاو بۆ پاڵەوانیەتیەکە هەڵبژێرە.هەرشتێک ئەگەر کەمێکیش نەگونجاوبێت، دەبێتە هۆی داخستنی هەژمارەکەت.ئەم خانەیە بە بەتاڵی جێبێڵە، بۆئەوەی بە شێوەیەکی هەڕەمەکی بە ناوی یاریزانێکی دیاری شەترەنجەوە بنرێت.
- ئێمە پێشنیار دەکەین، گۆڕانکاری لەو بەشە نەکرێت.
- ئەگەر مەرجی چوونەژوورەوە زیادبکەیت ڕەنگە یاریزانی کەمتر بەشداربن.
- ڕێکخستنی پێشکەوتوو نیشان بدەپاڵەوانێتییەکە بکە بە تایبەت، و بە وشەی نهێنی چوونە ژوورەوە سنووردار بکەبەشداریبکەکشانەوە
@@ -507,8 +504,6 @@
ئەگەر نییە، بە بەتاڵی جێیبێڵەپڕۆفایلدەستکاریکردنی پڕۆفایل
- ناو
- ناوی باپیرتتوانای خۆت دابنێبەهرەڕێکخستنێک هەیە بۆ شاردنەوەی هەموو تواناکانی بەکارهێنەر لە سەرانسەری ماڵپەڕەکەدا.
@@ -555,9 +550,7 @@
هۆکارکێشەکە چییە?فێڵکردن
- بێڕێزیبێزارکەرەکان
- دەستکاریکردنی هەڵسەنگاندنئەوانیترلینکی یاریەکە لێرە دابنێ، پاشان بە وردی لەبارەی هەڵسوکەوتە نەشیاوەکانی ئەو بەکارهێنەرە بنووسە، هیچ سنورێک بۆ فێڵکردن نییە، ئەمە تەنها نمونەیەکە لێرە بەکاری دێنین، لەبەرئەوەی ئەمە زۆرترین داواکاری ریپۆرتە.تکایە بەلایەنی کەمەوە لینکی یاریەک دابنێ بۆ ئەو یاریانەی فێڵی تێداکراوە.
diff --git a/translation/dest/site/co-FR.xml b/translation/dest/site/co-FR.xml
index aa05a263c66a1..85e4a36e1e7db 100644
--- a/translation/dest/site/co-FR.xml
+++ b/translation/dest/site/co-FR.xml
@@ -420,9 +420,6 @@
Scegli un nomu curtesu pè a ghjustra criata.S\'è vo date un nomu sgarbatu à u vostru turneu, u vostru contu pò esse chjosu.Lascià viotu darà à a ghjustra u nomu d\' un ghjucadore famosu.
- V\' arricumandemu d\' ùn tuccà.
- S\'è vo create parechji cundizioni d\' intrata, ci seranu menu ghjucadori.
- Mustrà l\' uzzioni avanzatiCreà una ghjustra privata è limità ne l\' accessu cù una parolla d\' intesaGhjunghjeRitirà si
@@ -461,8 +458,6 @@
S\'è ùn n\' avete, lasciate viotuProfiluEdità u prufilu
- Nome datu
- CugnomeBiugraffiaÀ ringrazià vi!Leie di e rete suciale
@@ -504,9 +499,7 @@
MutivuChì hè u ?Ingannu
- ParullacciaTrollu
- Valutazione trafficataAltruIncolla a leia di a partita è spiega ciò ch\' ùn si passa bè cù u cumpurtamentu di u ghjucadore. Ùn scrivi micca soltantu \"inganna\" ma dite dinù perchè. A vostra dumanda serà trattata di modu più prontu s\' ellu hè scrittu in inglese.Pè piace date omancu una leia d\' una partita ingannata.
diff --git a/translation/dest/site/cs-CZ.xml b/translation/dest/site/cs-CZ.xml
index addb6f204e434..c75eb83398929 100644
--- a/translation/dest/site/cs-CZ.xml
+++ b/translation/dest/site/cs-CZ.xml
@@ -531,9 +531,6 @@
Vyberte \"bezpečné\" jméno turnaje.Cokoli i mírně nevhodného může způsobit uzavření vašeho účtu.Pokud jméno turnaje nevyplníte, bude pojmenován po náhodném velmistrovi.
- Doporučujeme tato nastavení neměnit.
- Pokud nastavíte podmínky vstupu, zúčastní se vašeho turnaje méně hráčů.
- Zobrazit pokročilá nastaveníUdělejte turnaj soukromý a omezte přístup heslemPřidat seOdhlásit se
@@ -573,8 +570,6 @@
Pokud nemáte, nechte pole volnéProfilUpravit profil
- Jméno
- PříjmeníNastav si svou ikonu za jménemUpravitelná ikonaO mně
@@ -621,9 +616,7 @@
DůvodCo se stalo?Podvod
- UrážkaTroll
- Manipulace s ratingemJinéVložte link na hru(y) a popište, co je špatně na chování tohoto hráče. (Pokud možno anglicky.)Prosím, uveďte alespoň jeden link na partii, ve které se podvádělo.
diff --git a/translation/dest/site/cv-CU.xml b/translation/dest/site/cv-CU.xml
index 184cd1218d639..0bec260a5cf0e 100644
--- a/translation/dest/site/cv-CU.xml
+++ b/translation/dest/site/cv-CU.xml
@@ -283,8 +283,6 @@
Модӑратӑра %s ҫинчен пӗлтерПрофӗлӳПрофӗлне тӳрлетни
- Йат
- ХушаматБиографиТавах!Lichess TV паҫӑр кӑтартни
@@ -318,7 +316,6 @@
СӑлтавСӑлтава кӑтартУлтав
- КӳрентерӳТроллевЫтти%s тунӑ
diff --git a/translation/dest/site/cy-GB.xml b/translation/dest/site/cy-GB.xml
index 92615cbdb55ce..d0af00be301c4 100644
--- a/translation/dest/site/cy-GB.xml
+++ b/translation/dest/site/cy-GB.xml
@@ -336,9 +336,6 @@
Dewisia enw saff i\'r talwrn.Gall unrhywbeth amhriodol arwain at ddileu dy gyfrif.Gadewch yn wag i enwi\'r talwrn ar ol Uwchfeistr Rhyngwladol wedi ei ddewis ar hap.
- Rydym yn awgrymu nad ydych yn cyffwrdd rhain.
- Bydd gosod telerau ymuno yn debyg o olygu llai o chwaraewyr yn y talwrn.
- Dangos gosodiadau cymlethGwneud y talwrn yn breifat a cyfyngu mynediad gyda cyfrinairYmunoYmddiswyddo
@@ -375,8 +372,6 @@
Os heb gradd, gadewch yn wagProffilGolygu proffil
- Enw cyntaf
- CyfenwCofiantDiolch yn fawr!Dolenni cyfryngau cymdeithasol
@@ -411,9 +406,7 @@
RheswmBeth sy\'n bod?Twyll
- SarhadTrôl
- Twyllo sgôrArallGluda ddolen i\'r gêm ac esbonio be sydd o\'i le am ymddigiad y defnyddiwr hwn. Paid â dweud jyst ´\"Mae o\'n twyllo\", ond dwed pam wyt ti\'n meddwl hynny. Bydd dy adrodd yn cael ei brosesu yn gyflymach os ysgrifenni yn Saesneg.Rhowch o leiaf un dolen at gem lle bu twyllo.
diff --git a/translation/dest/site/da-DK.xml b/translation/dest/site/da-DK.xml
index 3e0f9b7520432..2388452c2a978 100644
--- a/translation/dest/site/da-DK.xml
+++ b/translation/dest/site/da-DK.xml
@@ -70,8 +70,8 @@
Forfrem variantGør til hovedlinjenSlet herfra
- Fold variationer sammen
- Udvid variationer
+ Fold variationer sammen
+ Udvid variationerGennemtving variationKopiér variant-PGNTræk
@@ -467,9 +467,6 @@
Vælg et meget ufarligt navn til turneringen.Selv noget lidt upassende kan resultere i at din konto lukkes.Lad stå tomt for at navngive turneringen efter en tilfældig stormester.
- Vi anbefaler at ikke ændre disse.
- Hvis du stiller betingelser for deltagelse, vil din turnering have færre spillere.
- Vis avancerede IndstillingerGør turneringen privat og begræns adgang med en adgangskodeDeltagFrameld
@@ -509,8 +506,7 @@
Hvis ingen, lad den være tomProfilRedigér profil
- Fornavn
- Efternavn
+ Rigtige navnIndstil dit ikonIkonDer er en indstilling til at skjule alle brugerikoner på tværs af hele webstedet.
@@ -557,9 +553,7 @@
ÅrsagHvad drejer henvendelsen sig om?Snyd
- FornærmelseTroll
- Manipulation af ratingAndetIndsæt et link til partiet (eller partierne) og forklar hvad der er i vejen med brugerens opførsel.Angiv mindst ét link til et parti med snyd.
@@ -594,6 +588,7 @@
LangsomPå brættetUden for brættet
+ Alle felter på brættetI langsomme spilAltidAldrig
diff --git a/translation/dest/site/de-DE.xml b/translation/dest/site/de-DE.xml
index ae4a17e4c7e0c..3a8cb76b96724 100644
--- a/translation/dest/site/de-DE.xml
+++ b/translation/dest/site/de-DE.xml
@@ -467,9 +467,6 @@
Wähle einen äußerst sicheren Namen für das Turnier.Sämtliche unangemessene Inhalte können zur Schließung deines Benutzerkontos führen.Frei lassen, um das Turnier nach einem zufälligen Großmeister zu benennen.
- Wir empfehlen, diese nicht zu ändern.
- Falls du Teilnahmebedingungen setzt, wird das Turnier weniger Spieler haben.
- Zeige erweiterte EinstellungenStelle das Turnier auf privat und beschränke den Zugang durch ein PasswortTeilnehmenVerlassen
@@ -509,8 +506,7 @@
Nur falls vorhandenProfilProfil bearbeiten
- Vorname
- Nachname
+ Echter NameSetze dein FlairFlairEs existiert eine Einstellungsmöglichkeit, um alle Benutzerflairs auf der gesamten Seite zu verbergen.
@@ -557,9 +553,7 @@
GrundWas ist das Problem?Betrug
- BeleidigungTroll
- Manipulation der WertungszahlSonstigesFüge den Link zu einer oder mehreren Partien ein und erkläre die Auffälligkeiten bezüglich des Spielerverhaltens. Bitte schreibe nicht einfach nur „dieser Spieler betrügt“, sondern begründe auch, wie Du zu diesem Schluss kommst. Dein Bericht wird schneller bearbeitet, wenn er in englischer Sprache verfasst ist.Bitte gib mindestens einen Link zu einem Spiel an, in dem betrogen wurde.
@@ -594,6 +588,7 @@
LangsamAuf dem BrettNeben dem Brett
+ Alle Felder auf dem BrettBei langsamen SpielenImmerNie
diff --git a/translation/dest/site/el-GR.xml b/translation/dest/site/el-GR.xml
index 487f92afc8a5c..816aa797b5c16 100644
--- a/translation/dest/site/el-GR.xml
+++ b/translation/dest/site/el-GR.xml
@@ -466,9 +466,6 @@
Διαλέξτε ένα πολύ ασφαλές όνομα για το τουρνουά.Οτιδήποτε ακόμα και ελάχιστα ακατάλληλο μπορεί να κλείσει τον λογαριασμό σας.Αφήστε το κενό για να πάρει το όνομά του τυχαία από κάποιον γνωστό σκακιστή.
- Σας συνιστούμε να μην τα αλλάξετε αυτά.
- Εάν ορίσετε προϋποθέσεις εισόδου, το τουρνουά σας θα έχει λιγότερους παίκτες.
- Εμφάνιση ρυθμίσεων για προχωρημένουςΚάντε το τουρνουά ιδιωτικό, και περιορίστε την πρόσβαση με κωδικόΣυμμετοχήΑπόσυρση
@@ -508,8 +505,6 @@
Αν δεν υπάρχει, αφήστε κενόΠροφίλΕπεξεργασία προφίλ
- Όνομα
- ΕπώνυμοΟρίστε τη νιφάδα σαςΝιφάδαΥπάρχει μια ρύθμιση για να κρύψει όλες τις νιφάδες χρήστη σε ολόκληρη την ιστοσελίδα.
@@ -556,9 +551,7 @@
ΑιτίαΤι τρέχει;Απάτη
- ΠροσβολήΕμπαιγμός
- Παραποίηση βαθμολογίαςΆλλοΚάντε επικόλληση τον σύνδεσμο για το παιχνίδι(α) και εξηγήστε τι είναι παράξενο στη συμπεριφορά του χρήστη. Μην πείτε απλά «επειδή κλέβει», πείτε μας πως καταλήξατε σε αυτό το συμπέρασμα. Η αναφορά σας θα επεξεργαστεί πιο γρήγορα αν είναι γραμμένη στα αγγλικά.Καταχωρίστε τουλάχιστον έναν σύνδεσμο σε ένα παιχνίδι εξαπάτησης.
@@ -593,6 +586,7 @@
ΑργήΜέσα στη σκακιέραΕκτός της σκακιέρας
+ Σε όλα τα τετράγωνα της σκακιέραςΣε αργά παιχνίδιαΠάνταΠοτέ
diff --git a/translation/dest/site/en-US.xml b/translation/dest/site/en-US.xml
index 332903fbaaaaa..c90a96949a5c7 100644
--- a/translation/dest/site/en-US.xml
+++ b/translation/dest/site/en-US.xml
@@ -468,9 +468,6 @@ computer analysis, game chat and shareable URL.
Pick a very safe name for the tournament.Anything even slightly inappropriate could get your account closed.Leave empty to name the tournament after a notable chess player.
- We recommend not touching these.
- If you set entry requirements, your tournament will have fewer players.
- Show advanced settingsMake the tournament private, and restrict access with a passwordJoinWithdraw
@@ -510,8 +507,7 @@ computer analysis, game chat and shareable URL.
If none, leave emptyProfileEdit profile
- First name
- Last name
+ Real nameSet your flairFlairThere is a setting to hide all user flairs across the entire site.
@@ -558,9 +554,7 @@ computer analysis, game chat and shareable URL.
ReasonWhat\'s the matter?Cheat
- InsultTroll
- Rating manipulationOtherPaste the link to the game(s) and explain what is wrong about this user behavior. Don\'t just say \"they cheat\", but tell us how you came to this conclusion. Your report will be processed faster if written in English.Please provide at least one link to a cheated game.
@@ -595,6 +589,7 @@ computer analysis, game chat and shareable URL.
SlowInside the boardOutside the board
+ All squares on the boardOn slow gamesAlwaysNever
diff --git a/translation/dest/site/eo-UY.xml b/translation/dest/site/eo-UY.xml
index 8719df99223f5..b471a8e2e1e60 100644
--- a/translation/dest/site/eo-UY.xml
+++ b/translation/dest/site/eo-UY.xml
@@ -464,9 +464,6 @@
Elekti tre sekuran nomon por la turniro.Se vi uzas maltaŭgan aŭ maldecan nomon, ni fermos vian konton.Se vi lasas ĝin malplena, ni uzos la nomon de fama ŝakludisto.
- Ni rekomendi ke vi ne tuŝas ĉi tiujn.
- Se vi aldonas aliĝpostulojn, via turniro havos malpli da ludantoj.
- Montri spertulajn agordojnFaru la turniron privata kaj restriktu la aliron per pasvortoAliĝiEliri
@@ -506,8 +503,6 @@
Se neniu, lasu malplenaProfiloRedakti profilon
- Persona nomo
- Familia nomoAgordi viaj emoĝioEmoĝioEstas agordo por kaŝi ĉiujn uzantajn emoĝiojn tra la tuta retejo.
@@ -553,9 +548,7 @@
KialoPri kio temas la raporto?Trompo
- InsultoTrolo
- Manipulado de rangoIo aliaInkluzivu la ligilon al la ludo(j) kaj ekspliku tion, kio malbonas pri la konduto de ĉi tiu uzanto.Bonvolu doni almenaŭ unu ligilon al ludo en kiu oni friponis.
diff --git a/translation/dest/site/es-ES.xml b/translation/dest/site/es-ES.xml
index c1e3946adc929..ebadd95e42b34 100644
--- a/translation/dest/site/es-ES.xml
+++ b/translation/dest/site/es-ES.xml
@@ -467,9 +467,6 @@
Escoge un nombre muy seguro para el torneo.Cualquier comportamiento mínimamente inapropiado podría conllevar al cierre de tu cuenta.Déjalo en blanco para poner al torneo el nombre de un Gran Maestro al azar.
- Se recomienda dejar como está.
- Si impones condiciones de entrada, el torneo tendrá menos jugadores.
- Mostrar configuración avanzadaHacer el torneo privado y restringir el acceso con una contraseñaUnirseAbandonar
@@ -509,8 +506,7 @@
Si no aplica, déjalo en blancoPerfilEditar perfil
- Nombre
- Apellido
+ Nombre realConfigura tu entornoEntornoExiste una opción para ocultar la configuración de entorno en todo el sitio.
@@ -557,9 +553,7 @@
Motivo¿Qué ocurre?Trampa
- InsultoAcoso
- Manipulación de puntuaciónOtroPega el enlace a la(s) partida(s) y explícanos qué hay de malo en el comportamiento de este usuario. No digas simplemente \"hace trampa\"; explícanos cómo has llegado a esta conclusión. Tu informe será procesado más rápido si está escrito en inglés.Por favor, proporciona al menos un enlace a una partida en la que se hicieron trampas.
@@ -594,6 +588,7 @@
LentoDentro del tableroFuera del tablero
+ Todas las casillas del tableroEn partidas lentasSiempreNunca
diff --git a/translation/dest/site/et-EE.xml b/translation/dest/site/et-EE.xml
index 2a4e5a45e07a9..47fd407698a1c 100644
--- a/translation/dest/site/et-EE.xml
+++ b/translation/dest/site/et-EE.xml
@@ -446,9 +446,6 @@ arvutianalüüsi, mängu jututoa ning jagatava URL-i.
Vali turniirile sobiv nimi.Isegi pisut kohatu nimi võib tähendada sinu konto sulgemist.Jäta tühjaks, et nimetada turniir juhusliku suurmeistri järgi.
- Me ei soovita neid muuta.
- Kui sa lisad osalemiseks tingimusi, siis osaleb turniiril vähem inimesi.
- Näita täpsemaid sätteidTee turniir privaatseks ja piira juurdepääsu parooligaLiituLoobu
@@ -487,8 +484,6 @@ arvutianalüüsi, mängu jututoa ning jagatava URL-i.
Kui pole, jäta tühjaksProfiilMuuda profiili
- Eesnimi
- PerekonnanimiKirjeldusAitäh!Sotsiaalmeedia lingid
@@ -530,9 +525,7 @@ arvutianalüüsi, mängu jututoa ning jagatava URL-i.
PõhjusMilles asi?Sohk
- SolvangTroll
- Reitingu manipulatsioonMuuKleebi link mängu(de)st ja selgita, mis on valesti selle kasutaja käitumises. Ära ütle lihtsalt \"ta teeb sohki\", vaid seleta, kuidas sa selle järelduseni jõudsid. Sõnum käsitletakse kiiremini kui see on kirjutatud inglise keeles.Palun andke vähemalt üks link pettust sisaldavale mängule.
diff --git a/translation/dest/site/eu-ES.xml b/translation/dest/site/eu-ES.xml
index e2f08bc85484e..90e0fbcc10424 100644
--- a/translation/dest/site/eu-ES.xml
+++ b/translation/dest/site/eu-ES.xml
@@ -464,9 +464,6 @@
Adeitasunezko izena hauta ezazu.Errespetua galduz gero, zure kontua itxiko dugu.Ez baduzu betetzen, txapelketak Maisu Handi baten izena hartuko du, ausaz.
- Hobe ez ukitu hau.
- Parte hartzeko baldintzak jartzen badituzu, jokalari gutxiago sartuko dira txapelketan.
- Ezarpen aurreratuakTxapelketa pribatu egin eta sarrera pasahitzarekin babestuSartuTxapelketa utzi
@@ -506,8 +503,6 @@
Ez baduzu, hutsik utziProfilaNire profila editatu
- Izena
- AbizenaEzarri zure iruditxoaIruditxoaWebgune guztian zehar erabiltzaile guztien iruditxoak ezkutatzeko ezarpen bat dago.
@@ -553,9 +548,7 @@
ArrazoiaZein da arazoa?Tranpak
- IrainakTrolla
- Puntuazioa manipulatuBestelakoakPartidaren esteka itsasi, eta azaldu zer egin duen gaizki erabiltzaileak. Ez esan \"tranpak egiten ditu\" bakarrik, eman horren arrazoiak. Zure mezua azkarrago begiratuko dugu ingelesez idazten baduzu.Iruzurra izandako partida baten lotura bidali gutxienez.
diff --git a/translation/dest/site/fa-IR.xml b/translation/dest/site/fa-IR.xml
index f4d20c9beedd6..a48bf958de11e 100644
--- a/translation/dest/site/fa-IR.xml
+++ b/translation/dest/site/fa-IR.xml
@@ -44,7 +44,7 @@
ممکن است حریف شما بازی را ترک کرده باشد. شما می توانید ادعای پیروزی کنید, اعلام تساوی کنید یا منتظر او بمانید.ادعای پیروزیاعلام تساوی
- لطفا در گپ زدن مودب باشید!
+ لطفا در گپزنی بااَدب باشید!نخستین کسی که به این وبنشانی آید با شما بازی خواهد کرد.سفید تسلیم شدسیاه تسلیم شد
@@ -112,7 +112,7 @@
همه چیز آماده است!PGN را وارد کنیدحذف
- آیا این بازیِ وارد شده حذف گردد؟
+ آیا این بازیِ درونبُرده پاک شود؟حالت پخشمشابه بازیدرنگ حین اشتباهات
@@ -142,7 +142,7 @@
%s غیردقیق%s غیردقیق
- مدت زمان حركت
+ مدت حركتهاچرخاندن صفحهتکرار سه گانهادعای تساوی
@@ -325,7 +325,7 @@
%s بازی در حال انجام%s بازی در حال انجام
- استخراج بازی ها
+ برونبُرد بازیهامحدوده درجهبندی%s ثانیه اضافه کن
@@ -398,7 +398,7 @@
ذخیرهجدول ردهبندیاز وضعیت فعلی نماگرفت بگیرید
- دانلود گیف بازی
+ بارگیری GIF بازیپوزیشن دلخواه(FEN) را در این قسمت وارد کنیدمتن PGN را در این قسمت وارد کنیدیا یک فایل PGN بارگذاری کنید
@@ -467,9 +467,6 @@
یک نام بسیار امن برای مسابقات انتخاب کنید.هرچیز حتی کمی نامناسب ممکن است باعث بسته شدن حساب کاربری شما بشود.این مکان را خالی بگذارید تا به صورت تصادفی اسم یک استاد بزرگ برای مسابقات انتخاب شود.
- توصیه میکنیم که تنظیمات پیشرفته را تغییر ندهید.
- اگر برای مسابقات شرایط ورود تعیین کنید بازیکنان کمتری وارد می شوند.
- نمایش تنظیمات پیشرفتهتورنومنت را به حالت خصوصی در بیاورید و دسترسی را محدود به داشتن پسورد کنیدملحق شدنمنصرف شدن
@@ -504,13 +501,12 @@
بارگذاری موقعیتخصوصیگزارش %s به مدیران سایت
- میزان تکمیل نمایه: %s
+ میزان تکمیل رُخنما: %sدرجهبندی %sاگر ندارید، خالی گذارید
- نمایه
- ویرایش نمایه
- نام
- نام خانوادگی
+ رُخنما
+ ویرایش رُخنما
+ نام راستینتعیین کردن شکلکنشانتنظیماتی برای مخفی کردن همه شکلکهای کاربر در کل ویگاه وجود دارد.
@@ -557,9 +553,7 @@
دلیلموضوعتقلب
- توهین کردنترول
- دستکاری درجهبندیموضوعات دیگرلینک بازی های این کاربر را قرار دهید و توضیع دهید خطای رفتار این بازیکن چه بوده استلطفآ حداقل یک نمونه تقلب در بازی را مطرح کنید.
@@ -594,6 +588,7 @@
آرامدر صفحهبیرون صفحه
+ همه خانههای صفحهدر بازی های آرامهمیشههرگز
@@ -655,7 +650,7 @@
نگاه کردنفیلم هابَرخَط-محتواسازها
- برنامه ی موبایل
+ گوشیافزاروبداراندرباره مادرباره %s
@@ -740,8 +735,8 @@
تاخیر شبکه بین شما و Lichessزمان سپری شده برای پردازش یک حرکتبارگیری حرکتنویسی
- دانلود خام
- دانلود جایگذاری شده
+ بارگیری خام
+ بارگیری درونبُردرودرروشما می توانید برای حرکت در بازی از صفحه استفاده کنیدبرای مشاهده آن ها اسکرول کنید.
@@ -763,7 +758,7 @@
جلساتباطل کردن تمامی مواردهمه جا شطرنج بازی کنید
- رایگان به مانند لیچس
+ کاملا رایگانساخته شده با عشق به شطرنج نه پولهمگی از مزایا بصورت رایگان استفاده می کنندبدون تبلیغات
@@ -771,12 +766,12 @@
موبایل و تبلتگلولهای، برقآسا، مرسومشطرنج مکاتبه ای
- بازی کردن بَرخط و بُرونخط
+ بازی بَرخط و بُرونخطدیدن راهِ حلدنبال کردن و پیشنهاد بازی دادن به دوستان
- در %s زبانها موجود است
- در %s زبانها موجود است
+ در %s زبان موجود است!
+ در %s زبان موجود است!تجزیه و تحلیلِ بازی%1$s میزبان ها %2$s
@@ -800,7 +795,7 @@
فامبازنشاندن به رنگهای پیشفرضنوع مهره
- قرار دادن در سایت خود
+ قرار دادن در وبگاه خوداین نام کاربری در حال حاضر انتخاب شده است.لطفا نام دیگری انتخاب کنید.نام کاربری باید با حرف شروع شود.نام کاربری باید با حرف یا شماره خاتمه یابد.
diff --git a/translation/dest/site/fi-FI.xml b/translation/dest/site/fi-FI.xml
index 62eaa8ba665cc..8db32305753fc 100644
--- a/translation/dest/site/fi-FI.xml
+++ b/translation/dest/site/fi-FI.xml
@@ -70,8 +70,8 @@
Nosta muunnelmaaPäämuunnelmaksiPoista tästä alkaen
- Taita kokoon muunnelmat
- Laajenna muunnelmat
+ Taita kokoon muunnelmat
+ Laajenna muunnelmatPakota muunnelmaksiKopioi muunnelman PGNSiirto
@@ -467,9 +467,6 @@
Valitse asiallinen nimi turnaukselle.Hiemankin epäasiallinen nimi voi johtaa käyttäjätunnuksesi sulkemiseen.Jos jätät tyhjäksi, turnaus nimetään jonkun suurmestarin mukaan.
- Emme suosittele näihin koskemista.
- Jos asetat liittymisehtoja, turnauksessasi tulee olemaan vähemmän pelaajia.
- Näytä lisäasetuksetTee turnauksesta yksityinen ja aseta salasana, jolla siihen pääseeLiityPeru osallistuminen
@@ -509,8 +506,7 @@
Jätä tyhjäksi jos ei oleProfiiliMuokkaa profiilia
- Etunimi
- Sukunimi
+ Oikea nimiValitse tyylisiTyyliOn olemassa asetus, jolla voit piilottaa kaikkien käyttäjien tyylit koko sivustolla.
@@ -557,9 +553,7 @@
SyyMikä hätänä?Huijaus
- LoukkausTrolli
- Vahvuusluvun manipulointiMuuLiitä linkki peliin/peleihin ja kerro, mikä on pielessä tämän käyttäjän käytöksessä. Älä vain sano että \"hän huijaa\", vaan kerro meille miksi ajattelet näin. Raporttisi käydään läpi nopeammin, jos se on kirjoitettu englanniksi.Anna ainakin yksi linkki peliin, jossa epäilet huijaamista.
@@ -594,6 +588,7 @@
HidasLaudan sisäpuolellaLaudan ulkopuolella
+ Kaikki laudan ruudutHitaissa peleissäAinaEi koskaan
diff --git a/translation/dest/site/fo-FO.xml b/translation/dest/site/fo-FO.xml
index 48fe10bde8aab..f0b0d01874888 100644
--- a/translation/dest/site/fo-FO.xml
+++ b/translation/dest/site/fo-FO.xml
@@ -410,9 +410,6 @@
Vel eitt trygt og hóskiligt navn til kappingina.Er navnið á nakran hátt ósømiligt, kann konta tín verða stongd.Lat teigin vera tóman, um tú vilt, at kappingin verður nevnd eftir gitnum telvara.
- Vit viðmæla ikki at nerta hesar.
- Um tú setir luttøkutreytir, verða færri telvarar í kappingini.
- Vís framkomnar stillingarGer so kappingin ikki er almen, og avmarka atgongdina við einum loyniorðiTak lutFar úr
@@ -449,8 +446,6 @@
Um einki, lat teigin vera tómanVangamyndBroyt vangamynd
- Fornavn
- EftirnavnÆvilýsingTakk fyri!Leinki til sosialar miðlar
@@ -490,9 +485,7 @@
OrsøkHvat bagir?Snýt
- HáðarTrøll
- Svik við styrkitaliAnnaðFlyt leinkið til talvið ella talvini higar, og greið frá, hvat bagir atburðinum hjá brúkaranum. Skriva ikki bert \"hann snýtir\", men sig okkum, hvussu tú komst til hesa niðurstøðu. Fráboðan tín verður skjótari viðgjørd, um hon verður skrivað á enskum.Útvega leinki til í minsta lagi eitt talv, har snýtt varð.
diff --git a/translation/dest/site/fr-FR.xml b/translation/dest/site/fr-FR.xml
index a53b18564860f..72e51aa92c751 100644
--- a/translation/dest/site/fr-FR.xml
+++ b/translation/dest/site/fr-FR.xml
@@ -70,8 +70,8 @@
Promouvoir la varianteEn faire la variante principaleSupprimer à partir d\'ici
- Fermer les variantes
- Afficher les variantes
+ Fermer les variantes
+ Afficher les variantesForcer la varianteCopier le PGN de la varianteCoup
@@ -467,9 +467,6 @@
Choisissez un sage nom pour le tournoi.Toute conduite inappropriée aboutira à la fermeture de votre compte.Laissez vide pour que le tournoi soit nommé d\'après le nom d\'un grand maître.
- Nous recommandons de ne pas modifier cela.
- Si vous définissez des conditions d\'admission, votre tournoi aura moins de joueurs.
- Afficher les paramètres avancésRendre le tournoi privé et en restreindre l\'accès avec un mot de passeRejoindreRenoncer
@@ -509,8 +506,7 @@
Sinon, laissez videProfilModifier le profil
- Prénom
- Nom
+ Nom réelChoisir votre émojiÉmojiUn paramètre permet de cacher les émojis des utilisateurs sur tout le site.
@@ -557,9 +553,7 @@
MotifQuel est le problème ?Triche
- InsulteTroll
- Manipulation du classementAutreCopiez le(s) lien(s) vers les parties et expliquez en quoi le comportement de cet utilisateur est inapproprié. Ne dites pas juste \"il triche\", mais expliquez comment vous êtes arrivé à cette conclusion. Votre rapport sera traité plus vite s\'il est écrit en anglais.Merci de fournir au moins un lien vers une partie où il y a eu triche.
@@ -594,6 +588,7 @@
LenteSur l\'échiquierEn dehors de l\'échiquier
+ Toutes les casesDurant les parties lentesToujoursJamais
diff --git a/translation/dest/site/fy-NL.xml b/translation/dest/site/fy-NL.xml
index a8ec219a1c671..c57226aa4d797 100644
--- a/translation/dest/site/fy-NL.xml
+++ b/translation/dest/site/fy-NL.xml
@@ -356,9 +356,6 @@ kompjûteranalyze, partijpetear en dielbere URL te krijen.
Kies in feilige, net kontroversjele namme foar it toernoai.Sels by it fermoeden fan in mispleatste namme, kin jo account sluten wurde.Lit leech om it toernoai nei in opmerklike skaakspiler te ferneamen.
- Wy riede oan dizze ynstellingen sa te litten.
- As jo tagongseasken ynstelle, sil jo toernoai minder spilers hawwe.
- Toan avansearre ynstellingenMeitsje it toernoai privee, en behein de tagong mei in wachtwurdMeidwaanWeromlûke
@@ -393,8 +390,6 @@ kompjûteranalyze, partijpetear en dielbere URL te krijen.
As der gjin is, lit dan leechProfylProfyl bewurkje
- Foarnamme
- EfternammeBiografyTankewol!Keppelingen nei sosjale media
@@ -427,7 +422,6 @@ kompjûteranalyze, partijpetear en dielbere URL te krijen.
RedenWat is der oan de hân?Falsk spul
- BeledigingProvokaasjeOarsPlak de link nei it spul(len) en lis út wat ferkeard is oan it gedrach fan dizze brûker. Sis net \"dit is falsk spul\", mar lis ús út hoe ast ta dizze konklúzje bist kaam. Dyn rapport sil rapper wurde ferwurke as it yn it Ingelsk wurdt skreaun.
diff --git a/translation/dest/site/ga-IE.xml b/translation/dest/site/ga-IE.xml
index f4d98f4466878..b76a6c9361ab2 100644
--- a/translation/dest/site/ga-IE.xml
+++ b/translation/dest/site/ga-IE.xml
@@ -543,9 +543,6 @@ anailís ríomhaire, comhrá cluiche agus URL inroinnte.
Pioc ainm an-sábháilte don chomórtas.D\'fhéadfadh do chuntas a dhúnadh má roghnaítear aon rud míchuí.Fág folamh chun an comórtas a ainmniú i ndiaidh imreoir fichille suntasach.
- Molaimid iad seo a fhágáil mar atá.
- Má shocraíonn tú riachtanais iontrála don chomórtas, beidh níos lú imreoirí i do chomórtas.
- Taispeáin ardsocruitheDéan an comórtas príobháideach, agus cuir srian ar rochtain le pasfhocalCláraighTarraing siar
@@ -584,8 +581,6 @@ anailís ríomhaire, comhrá cluiche agus URL inroinnte.
Mura bhfuil, fág folamhPróifílCuir próifíl in eagar
- Ainm
- SloinneBeathaisnéisGo raibh maith agat!Naisc chuig na meáin shóisialta
@@ -630,9 +625,7 @@ anailís ríomhaire, comhrá cluiche agus URL inroinnte.
FáthCad atá cearr?Caimiléir
- MaslaTroll
- Ionramháil rátálaEileGreamaigh an nasc chuig an gcluiche/na cluichí agus mínigh cad atá cearr le hiompar an úsáideora. Ná habair go díreach go mbíonn \"caimiléireacht\" ar bun acu, ach inis dúinn faoin dóigh a fuair tú amach faoi. Faraor, déanfar do thuairisc a phróiseáil níos tapúla más i mBéarla atá sé.Cuir nasc ar fáil chuig cluiche amháin ar a laghad ar tharla caimiléireacht ann le do thoil.
diff --git a/translation/dest/site/gd-GB.xml b/translation/dest/site/gd-GB.xml
index 248d92cd37860..ecc8650febbc5 100644
--- a/translation/dest/site/gd-GB.xml
+++ b/translation/dest/site/gd-GB.xml
@@ -191,8 +191,6 @@
Cuir gearan mu %s dha na maoirPròifilDeasaich a’ phròifil
- Ainm
- SloinneadhEachdraidh-beathaMòran taing!Air tbh Lichess roimhe
@@ -222,7 +220,6 @@
AdhbharDè an trioblaid?Cealgaireachd
- MosachTrollAdhbhar eilele %s
diff --git a/translation/dest/site/gl-ES.xml b/translation/dest/site/gl-ES.xml
index 2a36432053d19..5cff8daf187a0 100644
--- a/translation/dest/site/gl-ES.xml
+++ b/translation/dest/site/gl-ES.xml
@@ -467,9 +467,6 @@
Escolle un nome seguro para o torneo.Calquera comportamento minimamente inadecuado podería levar ao peche da túa conta.Deixar en branco para poñerlle ó torneo o nome dun Grande Mestre notable.
- Non recomendamos cambiar estes axustes.
- Se estableces condicións de entrada, o teu torneo terá menos xogadores.
- Amosar axustes avanzadosFai que o torneo sexa privado e restrinxe o acceso cun contrasinalUnirseRetirarse
@@ -509,8 +506,7 @@
Se non aplica, déixao en brancoPerfilEditar perfil
- Nome
- Apelido(s)
+ Nome realEscolle a túa habelenciaHabelenciaNas preferencias podes agochar por completo as habelencias dos xogadores en todo o sitio.
@@ -557,9 +553,7 @@
MotivoQue pasou?Trampa
- InsultoTroll
- Manipulación da puntuaciónOutroPega a ligazón á(s) partida(s) e explica o que é incorrecto no comportamento deste usuario. Non digas só \"fai trampas\", cóntanos como chegaches a esa conclusión. A túa denuncia será procesada máis rapidamente se está escrita en inglés.Por favor, incorpora cando menos unha ligazón a unha partida na que se fixeron trampas.
@@ -594,6 +588,7 @@
LentaDentro do taboleiroFóra do taboleiro
+ Todas as casas do taboleiroEn partidas lentasSempreNunca
diff --git a/translation/dest/site/gsw-CH.xml b/translation/dest/site/gsw-CH.xml
index 7c442c77447cf..e1f70373ffad5 100644
--- a/translation/dest/site/gsw-CH.xml
+++ b/translation/dest/site/gsw-CH.xml
@@ -469,9 +469,6 @@ zum bewise dass du en Mänsch bisch.
Wähl en möglichscht sichere Name fürs Turnier.Alles - au liecht Unagmässes - cha zur Schlüssig vu dim Konto fühere.Frei la zum s\'Turnier nach eme namhafte Schachschpiller z\'benänne.
- Mir empfehled, das nöd z\'ändere.
- Wänn du Teilnahmebedingige verlangsch, wird dis Turnier weniger Schpiller ha.
- Zeig die erwiterete IschtelligeMach das Turnier privat und beschränk de Zuegang mit PasswortMach mitUsstige
@@ -511,8 +508,7 @@ zum bewise dass du en Mänsch bisch.
Nur wänn vorhandeProfilProfil bearbeite
- Vorname
- Nachname
+ Richtige NameWähl dis EmojiEmojiAlli Benutzer-Emojis chönnd - uf de ganze Site - usbländet werde.
@@ -559,9 +555,7 @@ zum bewise dass du en Mänsch bisch.
GrundWas isch s\'Problem?Bschiss
- BeleidigungTroll
- Manipulation vu de WertigSuschtigsFüeg de Link dere/dene Partie bi und erchlär, wie sich de Benutzer falsch benah hät. Säg nöd nur \"de bschisst\", schrib eus wie du da druf chunnsch. (änglisch gschribeni Mäldige, werded schnäller behandlet).Bitte gib mindeschtens 1 Link zume Schpiel a, wo bschisse worde isch.
@@ -596,6 +590,7 @@ zum bewise dass du en Mänsch bisch.
LangsamUf em BrättUsse vum Brätt
+ Uf jedem FäldBi langsame PartieImmerNie
diff --git a/translation/dest/site/gu-IN.xml b/translation/dest/site/gu-IN.xml
index 0034d61fe2b74..e0152a6c23e01 100644
--- a/translation/dest/site/gu-IN.xml
+++ b/translation/dest/site/gu-IN.xml
@@ -409,8 +409,6 @@
કાળા ની જીતડ્રોપ્રોફાઇલ સંપાદિત કરો
- પ્રથમ નામ
- અટકતમારો સ્વભાવ સેટ કરોસ્વભાવ અન્યથા દેખાવઆખી સાઈટ પર તમામ યુઝર ફ્લેર્સને છુપાવવા માટે એક સેટિંગ છે.
@@ -453,9 +451,7 @@
કારણશું બાબત છે?છેતરપિંડી
- અપમાનમજાક
- રેટિંગ છેતરવુંઅન્યરમત(ઓ) ની લિંક પેસ્ટ કરો અને આ વપરાશકર્તાના વર્તન વિશે શું ખોટું છે તે સમજાવો. ફક્ત \"તેઓ છેતરે છે\" એમ ન બોલો, પરંતુ તમે આ નિષ્કર્ષ પર કેવી રીતે આવ્યા તે અમને કહો. જો અંગ્રેજીમાં લખવામાં આવે તો તમારી રિપોર્ટ પર ઝડપથી પ્રક્રિયા કરવામાં આવશે.કૃપા કરીને છેતરાયેલી રમતની ઓછામાં ઓછી એક લિંક પ્રદાન કરો.
diff --git a/translation/dest/site/he-IL.xml b/translation/dest/site/he-IL.xml
index 07c1667f44639..2157e05528c08 100644
--- a/translation/dest/site/he-IL.xml
+++ b/translation/dest/site/he-IL.xml
@@ -72,10 +72,10 @@
העדפת וריאנטקביעה כוריאנט הראשימחיקה מכאן והלאה
- הסתרת מהלכים חלופיים
- הצגת מהלכים חלופיים
+ הסתרת מהלכים חלופיים
+ הצגת מהלכים חלופייםוריאנט יחיד
- העתקת ה-PGN של הוריאנט
+ העתקת ה־PGN של הוריאנטמסעהפסד וריאנטניצחון וריאנט
@@ -92,7 +92,7 @@
דירוג ממוצע: %sמשחקים אחרוניםהמשחקים המובילים
- משחקים על־גבי לוח של שחקנים עם דירוג פיד״ה של %1$s+ מ-%2$s עד %3$s
+ משחקים על־גבי לוח של שחקנים עם דירוג פיד״ה של %1$s+ מ־%2$s עד %3$sמט בעוד חצי מהלך %sמט בעוד %s חצאי מהלכים
@@ -233,7 +233,7 @@
שם משתמששם משתמש או דוא״לשינוי שם המשתמש
- באותיות לועזיות ניתן להחליף אותיות קטנות בגדולות, למשל מ-\"johndoe\" ל-\"JohnDoe\".
+ באותיות לועזיות ניתן להחליף אותיות קטנות בגדולות, למשל מ־\"johndoe\" ל־\"JohnDoe\".שינוי שם המשתמש. ניתן לעשותו פעם אחת בלבד, ורק על ידי החלפת אותיות גדולות בקטנות ולהיפך.ודאו ששם המשתמש שלכם מתאים גם לילדים. לא תוכלו לשנות אותו מאוחר יותר וחשבונות עם שמות משתמש לא הולמים יסגרו!רק לצורך איפוס הסיסמה.
@@ -245,10 +245,10 @@
שכחת סיסמה?הסיסמה הזו נפוצה ביותר וקלה מדי לניחוש.נא לא להשתמש בשם המשתמש בתור הסיסמה.
- השתמשת בסיסמה שלך באתר אחר, ויתכן שהיא מועדת לפריצה. כדי להגן על חשבונך בליצ׳ס, עליך להגדיר סיסמה חדשה. תודה על ההבנה.
+ השתמשת בסיסמה שלך באתר אחר, ויתכן שהיא מועדת לפריצה. כדי להגן על חשבונך ב־Lichess, עליך להגדיר סיסמה חדשה. תודה על ההבנה.את/ה עוזב/ת את Lichess
- לעולם אל תקלידו את סיסמתכם בליצ׳ס באף אתר אחר!
- מעבר ל-%s
+ לעולם אל תקלידו את סיסמתכם ב־Lichessבאף אתר אחר!
+ מעבר ל־%sאל תשתמשו בסיסמה שהציע לכם אדם אחר. הוא ישתמש בה כדי לגנוב את חשבונכם!אל תשמשו בכתובת מייל שהציע אדם אחר. הוא ישתמש בה כדי לגנוב את חשבונכם.עזרה עם אימייל האישור
@@ -473,10 +473,10 @@
זה CAPTCHA של שחמט.לחץ/י על הלוח כדי לעשות מהלך, כדי להוכיח שאת/ה בן אנוש.
- אנא בצע/י את המהלך הנכון בלוח ה-Captcha.
+ אנא בצע/י את המהלך הנכון בלוח ה־Captcha.לא מט
- מט ב-1 ללבן
- מט ב-1 לשחור
+ מט ב־1 ללבן
+ מט ב־1 לשחורנסו שובמתחבר מחדשלא מחובר
@@ -517,7 +517,7 @@
גרףפחות מדקה %s
- פחות מ- %s דקות
+ פחות מ־ %s דקותפחות מ%s דקותפחות מ%s דקות
@@ -533,9 +533,6 @@
בחר/י שם בטוח מאוד לטורניר.כל דבר לא הולם ולו במעט עלול לגרום לסגירת חשבונך.השאירו ריק כדי לקרוא לטורניר על שם שחקן/ית שח דגול/ה.
- אנו ממליצים לא לגעת בזה.
- אם תגדיר/י תנאי כניסה, יהיו בטורניר פחות שחקנים.
- הצגת הגדרות מתקדמותהפכו את הטורניר לפרטי, והגבילו את הכניסה עם סיסמההצטרף/יצא/י
@@ -575,8 +572,7 @@
אם אין, השאירו ריקפרופילעריכת פרופיל
- שם פרטי
- שם משפחה
+ שם אמיתיהגדירו את הסמליל שלכםסמלילישנה הגדרה שמאפשרת להסתיר את כל הסמלילים באתר.
@@ -625,9 +621,7 @@
סיבהמה הבעיה?רמאות
- העלבההטרלה
- מניפולציה בדירוגאחרהדביקו את הקישור למשחק(ים) והסבירו מה לא בסדר בהתנהגות המשתמש. אל תכתבו סתם ״השחקן/ית מרמה״, הסבירו לנו כיצד הגעתם למסקנה הזו. הדיווח יטופל מהר יותר אם ייכתב באנגלית.בבקשה לספק לפחות קישור אחד למשחק עם רמאות.
@@ -662,10 +656,11 @@
איטיבתוך הלוחמחוץ ללוח
+ כל משבצות הלוחבמשחקים איטייםתמידאף פעם
- %1$s מתחרה ב-%2$s
+ %1$s מתחרה ב־%2$sניצחוןהפסד%1$s נגד %2$s ב%3$s
@@ -749,7 +744,7 @@
המשחק הסימולטני אינו קיים.חזרה לדף הבית של המשחקים הסימולטנייםמשחק סימולטני מערב שחקן יחיד אשר משחק נגד שחקנים רבים בו זמנית.
- מתוך 50 משחקים בו־זמנית, פישר ניצח ב-47 משחקים, השיג 2 תוצאות תיקו והפסיד במשחק אחד.
+ מתוך 50 משחקים בו־זמנית, פישר ניצח ב־47 משחקים, השיג 2 תוצאות תיקו והפסיד במשחק אחד.המושג נלקח מאירועים בעולם האמיתי. בחיים האמיתיים, המארח/ת עובר/ת משולחן לשולחן ומשחק/ת מהלך אחד בכל פעם.כאשר המשחק הסימולטני מתחיל, כל שחקן מתחיל את המשחק עם המארח, אשר משחק בתור הלבן. המשחק הסימולטני מסתיים כאשר כל המשחקים מסתיימים.המשחקים הסימולטניים הם תמיד לא מדורגים. האפשרויות של: \"נסה שוב\", ״החזר מהלך״ ו\"הוסף זמן\" מבוטלות.
@@ -800,9 +795,9 @@
%1$s שחקני %2$s השבוע.דירוגך במשחקי %1$s הוא %2$s.
- דירוגך גבוה יותר מ-%1$s משחקני %2$s.
- %1$s טוב יותר מ-%2$s משחקני ה%3$s.
- יותר טוב מ-%1$s משחקני ה־%2$s
+ דירוגך גבוה יותר מ־%1$s משחקני %2$s.
+ %1$s טוב יותר מ־%2$s משחקני ה%3$s.
+ יותר טוב מ־%1$s משחקני ה־%2$sטרם נקבע לך דירוג במשחקי %s.הדירוג שלךמצטבר
@@ -858,7 +853,7 @@
ניתוח המשחק%1$s מארח/ת %2$s
- %1$s מצטרף/ת ל-%2$s
+ %1$s מצטרף/ת ל־%2$s%1$s אוהב/ת את %2$sהצטרפות מהירהלובי
@@ -954,7 +949,7 @@
ושמרו %s המשכים מוגדרים מראשושמרו %s המשכים מוגדרים מראש
- קיבלתם הודעה פרטית מ-Lichess.
+ קיבלתם הודעה פרטית מ־Lichess.לחצו כאן כדי לקרוא אותהמצטערים :(נאלצנו להשעות אותך לזמן מה.
@@ -981,7 +976,7 @@
BlitzRapidClassical
- משחקים מהירים בטירוף: פחות מ-30 שניות על השעון
+ משחקים מהירים בטירוף: פחות מ־30 שניות על השעוןמשחקים מהירים מאוד: פחות מ3 דקות על השעוןמשחקים מהירים: בין 3 ל8 דקותמשחקים זריזים: בין 8 ל25 דקות
@@ -1003,9 +998,9 @@
אתה עדיין לא יכול לפרסם בפורום זה. שחק כמה משחקים!עקובבטל את המעקב
- תייג/ה אותך ב- %1$s.
- %1$s הזכיר/ה אותך בהודעה ב-\"%2$s\".
- הזמין אותך ל-\"%1$s\".
+ תייג/ה אותך ב־ %1$s.
+ %1$s הזכיר/ה אותך בהודעה ב־\"%2$s\".
+ הזמין אותך ל־\"%1$s\".%1$s הזמין/ה אותך ללוח הלמידה \"%2$s\".את/ה כעת חבר/ה בקבוצה.הצטרפת אל \"%1$s\".
@@ -1039,7 +1034,7 @@
צבע מנחה המשחקזמן התחלה משוערהצג ב%s
- גרום למשחק להיות פומבי ב-%s. בטל בשביל משחק סימולטני פרטי.
+ גרום למשחק להיות פומבי ב־%s. בטל בשביל משחק סימולטני פרטי.תיאור המשחק הסימולטנימשהו שאת/ה רוצה להגיד למשתתפים?%s זמין לתחביר מתקדם יותר.
@@ -1071,7 +1066,7 @@
לא תוכל/י להתחיל משחק חדש עד גמר הנוכחי.מאזעד
- משחקים מדורגים אשר נדגמו מכלל שחקני ליצ׳ס
+ משחקים מדורגים אשר נדגמו מכלל שחקני Lichessהפוך צדסגירת החשבון תבטל את פנייתךהטיפים שלנו לארגון אירועים
diff --git a/translation/dest/site/hi-IN.xml b/translation/dest/site/hi-IN.xml
index 38b209c413d2a..84e5eaef88d6c 100644
--- a/translation/dest/site/hi-IN.xml
+++ b/translation/dest/site/hi-IN.xml
@@ -463,9 +463,6 @@
टूर्नामेंट के लिए उचित नाम चुनिए ।थोड़ा सा भी अनुचित नाम चुनने से आपका ख़ाता बंद हो सकता है।खाली रखने पर बेतरतीब ढंग से कोई एक सर्वश्रेष्ठ शतरंज के खिलाड़ी के बाद टूर्नामेंट का नाम चुना जाएगा।
- हम इन चिज़ों को छूने की सलाह नहीं देते ।
- यदि अत्यधिक एवं अनुचित शर्ते रखे तो आपके टूर्नामेंट में कम खिलाड़ियों होंगे।
- एडवांस्ड सेटिंग्स दिखाएंप्रतियोगिता को निजी बनाएं, और पासवर्ड के साथ पहुंच को प्रतिबंधित करेंहिस्सा लेंछोड़ के जाएं
@@ -504,8 +501,6 @@
यदि कोई नहीं, खाली छोड़ दोप्रोफ़ाइलप्रोफ़ाइल संपादित करें
- प्रथम नाम
- अंतिम नामसंपूर्ण साइट पर सभी उपयोगकर्ता विशेषताओं को छिपाने के लिए एक सेटिंग हैजीवनीधन्यवाद!
@@ -549,9 +544,7 @@
कारणबात क्या है?धोखेबाज़ी
- अपमानट्रोल
- जब एक उपयोगकर्ता (lichess. org/report) की रिपोर्टिंग करते हैं, तो \"कारण\" ड्रॉपडाउन के संभावित चयनों में से एक। यह रिपोर्टिंग खिलाड़ियों के लिए है जो उनकी रेटिंग में हेरफेर करते हैं, या तो इसे बढ़ाते हैं या नकली खातों के साथ कृत्रिम रूप से घटाते हैंदूसराखेल/खेलों के लिंक को लगाएं (paste) और बताएँ की यूज़र के व्यवहार में क्या खराबी है|कृपया ठगे गए खेल के लिए कम से कम एक लिंक प्रदान करें।
diff --git a/translation/dest/site/hr-HR.xml b/translation/dest/site/hr-HR.xml
index fc677db2d662d..bed122e319954 100644
--- a/translation/dest/site/hr-HR.xml
+++ b/translation/dest/site/hr-HR.xml
@@ -485,9 +485,6 @@ računalnu analizu, chat partije i URL za dijeljenje.
Odaberi vrlo siguran naziv za turnir.Sve imalo neprikladno može trajno zatvoriti tvoj profil.Ako ostaviš prazno, turnir će se nazvati po nasumičnom velemajstoru.
- Preporučamo da ne ovo ne dira.
- Ako se postavi uvjet za sudjelovanje, turnir će imati manje igrača.
- Prikaži napredne postavkeUčini turnir privatnim i ograniči pristup lozinkomPridruži seOdustani
@@ -526,8 +523,6 @@ računalnu analizu, chat partije i URL za dijeljenje.
Nemaš rejting? Ostavi polje praznoProfilUredi profil
- Ime
- PrezimeŽivotopisHvala!Linkovi društvenih mreža
@@ -570,9 +565,7 @@ računalnu analizu, chat partije i URL za dijeljenje.
RazlogU čemu je problem?Varanje
- VrijeđanjeProvokacija
- Manipulacija rejtingomOstaloZalijepi link na partiju/e u pitanju i objasni što nije u redu s ponašanjem korisnika. Nemoj samo reći \"varao je\", nego reci kako si došao/la do tog zaključka. Tvoja prijava bit će obrađena brže ako ju napišeš na engleskom jeziku.Molimo navedite barem jedan link igre u kojoj je igrač varao.
diff --git a/translation/dest/site/hu-HU.xml b/translation/dest/site/hu-HU.xml
index 6a01ed9b523bc..ce1953df0071a 100644
--- a/translation/dest/site/hu-HU.xml
+++ b/translation/dest/site/hu-HU.xml
@@ -465,9 +465,6 @@
Válassz egy nevet a versenyednek.Akár a legkisebb pontatlanság is a fiókod zárolását eredményezheti.Hagyd üresen, ha azt szeretnéd, hogy a versenyed egy nagymesterről kapjon nevet.
- Azt javasoljuk, hogy ne változtass ezeken.
- Követelmények beállítása esetén kevesebb játékos lesz a versenyen.
- Haladó beállítások megjelenítéseA torna priváttá tétele a fenti jelszóvalCsatlakozásVisszavon
@@ -507,8 +504,6 @@
Ha nincs, hagyd üresenProfilProfil szerkesztése
- Keresztnév
- VezetéknévÁllítsd be az ikonodIkonVan egy beállítás amivel elrejtheted az összes felhasználói ikont az egész oldalon.
@@ -555,9 +550,7 @@
OkProbléma meghatározásaCsalás
- SértegetésTrollkodás
- Pontszám manipulációEgyébMásold be a játék(ok) linkjét, és mondd el, mi a gond a játékos viselkedésével. Ne csak annyit írj, hogy \"csalt\", hanem próbáld elmondani, miből gondolod ezt. A jelentésedet hamarabb feldolgozzák, ha angolul írod.Kérünk, legalább adj meg linket legalább egy csalt játszmához.
diff --git a/translation/dest/site/hy-AM.xml b/translation/dest/site/hy-AM.xml
index c5dc6ab3b114a..92fd850aac1b5 100644
--- a/translation/dest/site/hy-AM.xml
+++ b/translation/dest/site/hy-AM.xml
@@ -461,9 +461,6 @@
Ընտրեք շատ ապահով անվանում մրցաշարի համար։Եթե անվանումը թվա նույնիսկ փոքր-ինչ անհարիր, Ձեզ կարող են արգելափակել։Թողեք դատարկ` մրցաշարը պատահական գրոսմայստերի պատվին կոչելու համար։
- Խորհուրդ չենք տալիս սահմանել այդ պայմանները։
- Եթե Դուք սահմանեք մասնակցության պայմանները, Ձեր մրցաշարին կարող են մասնակցել ավելի քիչ թվով խաղացողներ։
- Ցույց տալ ընդլայնված կարգավորումներըՄրցաշարը դարձնել փակ և մուտքը սահմանափակել գաղտնաբառովՄիանալՉեղարկել
@@ -502,8 +499,6 @@
Կամ թողնել դատարկՊրոֆիլԽմբագրել անձնագիրը
- Անուն
- ԱզգանունԿենսագրությունՇնորհակալությո՛ւն։Հղումներ սոցցանցերին
@@ -545,9 +540,7 @@
ՊատճառԻ՞նչ է պատահելխաբեբա
- վիրավորանքԹրոլինգ
- Կեղծարարություններ վարկանիշի հետայլԿիսվեք մեզ հետ Այն խաղերի հղումներով, որտեղ կարծում եք, որ կանոնները խախտվել են և նկարագրեք, թե ինչն է սխալ: Բավական չէ պարզապես գրել \"Նա խարդախում է\", խնդրում ենք նկարագրել, թե ինչպես եք եկել այս եզրակացության: Մենք ավելի արագ կաշխատենք, եթե գրեք անգլերեն:Խնդրում ենք ավելացնել առնվազն մեկ խաղի հղում, որտեղ ձեր կարծիքով խախտվել են կանոնները:
diff --git a/translation/dest/site/ia-IA.xml b/translation/dest/site/ia-IA.xml
index 26615d09d3525..89642c35c78f7 100644
--- a/translation/dest/site/ia-IA.xml
+++ b/translation/dest/site/ia-IA.xml
@@ -380,9 +380,6 @@
Selige un nomine assatis secur pro le torneo.Mesmo alco levemente inappropriate pote causar que tu conto sia terminate.Lassa iste campo vacue pro que le torneo ha un nomine de un Grande Maestro al hasardo.
- Nos recommenda non modificar isto.
- Si tu impone conditiones de entrata, tu torneo habera minus jocatores.
- Monstrar le configurationes avantiateFacer le torneo esser private, e restringer le accesso con un contrasignoParticiparRetirar se
@@ -417,8 +414,6 @@
Si necun, lassa lo vacueProfiloModificar profilo
- Prenomine
- Nomine de familiaBiographiaGratias!Ligamines de medios social
@@ -457,9 +452,7 @@
RationQue es le problema?Fraude
- InsultoTroll
- Manipulation de classificationAltereColla le ligamine al joco(s) e explica lo que es improprie re le conducto del usator. Non dice solmente \"ille frauda\", ma informa como tu arrivava a iste conclusion. Tu reporto essera processate plus rapidemente si tu scribe in anglese.Per favor, provide al minus un ligamine de un partita fraudate.
diff --git a/translation/dest/site/id-ID.xml b/translation/dest/site/id-ID.xml
index b8d7b158a2bb8..e06add628a579 100644
--- a/translation/dest/site/id-ID.xml
+++ b/translation/dest/site/id-ID.xml
@@ -428,9 +428,6 @@
Pilih nama yang paling aman untuk turnamen.Nama apapun yang bahkan sedikit tidak pantas akan mengakibatkan akun Anda ditutup.Biarkan kosong untuk nama turnamen setelah pengacakan Grandmaster.
- Kita rekomendasikan jangan sentuh ini.
- Jika Anda atur persyaratan masuk, turnamen yang Anda buat akan memiliki lebih sedikit pemain.
- Tampilkan pengaturan lanjutanJadikan turnamen pribadi, dan batasi akses dengan kata sandiGabungKeluar
@@ -470,8 +467,6 @@
Jika tidak ada, biarkan kosongProfilUbah profil
- Nama depan
- Nama BelakangSunting flair andaFlairTerdapat setting untuk menyembunyikan semua flair pengguna pada seluruh situs.
@@ -516,9 +511,7 @@
AlasanApa masalahnya?Cheat
- PenghinaanJebakan
- Manipulasi ratingLainnyaPaste link berikut ke dalam permainan dan jelaskan apa masalah tentang pengguna ini.Harap berikan setidaknya satu tautan ke permainan yang curang.
diff --git a/translation/dest/site/is-IS.xml b/translation/dest/site/is-IS.xml
index c9c1913404157..054038bb8dfb1 100644
--- a/translation/dest/site/is-IS.xml
+++ b/translation/dest/site/is-IS.xml
@@ -416,9 +416,6 @@
Veldu mjög öruggt nafn fyrir mótið.Eitthvað sem er hið minnsta óviðeigandi getur leitt til þess að reikningi verði lokað.Skildu eftir autt til að nefna mótið eftir handahófskennt völdum stórmeistara.
- Við mælum með því að breyta þessu ekki.
- Ef þú setur skilyrði við þátttöku mun mótið hafa færri leikmenn.
- Sýna ítarlegar stillingarLoka móti, og takmarka aðgang með aðgangsorðiTaka þáttafturkalla
@@ -457,8 +454,6 @@
Autt ef á ekki viðPrófíllStillingar
- Fornafn
- EftirnafnLífssagaTakk fyrir!Samfélagsmiðlatengill
@@ -495,7 +490,6 @@
ÁstæðaHvað er að?Svindl
- MóðgunTröllAnnaðLímdu hér hlekk(i) að leik eða leikjum og útskýrðu hvað er að hegðun notandans. Ekki segja bara ,,hann svindlar\'\', en segðu okkur hvernig þú komst að þeirri niðurstöðu. Unnið verður örar úr kvörtuninni ef hún er skrifuð á ensku.
diff --git a/translation/dest/site/it-IT.xml b/translation/dest/site/it-IT.xml
index 29cb8e9c5e8c4..ac0b8633e456a 100644
--- a/translation/dest/site/it-IT.xml
+++ b/translation/dest/site/it-IT.xml
@@ -466,9 +466,6 @@ analizzarla con il computer, commentarla in chat, e condividerla tramite un indi
Scegli un nome appropriato per il torneo.Qualsiasi cosa anche solo lievemente inappropriata potrebbe comportare l\'eliminazione del tuo account.Lascia vuoto il nome del torneo per chiamarlo con il nome di un giocatore famoso casuale.
- Si consiglia di non toccare queste impostazioni.
- Se imponi condizioni d\'accesso il torneo avrà un minor numero di giocatori.
- Mostra impostazioni avanzateRendi privato il torneo e limita l\'accesso con una passwordUniscitiRitirati
@@ -508,8 +505,6 @@ analizzarla con il computer, commentarla in chat, e condividerla tramite un indi
Se nessuno, lasciare vuotoProfiloModifica profilo
- Nome
- CognomeImposta la tua iconaIconaEsiste un\'impostazione per nascondere le icone di tutti gli utenti, sull\'intero sito.
@@ -556,9 +551,7 @@ analizzarla con il computer, commentarla in chat, e condividerla tramite un indi
MotivoQual è il problema?Imbrogli
- InsultiProvocazioni
- Manipolazione del ratingAltroIncolla il link della partita/e e spiega cosa non va con questo giocatore. Non dire soltanto \"ha imbrogliato\", ma specifica come sei arrivato a questa conclusione. Il tuo report verrà processato più velocemente se scritto in lingua inglese.Si prega di fornire almeno un collegamento link di una partita in cui il giocatore ha imbrogliato.
diff --git a/translation/dest/site/ja-JP.xml b/translation/dest/site/ja-JP.xml
index 7406145dafbf2..d445bb096f881 100644
--- a/translation/dest/site/ja-JP.xml
+++ b/translation/dest/site/ja-JP.xml
@@ -69,8 +69,8 @@
変化を主手順にする主手順にするこれ以降を削除
- 変化手順をかくす
- 変化手順を表示する
+ 変化手順をかくす
+ 変化手順を表示する変化として表示手順の PGN をコピー手
@@ -435,9 +435,6 @@
トーナメントの名前は無難なものにしてください。少しでも不適切な名前の場合、あなたのアカウントを停止することがあります。空白のままにしておくと、自動でランダムな有名選手の名前がつきます。
- ここは触らないことを推奨します。
- 参加条件を決めると、当然参加者は少なくなります。
- 「高度な設定」を表示トーナメントを「非公開」にすると参加にパスワードが必要になります参加する参加をやめる
@@ -477,8 +474,7 @@
ない場合は空白でプロフィールプロフィールの編集
- 名
- 姓
+ 実名フレアを設定フレアサイト全体でフレアを非表示にする設定があります。
@@ -524,9 +520,7 @@
理由どうされましたか?ソフト使用
- 侮辱荒らし
- レーティング不正操作その他問題のゲームへのリンクを貼って、相手ユーザーの問題点を説明してください。ただ「イカサマだ」と言うのではなく、なぜそう思うか理由を書いてください。英語で書くと対応が早くできます。不正のあった対局 1 局以上へのリンクを添えてください。
@@ -561,6 +555,7 @@
遅い盤の内盤の外
+ すべてのマスに長時間の対局のみ常に有効無効
diff --git a/translation/dest/site/jbo-EN.xml b/translation/dest/site/jbo-EN.xml
index 6f46ea39caa42..9b8c69f2bb3df 100644
--- a/translation/dest/site/jbo-EN.xml
+++ b/translation/dest/site/jbo-EN.xml
@@ -353,8 +353,6 @@
.e\'o ko gasnu lonu na da\'asnu lo cmene be ti poi grinunjvi.e\'unai lonu lo do jaspu ku cu\'urga\'o cu cumki lonu ba\'ucu\'i toltce da\'asnulo cmene pe lo caxmati mispre cu tecycuxskicauzmi
- .e\'unai
- arco lo certu gaftercu\'acmibi\'oti\'eklalo kelnemka\'u
@@ -386,8 +384,6 @@
lonu noda co\'e cu krinu lonu curmi lonu kuntilo predatnistika lo predatni be do
- lo du\'acme
- lo lazme\'evelski do fo doki\'e.urli lo kibro jikca predatni pesai do
@@ -422,7 +418,6 @@
muktima se mablalo ka toltinbe
- lo ka malskulo ka trololo dratako jarco lo judri pe lo selkei gi\'e ciksi lo du\'u ma kau se mabla lo seltra .i ko na skuxusra ke po\'o lo du\'u jvatoltinbe kei gi\'e cusku lo nibli be ri be\'o pe do .i lo notci pe do cu jai zmadu se sutra fai lo ka se tcidu kei fau lo nu glibau
diff --git a/translation/dest/site/ka-GE.xml b/translation/dest/site/ka-GE.xml
index 0171e587e82a3..5c765372adb94 100644
--- a/translation/dest/site/ka-GE.xml
+++ b/translation/dest/site/ka-GE.xml
@@ -460,9 +460,6 @@
ტურნირისთვის შეარჩიეთ უსაფრთხო სახელი.ნებისმიერი, თუნდაც მცირედი, უტაქტობა გამოიწვევს თქვენი ანგარიშის დახურვას.დატოვეთ ცარიელი, თუ გნებავთ რომ ტურნირს დაერქვას შემთხვევითად შერჩეული ჭადრაკის დიდოსტატის სახელი.
- გირჩევთ ამას არ შეეხოთ.
- თუ თქვენ შესვლის წინაპირობებს დააყენებთ, თქვენს ტურნირს უფრო ცოტა მოთამაშე ეყოლება.
- დამატებითი პარამეტრების ნახვაგახადე ტურნირი დახურული და შეუზღუდე ჭვდომა პაროლითშეუერთდითგავარდნა
@@ -501,8 +498,6 @@
არარსებობის შემთხვევაში დატოვე ცარიელიპროფილიპროფილის განახლება
- სახელი
- გვარიბიოგრაფიაგმადლობთ შეფასებისთვის!სოციალური მედიის ბმულები
@@ -544,9 +539,7 @@
მიზეზიმიზეზიტყული
- შეურაცხყოფაპროვოკაცია
- რეიტინგის მანიპულაციასხვაჩასვით თამაშ(ებ)ის ბმული და მიუთითეთ თუ რა არის საეჭვო მომხმარებლის ქცევაში.გთხოვთ მიუთითო სულ მცირე ერთი პარტიის ბმული სადაც თვლით რომ მოწინააღმდეგემ წესების დარღვევით ითამაშა.
diff --git a/translation/dest/site/kaa-UZ.xml b/translation/dest/site/kaa-UZ.xml
index 0ca9f3330d144..b05a5e233d69d 100644
--- a/translation/dest/site/kaa-UZ.xml
+++ b/translation/dest/site/kaa-UZ.xml
@@ -259,7 +259,6 @@
Turnir kalendarıQatnasıw shártleri:Qosımsha sazlawlar
- Qosımsha sazlawlardı kórsetiwQosılıwOyınnan shıǵıwJeńis
diff --git a/translation/dest/site/kab-DZ.xml b/translation/dest/site/kab-DZ.xml
index 2bca50df0da6d..004dd31c6d8b9 100644
--- a/translation/dest/site/kab-DZ.xml
+++ b/translation/dest/site/kab-DZ.xml
@@ -244,8 +244,6 @@
Ɛeyyen %s ɣer anebdalAlegdisZreg alegdis
- Issem
- Isem n twacultTameddurtTanemmirt!Yakan seg Lichess TV
diff --git a/translation/dest/site/kk-KZ.xml b/translation/dest/site/kk-KZ.xml
index 79e714325daee..5644e60d087b1 100644
--- a/translation/dest/site/kk-KZ.xml
+++ b/translation/dest/site/kk-KZ.xml
@@ -462,9 +462,6 @@
Жарысты түзу, жөнді сөзбен атаңыз.Кез-келген, тіпті шамалы орынсыз әрекет себебінен тіркелгіңіз жабылуы мүмкін.Елеулі бір шахматшының атымен атау үшін бос қалдырыңыз.
- Бұны тиіспеуге кеңес береміз.
- Егер кіру талаптарын қойсаңыз, қатысатын ойыншылар саны аз болады.
- Қосымша баптауларды көрсетуКіруді құпиясөзбен шектеп, жарысты оңашалаңызҚосылыңызЖарыстан шығу
@@ -503,8 +500,6 @@
Жоқ болса, бос қалдырыңызКуәлікКуәлікті өзгерту
- Атыңыз
- ТегіңізӨмірбаянРахмет!Әлеуметтік медиа
@@ -546,9 +541,7 @@
ТүйініНе болды?Чит, алдап ойнау
- ҚорлауТроль, кемсіту
- Рейтингпен айла-шарғыБасқаОйынның (-дардың) сілтемесін қойып, осы ойыншының қай әрекеті орынсыз болғанын түсіндіріп беріңіз. Жай ғана \"ол алдап ойнады\" деп жаза салмай, осы ойға қалай келгеніңізді айтып беріңіз. Сіздің шағымыңыз ағылшын тілінде жазылса, тезірек тексеруден өтеді.Кемі бір ойынның сілтемесін беруіңізді сұраймыз.
diff --git a/translation/dest/site/kmr-TR.xml b/translation/dest/site/kmr-TR.xml
index f4987c0ac7004..2f2b1e7142944 100644
--- a/translation/dest/site/kmr-TR.xml
+++ b/translation/dest/site/kmr-TR.xml
@@ -410,9 +410,6 @@
Ji bo pêşbirkê navekê pir ewle bibijêre.Navekê piçekî nelirê dibe ku bibe sedem ji girtina hesabê te re.Cihê navê vala bihêlî wê bi ketoberî naveke hosteyeke kişikê yê hêja lê were danîn.
- Em pêşniyar dikin ku destê xwe nedî van.
- Ger tu mercên tevlîbûnê saz bikî, wê kêmtir lîzer hebin di pêşbirka te de.
- Sazkariyên pêşketî nîşan bideTûrnûva bik taybet û gihînê jî bi şîfre tengbikTevlê bibeVekişe
@@ -450,8 +447,6 @@
Ger nîn be, vala bihêleProfîlProfîlê sererast bike
- Nav
- PaşnavBiyografîSpas!Têkîliyên Medyaya Civakî
@@ -489,7 +484,6 @@
SedemMijar çi ye?Hîle
- HeqaretTrollYên dinJi bo lîstikê/an lînk pê ve bike û îzah bike ku çi xeletî hene di hal û hereketên vî bikarhênerê de. Tenê nebêje \"ew hîle dike\", bêje me ku tê çawa gihîştiye wê encamê. Ger bi îngîlîzî binivîsînî wê zûtir hel bibe giliya te.
diff --git a/translation/dest/site/kn-IN.xml b/translation/dest/site/kn-IN.xml
index da83dff64cdf3..05d104b4599cf 100644
--- a/translation/dest/site/kn-IN.xml
+++ b/translation/dest/site/kn-IN.xml
@@ -461,9 +461,6 @@
ಪಂದ್ಯಾವಳಿಗೆ ಸುರಕ್ಷಿತ ಹಾಗೂ ಅಪಾಯವಿಲ್ಲದ ಹೆಸರನ್ನು ಆಯ್ಕೆ ಮಾಡಿ.ಕೇವಲ ಸಣ್ಣಮಟ್ಟಿನ ಅನುಚಿತ ಅಥವಾ ಅಸಮಂಜಸ ಹೆಸರುಗಳೂ ಕೂಡ ನಿಮ್ಮ ಖಾತೆಯ ನಿಷೇದಕ್ಕೆ ಕಾರಣವಾಗಬಹುದು.ನಿಮ್ಮ ಪಂದ್ಯಾವಳಿಯನ್ನು ಯಾವುದೋ ಒಬ್ಬರು ಪ್ರಸಿದ್ಧ ಚೆಸ್ ಆಟಗಾರರ ಹೆಸರಿನಲ್ಲಿ ನಾಮಕರಣಗೊಳಿಸಬೇಕೆಂದಿದ್ದರೆ, ಹೆಸರಿನ ಭಾಗವನ್ನು ಖಾಲಿ ಬಿಟ್ಟು ಬಿಡಿ.
- ಇದನ್ನು ಬದಲಾಯಿಸಬೇಡಿ ಎಂದು ಶಿಫಾರಸ್ಸು ಮಾಡುತ್ತೇವೆ.
- ಇನ್ನೂ ಹೆಚ್ಚಿನ ಪ್ರವೇಶಾರ್ಹತೆಗಳನ್ನು ನಿಗದಿಪಡಿಸಿದರೆ, ನಿಮ್ಮ ಪಂದ್ಯಾವಳಿಗೆ ಲಭ್ಯವಾಗುವ ಆಟಗಾರರ ಸಂಖ್ಯೆ ಕಡಿಮೆಯಾಗುವ ಸಾಧ್ಯತೆಯಿದೆ.
- ಇನ್ನೂ ಹೆಚ್ಚಿನ ಅಳವಡಿಕೆಗಳನ್ನು ತೋರಿಸಿಈ ಪಂದ್ಯಾವಳಿಯನ್ನು ಖಾಸಗಿಯಾಗಿಸಿ, ಹಾಗೂ ಕೀಲಿಪದ ಅಂದರೆ ಪಾಸ್ವರ್ಡ್ ಬಳಸಿ ಪ್ರವೇಶವನ್ನು ನಿರ್ಬಂಧಿಸಿಸೇರಿಹಿಂಪಡೆಯಿರಿ
@@ -502,8 +499,6 @@
ಧಾರಣೆ ಇಲ್ಲವಾದರೆ, ಈ ಜಾಗ ಖಾಲಿ ಬಿಟ್ಟು ಬಿಡಿಪ್ರೊಫೈಲುಪ್ರೊಫೈಲ್ ಪರಿಷ್ಕರಿಸಿ
- ಹೆಸರು
- ಕುಟುಂಬನಾಮ (surname)ನಿಮ್ಮ ಬಗ್ಗೆಧನ್ಯವಾದಗಳು!ಸಾಮಾಜಿಕ ಮಾಧ್ಯಮಗಳ ಕೊಂಡಿ
@@ -545,9 +540,7 @@
ಕಾರಣವಿಷಯ ಅಥವಾ ಸಮಸ್ಯೆ ಏನು?ಮೋಸದಾಟ
- ಅವಮಾನಿಸಿದ್ದಾರೆಉಪದ್ರವಿ
- ಧಾರಣೆಯಲ್ಲಿ ವಂಚನೆಇತರೆಮೋಸ ನಡೆದಿದೆ ಎಂಬ ಸಂಶಯವಿರುವ ಆಟದ (ಆಟಗಳ) ಕೊಂಡಿ ಅಥವಾ ಲಿಂಕ್ ಅನ್ನು ಇಲ್ಲಿ ಅಂಟಿಸಿ. ಹಾಗೂ, ಈ ವ್ಯಕ್ತಿಯ ಅಥವಾ ಖಾತೆಯ ವರ್ತನೆಯಲ್ಲಿ ಏನು ಸಮಸ್ಯೆ ಇದೆ ಎಂಬುದನ್ನು ಸ್ಪಷ್ಟವಾಗಿ ವಿವರಿಸಿ. ಕೇವಲ \"ಅವರು ಮೋಸ ಮಾಡಿದ್ದಾರೆ\" ಎಂದಷ್ಟೇ ಬರೆದು ಬಿಡಬೇಡಿ. ಬದಲಾಗಿ, ಹೇಗೆ ಈ ನಿರ್ಧಾರಕ್ಕೆ ಬಂದಿರಿ ಎಂಬುದನ್ನು ವಿವರಿಸಿ. ನಿಮ್ಮ ದೂರು ಇಂಗ್ಲಿಷ್ ಭಾಷೆಯಲ್ಲಿದ್ದರೆ ಬೇಗನೆಯೇ ಪರಿಹಾರ ಸಿಗುವ ಸಾಧ್ಯತೆ ಇದೆ.ದಯವಿಟ್ಟು ಮೋಸಕ್ಕೊಳಗಾದ ಒಂದಾದರೂ ಆಟದ ಕೊಂಡಿಯನ್ನು ಇಲ್ಲಿ ಹಂಚಿಕೊಳ್ಳಿ.
diff --git a/translation/dest/site/ko-KR.xml b/translation/dest/site/ko-KR.xml
index 55f4f6a8b83ac..d69f7e3828067 100644
--- a/translation/dest/site/ko-KR.xml
+++ b/translation/dest/site/ko-KR.xml
@@ -432,9 +432,6 @@
토너먼트 이름은 무난한 것으로 정해주십시오.조금이라도 부적절한 이름일 경우에는 계정이 정지될 수도 있습니다.토너먼트 이름을 공란으로 두면, 임의의 그랜드마스터 선수 이름으로 선택됩니다.
- 이 설정은 되도록이면 그대로 두는 것을 추천합니다.
- 참가조건을 설정하면, 참가자 수가 적어집니다.
- 고급 설정 보기토너먼트를 비공개로 바꾸고, 비밀번호가 있어야만 들어갈 수 있습니다.참가하기중단
@@ -474,8 +471,7 @@
없으면 무시하세요프로필프로필 수정
- 이름
- 성
+ 본명소개국가/지역감사합니다!
@@ -517,9 +513,7 @@
이유무엇이 문제인가요?부정행위
- 모욕분란 조장
- 레이팅 조작기타게임 URL 주소를 붙여넣으시고 해당 사용자가 무엇을 잘못했는지 설명해 주세요.부정행위가 존재하는 게임의 링크를 적어도 하나는 적어주세요.
diff --git a/translation/dest/site/la-LA.xml b/translation/dest/site/la-LA.xml
index d610118c762d8..837ca6892f2f8 100644
--- a/translation/dest/site/la-LA.xml
+++ b/translation/dest/site/la-LA.xml
@@ -396,8 +396,6 @@
Facere certamen novumTabula certaminumOccasus provectus
- Commendamus te non hos mutare.
- Ostende occasus provectusIungereDecederePuncta
@@ -425,8 +423,6 @@
Gradus %sCodexMutare codicem
- Praenomen
- Nomen gentiliciumBiographiaGratias tibi!Prius in Lichess TV
@@ -461,7 +457,6 @@
RatioQuid est?Fraus
- IniuriaBarbarusAliaGlutina inscriptionem lud(i/orum) et explica quid de moribus usuarii malum est.
diff --git a/translation/dest/site/lb-LU.xml b/translation/dest/site/lb-LU.xml
index cc05128a13d49..6613f8068c510 100644
--- a/translation/dest/site/lb-LU.xml
+++ b/translation/dest/site/lb-LU.xml
@@ -70,8 +70,8 @@
Variant opwäertenHaaptvariant maachenVun hei läschen
- Varianten zesummeklappen
- Varianten opklappen
+ Varianten zesummeklappen
+ Varianten opklappenVariant forcéierenPGN-Variant kopéierenZuch
@@ -466,9 +466,6 @@
Wiehl en ganz sécheren Numm fir däin Turnéier.Alles nemmen liicht Onangemessenes kéint zum Zoumaachen vun dengem Konto féieren.Eidel loossen, wann den Turnéier no engem bekannten Schachspiller soll benannt ginn.
- Mir recommandéieren déi net unzepaken.
- Mat Teilnahmebedingungen wäert däin Turnéier maner Spiller hunn.
- Erweidert Optiounen uweisenTurnéier privat maachen an Accès mat Passwuert beschränkenBäitriedenZeréckzéihen
@@ -508,8 +505,7 @@
Eidel loossen, falls kengProfilProfil änneren
- Virnumm
- Numm
+ Richtegen NummBiographieLand oder RegiounMerci!
@@ -553,9 +549,7 @@
GrondWat ass den Problem?Bedruch
- BeleidegungTroll
- WäertungsmanipulatiounAnerPost den Link vun Partie(n) and erklär wat den Problem mat dësem Benotzer sengem Verhalen ass. So net just \"Hien fuddelt\", mee so eis wéi du zu dëser Konklusioun komm bass. Däin Rapport gëtt méi schnell veraarbecht wann en op Englesch ass.Wannechgelift gëff eis op mannst een Link zu enger Partie mat Bedruch.
@@ -590,6 +584,7 @@
LuesUm BrietAußerhalb vum Briet
+ All d\'Felder um BrietAn luesen PartienËmmerNi
diff --git a/translation/dest/site/lt-LT.xml b/translation/dest/site/lt-LT.xml
index 66a91244c200c..37330429494c3 100644
--- a/translation/dest/site/lt-LT.xml
+++ b/translation/dest/site/lt-LT.xml
@@ -532,9 +532,6 @@ kompiuterinę analizę, partijos pokalbį bei URL dalinimuisi.
Pasirinkite labai saugų turnyro pavadinimą.Kas nors bent kiek netinkamo gali lemti jūsų paskyros uždarymą.Palikus tuščią, turnyras bus pavadintas pagal atsitiktinį didmeistrį.
- Rekomenduojame šitų neliesti.
- Jeigu pridėsite dalyvavimo sąlygų, jūsų turnyre bus mažiau žaidėjų.
- Rodyti papildomas nuostatasPadaryti turnyrą privačiu, ir apriboti patekimą su slaptažodžiuPrisijungtiPasitraukti
@@ -574,8 +571,6 @@ kompiuterinę analizę, partijos pokalbį bei URL dalinimuisi.
Jei neturite, palikite tuščiąProfilisRedaguoti profilį
- Vardas
- PavardėPasirinkite savo atskiriamąjį ženklą - avatarąAtskiriamasis ženklasYra nustatymas leidžiantis atjungti visų žaidėjų skiriamuosius ženklus.
@@ -624,9 +619,7 @@ kompiuterinę analizę, partijos pokalbį bei URL dalinimuisi.
PriežastisKas nutiko?Sukčiaviavo
- Ižeidė„Troll\'ino“
- Reitingo manipuliacijaKitaĮdėkite nuorodą į partiją(-as) ir paaiškinkite, kas netinkamo yra šio vartotojo elgsenoje. Paminėkite, kaip priėjote prie tokios išvados. Jūsų pranešimas bus apdorotas greičiau, jei bus pateiktas anglų kalba.Pateikite bent vieną nuorodą į partiją, kurioje buvo sukčiauta.
diff --git a/translation/dest/site/lv-LV.xml b/translation/dest/site/lv-LV.xml
index ef03892cc23e0..bb9a741bdd809 100644
--- a/translation/dest/site/lv-LV.xml
+++ b/translation/dest/site/lv-LV.xml
@@ -492,9 +492,6 @@
Izvēlieties drošu turnīra nosaukumu.Jebkas kaut nedaudz nepiedienīgs var novest pie jūsu konta slēgšanas.Atstājiet neaizpildītu, lai nosauktu turnīru kāda ievērojama šahista vārdā.
- Iesakām šeit neko nemainīt.
- Ja uzstādīsiet dalības noteikumus, jūsu turnīrā piedalīsies mazāk spēlētāju.
- Rādīt lietpratēju uzstādījumusPadarīt turnīru privātu, un ierobežot piekļuvi ar paroliPievienotiesIzstāties
@@ -533,8 +530,6 @@
Ja nav piešķirts, atstājiet tukšuProfilsLabot profilu
- Vārds
- UzvārdsBiogrāfijaPaldies!Sociālo mediju saites
@@ -577,9 +572,7 @@
IemeslsKas par lietu?Krāpšanās
- ApvainošanaTroļļošana
- Reitinga manipulācijaCitsIelīmējiet spēles saiti un paskaidrojiet, kas nav kārtībā ar lietotāja uzvedību. Nepietiks, ja tikai norādīsiet, ka \"lietotājs krāpjas\" — lūdzu, pastāstiet, kā nonācāt pie šī secinājuma. Ja jūsu ziņojums būs rakstīts angliski, par to varēsim parūpēties ātrāk.Lūdzu, norādiet vismaz vienu saiti uz spēli, kurā pretinieks ir krāpies.
diff --git a/translation/dest/site/mg-MG.xml b/translation/dest/site/mg-MG.xml
index 0a7f0811bb291..4b6bc624a65a8 100644
--- a/translation/dest/site/mg-MG.xml
+++ b/translation/dest/site/mg-MG.xml
@@ -333,8 +333,6 @@
Toroy any amin\'ny tompon-andraikitra i %sMombamombaOvay ny mombamomba anao
- Anarana
- Fanampin\'anaranaBiographieMisaotra!Teto amin\'ny Lichess TV
@@ -363,9 +361,7 @@
AntonyInona ny olana?Fanambakana
- FanopanaFananihanina
- Fanovana laharanaAntony hafaMikatona ity lohahevitra ity.Bilaogy
diff --git a/translation/dest/site/mk-MK.xml b/translation/dest/site/mk-MK.xml
index ad680fe71e5fc..750f0f2a7049c 100644
--- a/translation/dest/site/mk-MK.xml
+++ b/translation/dest/site/mk-MK.xml
@@ -456,9 +456,6 @@
Одбери многу безбедно име за турнирот.И најмалку непристојни работи можат да ви ја затворат сметката.Остави празно за турнирот да биде крстен по шаховски првак.
- Препорачуваме да не ги менувате овие поставки.
- Ако поставите услови за влез, вашиот турнир ќе има помалку играчи.
- Покажи ги напредните поставкиНаправи го турнирот приватен и ограничи го пристапот со лозинкаПриклучи сеПредади
@@ -497,8 +494,6 @@
Без рејтинг? Остави го полето празноПрофилУреди го профилот
- Име
- ПрезимеБиографијаБлагодарам!Врски на друштвени мрежи
@@ -540,9 +535,7 @@
ПричинаКаде е проблемот?Мамење
- НавредаТрол
- Манипулација на рејтингДругоВнесете линк од играта/игрите и објаснете каде е проблемот во однесувањето на овој корисник. Немојте само да обвините за мамење, туку објаснете како дојдовте до тој заклучок. Вашата пријава ќе биди разгледана побрзо ако е напишана на англиски јазик.Ве молиме доставете барем една врска до партија со мамење.
diff --git a/translation/dest/site/ml-IN.xml b/translation/dest/site/ml-IN.xml
index a0c1e46153f1e..6a2a6e65950a2 100644
--- a/translation/dest/site/ml-IN.xml
+++ b/translation/dest/site/ml-IN.xml
@@ -407,9 +407,6 @@
ടൂർണമെന്റിന് വളരെ സുരക്ഷിതമായ പേര് കൊടുക്കുക.എന്തെങ്കിലും ചെറിയ ഔചിത്യപൂർണമല്ലാത്ത പ്രവൃത്തി മതി നിങ്ങളുടെ അക്കൗണ്ട് പൂട്ടാൻ.ടൂർണമെന്റിന്റെ പേര് ഒഴിവാക്കി വിട്ടാൽ ഏതെങ്കിലും ഗ്രാൻഡ്മാസ്റ്ററുടെ പേരിലായിരിക്കും ടൂർണമെന്റ് നടത്തപ്പെടുക.
- ഇവ തൊടരുതെന്ന് ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു.
- പ്രവേശനത്തിനുള്ള നിബന്ധനങ്ങൾ നിങ്ങൾ സെറ്റ് ചെയ്താൽ, അത് കുറച്ചു കളിക്കാർ മാത്രം നിങ്ങളുടെ ടൂർണമെന്റിൽ കളിക്കുന്നതിനു കാരണമാകും.
- നൂതനമായ ക്രമീകരണംടൂർണമെന്റ് പ്രൈവറ്റ് ആക്കുക പാസ്സ്വേർഡ് വെച്ച് സംരക്ഷിക്കുകപങ്കെടുക്കാംറദ്ദാക്കുക
@@ -446,8 +443,6 @@
ഒന്നുമില്ലെങ്കിൽ ഒഴിവാക്കിയിടുകരൂപരേഖരൂപരേഖ തിരുത്താം
- നൽകിയ പേര്
- അവസാന പേര്ജീവചരിത്രംനന്ദി!സമൂഹമാധ്യമ ലിങ്കുകൾ
@@ -486,9 +481,7 @@
കാരണംഎന്താണു സംഗതി?ചതി
- അധിക്ഷേപംചൂണ്ട
- റേറ്റിംഗ് കൃത്യമംമറ്റുള്ളവഗെയിമിന്റെ ലിങ്ക് ഇവിടെ പേസ്റ്റ് ചെയ്യുക. ശേഷം യുസറിന്റെ പെരുമാറ്റത്തിലെ അപാകത ഞങ്ങളോട് വിശദമായി പറയുക. \"they cheat\" എന്ന് പറയരുത്. പക്ഷെ എന്തുകൊണ്ട് നിങ്ങൾ ആ അഭിപ്രായത്തിലേക്ക് എത്തി എന്നാണ് പറയേണ്ടത്. ഇംഗ്ലീഷിൽ എഴുതിയാൽ നിങ്ങളുടെ റിപ്പോർട്ട് വേഗത്തിൽ വിശകലനം ചെയ്യപ്പെടും.കുറഞ്ഞത് ഒരു കളിയുടെയെങ്കിലും ലിങ്ക് നല്കേണ്ടതാണ്.
diff --git a/translation/dest/site/mn-MN.xml b/translation/dest/site/mn-MN.xml
index 10ef6fafc554a..5c9769b6e3a5f 100644
--- a/translation/dest/site/mn-MN.xml
+++ b/translation/dest/site/mn-MN.xml
@@ -427,9 +427,6 @@
Тэмцээний хувьд маш аюулгүй нэр сонгоно уу.Бүр бага зэрэг зохисгүй зүйл таны данс хаагдах боломжтой болно.Тэмцээний Grandmaster-ийн дараа хоосон орхи.
- Бид эдгээрийг хөндөхгүй байхыг зөвлөж байна.
- Хэрэв та орох нөхцөлийг тохируулсан бол таны тэмцээн цөөхөн тоглогчтой болно.
- Нарийвчилсан тохиргоог харуулахХувийн тур нууц үгтэйгээр үүсгэхНэгдэхТэмцээнийг орхих
@@ -469,8 +466,6 @@
Байхгүй бол хоосон орхиГишүүний хуудасТанилцуулга хуудсаа засварлах
- Өөрийн нэр
- Эцгийн нэрНэрнийхээ хажууг чимэглэхЭможиСайтанд байгаа бүх нэрний хажуу зүйлсийг нуух тохиргоо байдгийг санаарай.
@@ -515,9 +510,7 @@
ШалтгаанШалтгаан?Булхайцсан
- ДоромжилсонТохуурхсан
- Үнэлгээгээ гуйвуулахӨөр шалтаанТа энэ гишүүнтэй тоглосон өргийнхөө холбоос хаягыг энд хуулж тавиад зүй бус үйлдлийнх нь талаар тайлбар бичнэ үү. Та хэрхэн энэ гишүүнийг булхайцсан үйлдэл хийсэн гэсэн дүгнэлтэд хүрсэн бэ? Хэрэв та гомдлоо англи хэлээр мэдүүлвэл бид илүү түргэн шуурхай арга хэмжээ авах болно.Тоглоомын дор хаяж нэг холбоосыг оруулна уу.
diff --git a/translation/dest/site/mr-IN.xml b/translation/dest/site/mr-IN.xml
index e87b10cb1b4e7..2a9b717a8a398 100644
--- a/translation/dest/site/mr-IN.xml
+++ b/translation/dest/site/mr-IN.xml
@@ -428,9 +428,6 @@
क्रीडासत्रासाठी खूप सुरक्षित नाव निवडा.थोडे अनुचित काहीही आपले खाते बंद करू शकते.क्रीडासत्राला उल्लेखनीय बुद्धिबळपटूचे नाव देणीसाठी रिकामे सोडा.
- आमच्या मते तुम्ही याला बदलू नये.
- आपण प्रविष्टी आवश्यकता सेट केल्यास, आपल्या क्रीडासत्रात कमी खेळाडू असतील.
- प्रगत सेटिंग्ज दाखवाक्रीडासत्र खाजगी करा, व पासवर्डने प्रवेश मर्यादित करासामील व्हामागे घ्या
@@ -469,8 +466,6 @@
काहीही नसल्यास रिक्त सोडाप्रोफाइलप्रोफाईल संपादित करा
- नाव
- आडनावचरित्रआभारी आहेसोशल मीडिया दुवे
@@ -511,9 +506,7 @@
कारणकाय समस्या आहेफसवणूक
- अपमानथट्टा
- रेटिंग मॅनिपुलेशनइतरखेळाचा दुवा पेस्ट करा आणि या वापरकर्त्याच्या वर्तनाबद्दल काय चुकीचे आहे ते सांगा. फक्त \"ते फसवतात\" असे म्हणू नका, परंतु आपण या निष्कर्षावर कसे आलात ते सांगा. इंग्रजीमध्ये लिहिले असल्यास आपल्या अहवालावर वेगवान प्रक्रिया केली जाईल.कृपया फसवणूक झालेल्या खेळासाठी किमान एक दुवा प्रदान करा.
diff --git a/translation/dest/site/ms-MY.xml b/translation/dest/site/ms-MY.xml
index 77bfc09f23cbd..52c4166b4daf6 100644
--- a/translation/dest/site/ms-MY.xml
+++ b/translation/dest/site/ms-MY.xml
@@ -421,9 +421,6 @@ analisis komputer, perbualan dalam permainan dan URL kongsi bersama.
Pilih nama yang selamat untuk pertandingan ini.Sebarang perkara yang tidak senonoh boleh menyebabkan akaun anda ditutup.Biarkan kosong untuk menamakan pertandingan kepada pemain catur terkenal.
- Kami menasihat agar tidak menukar tetapan ini.
- Jika anda tetapkan keperluan kemasukan, pertandingan anda akan ada lebih sedikit pemain.
- Tunjukkan tetapan lanjutanBuat pertandingan privasi peribadi and kurangkan akses dengan kata kunciSertaTarik diri
@@ -462,8 +459,6 @@ analisis komputer, perbualan dalam permainan dan URL kongsi bersama.
Jika tiada, biar kosongProfilSunting profile
- Nama yang diberi
- Nama keluargaBiografiTerima kasih!Pautan media sosial
@@ -498,9 +493,7 @@ analisis komputer, perbualan dalam permainan dan URL kongsi bersama.
SebabApa masalahnya?Penipuan
- Unsur ejekanUnsur jenaka
- Manipulasi TarafLain-lainLaporkan link kepada permainan dan terangkan apa yang dilakukan oleh pengguna yang tidak betul. Jangan hanya beritahu \"mereka menipu\" tapi terangkan juga bagaimana anda dapatkan konklusi ini. Laporan anda akan diproses lebih cepat jika ditulis dalam English.Tolong berikan sekurangnya satu link kepada game yang dicurigai ditipu.
diff --git a/translation/dest/site/nb-NO.xml b/translation/dest/site/nb-NO.xml
index c1a31af2191f6..dc61f5eb832fc 100644
--- a/translation/dest/site/nb-NO.xml
+++ b/translation/dest/site/nb-NO.xml
@@ -70,8 +70,8 @@
Forfrem variantGjør til hovedvariantSlett herfra
- Skjul varianter
- Vis varianter
+ Skjul varianter
+ Vis varianterVis som variantKopier variant-PGNTrekk
@@ -467,9 +467,6 @@
Velg et veldig trygt navn for turneringen.Upassende innhold kan føre til at brukerkontoen din blir stengt.La stå tomt for at turneringa skal få navn etter en tilfeldig stormester.
- Vi anbefaler å ikke endre disse.
- Om du stiller betingelser for å delta vil turneringa få færre deltakere.
- Vis avanserte innstillingerGjør turneringen privat og begrens tilgang med et passordBli medTrekk deg
@@ -509,8 +506,7 @@
Hvis ingen, la stå tomProfilRediger profil
- Fornavn
- Etternavn
+ Virkelig navnVelg flairFlairDet finnes en innstilling for å skjule alle brukerflairer på hele nettstedet.
@@ -557,9 +553,7 @@
ÅrsakHva gjelder det?Juks
- FornærmelseTroll
- RatingmanipuleringAnnetKopier lenken til partiet/partiene og forklar hva som er galt med denne brukerens oppførsel.Oppgi minst én lenke til et jukseparti.
@@ -594,6 +588,7 @@
SakteInnenfor brettetUtenfor brettet
+ Alle felt på brettetPå lange partierAlltidAldri
diff --git a/translation/dest/site/ne-NP.xml b/translation/dest/site/ne-NP.xml
index 343f61a2b8df1..ebac23c994e0a 100644
--- a/translation/dest/site/ne-NP.xml
+++ b/translation/dest/site/ne-NP.xml
@@ -438,9 +438,6 @@
प्रतियोगिताको लागि एउटा असाध्यै सभ्य नाम रोजौं।थोरै पनि अवैधानिक भएमा तपाइको खाता नै बन्द गर्न सकिनेछ।खाली राखेमा कुनै ग्र्याण्डमास्टरको नाम आफै राखिनेछ।
- यीनलाई नछुने सल्लाह दिईन्छ।
- यस्ता प्रावधानहरू राख्दा प्रतियोगितामा खेलाडीको संख्या कम हुन जान्छ।
- उन्नत सेटिङहरू देखाऔंप्रतियोगितालाई निजी बनाई पासवर्ड चाहिने बनाऔँभाग लिनुहोस्फिर्ता
@@ -475,8 +472,6 @@
नभएको खण्डमा खाली छोडौंप्रोफाइलप्रोफाइल सम्पादन गर्नुहोस्
- शुभनाम
- थरजीवनीधन्यवाद!सामाजिक सञ्जाल लिङ्क
@@ -513,7 +508,6 @@
कारणसमस्या के हो?चोरी
- मानहानीट्रोलअन्यसबै खेलको लिङ्क पेष्ट गरी खेलाडीको व्यवहारमा के गलत छ र तपाई त्यो निष्कर्षमा कसरी पुग्नुभयो उल्लेख गर्नुहोस्। अंग्रेजी भाषाको प्रयोग गर्नुभयो भने छिटो निष्कर्षमा पुग्न सकिनेछ।
diff --git a/translation/dest/site/nl-NL.xml b/translation/dest/site/nl-NL.xml
index 6de9fd1f1ec8c..31ff9c7ea460a 100644
--- a/translation/dest/site/nl-NL.xml
+++ b/translation/dest/site/nl-NL.xml
@@ -70,8 +70,8 @@
Promoveer variantMaak hoofdvariantVerwijder vanaf hier
- Varianten verbergen
- Varianten weergeven
+ Varianten verbergen
+ Varianten weergevenForceer variatieKopieer variatie PGNZet
@@ -466,9 +466,6 @@
Kies een zeer veilige naam voor het toernooi.Bij zelfs het minste vermoeden van een misplaatst gekozen naam, kan uw account gesloten worden.Laat het veld leeg om het toernooi naar een willekeurige grootmeester te vernoemen.
- Wij raden aan om deze niet aan te raken.
- Als u voorwaarden voor deelname instelt, zullen er minder spelers meedoen.
- Toon uitgebreide instellingen >>Maak het toernooi privé en beperk de toegang met een wachtwoordNeem deelTrek terug
@@ -508,8 +505,7 @@
Leeg indien n.v.t.ProfielPas profiel aan
- Voornaam
- Achternaam
+ Echte naamStel je flair inSymboolEr bestaat een instelling om alle gebruikersflairs over de hele site te verbergen.
@@ -556,9 +552,7 @@
RedenWat is er aan de hand?Valsspelen
- BeledigenProvoceren
- Rating manipulatieAndersPlak de link naar de partij(en) en leg uit wat er mis is met het gedrag van de gebruiker. Zeg niet alleen \'hij speelt vals\', maar vertel ons hoe u bent gekomen op deze conclusie. Uw rapportage zal sneller worden verwerkt als het in het Engels is geschreven.Geef ten minste één link naar een partij waarin vals gespeeld is.
@@ -593,6 +587,7 @@
TraagBinnen het bordBuiten het bord
+ Alle velden van het bordAlleen bij langzame partijenAltijdNooit
diff --git a/translation/dest/site/nn-NO.xml b/translation/dest/site/nn-NO.xml
index 64a80714a7d24..27ba66009450c 100644
--- a/translation/dest/site/nn-NO.xml
+++ b/translation/dest/site/nn-NO.xml
@@ -468,9 +468,6 @@ få en computeranalyse, chatte eller dele ein URL.
Finn eit svært sikkert namn på turneringa.Upassande innhald kan føre til at brukarkontoen din blir stengd.Lat stå tomt for at turneringa skal få namn etter ein tilfeldig stormester.
- Vi tilrår å ikkje endre desse.
- Om du set opp vilkår for deltaking vil turneringa di få færre deltakarar.
- Vis avanserte innstillingarGjer turneringa privat og avgrens tilgang vha. eit passordBli medTrekk deg
@@ -510,8 +507,7 @@ få en computeranalyse, chatte eller dele ein URL.
Om ingen, lat stå tomtProfilRediger profilen
- Førenamn
- Etternamn
+ Verkelege namnVel eit ikon som best representerer talentet dittTalentDet finst ei innstilling for å skjule symbolet for spelarane sine talent på heile nettstaden.
@@ -558,9 +554,7 @@ få en computeranalyse, chatte eller dele ein URL.
ÅrsakKva gjeld saka?Juks
- ÆrekrenkingTroll
- RatingmanipuleringAnnaLim inn link til partiet/partia og forklar kva som er gale med åtferda til denne brukaren.Oppgje minst ei lenke til eit jukseparti.
@@ -595,6 +589,7 @@ få en computeranalyse, chatte eller dele ein URL.
SaktePå brettetUtanfor brettet
+ Alle felt på brettetI parti med lang tidAlltidAldri
diff --git a/translation/dest/site/or-IN.xml b/translation/dest/site/or-IN.xml
index e23819d422dad..bcba6566aaaa4 100644
--- a/translation/dest/site/or-IN.xml
+++ b/translation/dest/site/or-IN.xml
@@ -194,15 +194,11 @@
ଖେଳାଳିଏକ ନୂଆ ଟୁର୍ନାମେଣ୍ଟ ସୃଷ୍ଟି କରନ୍ତୁଵିକଶିତ ସେଟିଂ
- ଏଗୁଡ଼ିକୁ ସ୍ପର୍ଶ ନକରିବାକୁ ଆମେ ସୁପାରିଶ କରୁ।
- ଯଦି ଆପଣ ପ୍ରବେଶ ଆବଶ୍ୟକତାକୁ ସେଟ୍ କରନ୍ତି, ତେବେ ଆପଣଙ୍କ ଟୁର୍ନାମେଣ୍ଟରେ କମ୍ ଖେଳାଳି ରହିବେ।
- ଵିକଶିତ ସେଟିଂ ଦେଖାଅବୋର୍ଡ ସମ୍ପାଦକଘରୋଇପ୍ରୋଫାଇଲ୍ ସମାପ୍ତି: %sପ୍ରୋଫାଇଲ୍ପ୍ରୋଫାଇଲ୍ ସମ୍ପାଦନା
- ପ୍ରଦତ୍ତ ନାମଜୀବନୀଧନ୍ୟବାଦ!ପ୍ରତି ଧାଡ଼ିରେ ଗୋଟିଏ URL।
diff --git a/translation/dest/site/os-SE.xml b/translation/dest/site/os-SE.xml
index 1453652f07d2a..26db56ed8cd22 100644
--- a/translation/dest/site/os-SE.xml
+++ b/translation/dest/site/os-SE.xml
@@ -392,9 +392,6 @@
Равзар æдас ном турнирæн.Турниры ном куы зæрдæхсайгæ уа, уæд блокадæ дын акæндзысты.Ныууадз афтидæй, цæмæй турнир уыд сæмбæлгæ гроссмейстеры номæн.
- Фæлтау сæ ма æвнал.
- Хайады домæнтæ куы раттдзынæ, уæд дæ ерысы къаддæр адæм хъаздзысты.
- Равдисын баххæстæг настройкæтæТурнир æхгæдæй скæнын æмæ бацæуæн арæн скæнын паролæйХайад исынНыууадзын
@@ -429,8 +426,6 @@
Кæд нæй, ныууадз афтидæйПрофильПрофиль æндæр кæнын
- Ном
- МыггагМахи тыххæйБузныг!Социалон хызтæм дæнцæгтæ
@@ -469,9 +464,7 @@
АххосЦы хабар у?Фæлитой митæ
- БафхæрдТроллинг
- Рейтингимæ махинацитæÆндæрБавæр дæнцæгтæ ахæм хъæзтытæм, кæм, дæм кæсы, уыдысты уагты халынтæ, æмæ бамбарын кæ, цы хабар у. Комкоммæ зæгъын \"уый сайы\" æнæфаг у, радзур нын, ахæм хатдзæгмæ куыд æрцыдтæ. Мах тагъддæр кусдзыстæм, англисагау кæд фысдзынæ.Табуафси, бафтау æммыст иу дæнцæг ахæм хъазтмæ, кæм, дæм кæсы, уыдысты уагты халынтæ.
diff --git a/translation/dest/site/pl-PL.xml b/translation/dest/site/pl-PL.xml
index bb9d250caf713..c2687e9602c72 100644
--- a/translation/dest/site/pl-PL.xml
+++ b/translation/dest/site/pl-PL.xml
@@ -533,9 +533,6 @@
Nadaj turniejowi neutralną nazwę.Nawet nieco nieodpowiednia nazwa może spowodować zamknięcie Twojego konta.Jeśli nie podasz nazwy turnieju, zostanie on nazwany od nazwiska losowo wybranego arcymistrza.
- Zalecamy nie zmieniać tych ustawień.
- Ustawienie warunków wstępu sprawi, że do turnieju przystąpi mniej osób.
- Pokaż ustawienia zaawansowaneUstaw turniej jako prywatny i ogranicz dostęp za pomocą hasłaDołączWycofaj się
@@ -575,8 +572,7 @@
Jeśli nie masz, zostaw pusteProfilEdycja profilu
- Imię
- Nazwisko
+ Prawdziwe nazwiskoUstaw swój emblematEmblematIstnieje ustawienie, pozwalające ukryć wszystkie emblematy użytkowników na lichess.
@@ -625,9 +621,7 @@
PowódJakie to ma znaczenie?Oszust
- ZnieważenieNatręt (troll)
- Manipulacja rankingiemInneWklej odnośnik do partii i wyjaśnij, co złego jest w zachowaniu tego użytkownika. Nie pisz tylko, że „oszukuje”, ale wytłumacz nam, na jakiej podstawie doszedłeś/aś do takiego wniosku. Odniesiemy się do twojego zgłoszenia szybciej, jeżeli napiszesz je w języku angielskim.Podaj przynajmniej jeden odnośnik do gry, w której oszukiwano.
@@ -662,6 +656,7 @@
WolnoNa szachownicyPoza szachownicą
+ Wszystkie pola szachownicyW wolniejszych partiachZawszeNigdy
diff --git a/translation/dest/site/pt-BR.xml b/translation/dest/site/pt-BR.xml
index 705434a0b1373..0200a37228fc3 100644
--- a/translation/dest/site/pt-BR.xml
+++ b/translation/dest/site/pt-BR.xml
@@ -467,9 +467,6 @@
Escolha um nome seguro para o torneio.Até mesmo a menor indecência poderia ensejar o encerramento de sua conta.Deixe em branco para dar ao torneio o nome de um grande mestre aleatório.
- Recomendamos não mexer nisso.
- Se você restringir as condições de participação, haverá menos jogadores no torneio.
- Exibir configurações avançadasFaça o torneio privado e restrinja o acesso com uma senhaEntrarSair
@@ -509,8 +506,7 @@
Se nenhuma, deixe vazioPerfilEditar perfil
- Primeiro nome
- Sobrenome
+ Nome realEscolha seu emoteEstiloVocê pode esconder todos os emotes de usuário no site.
@@ -557,9 +553,7 @@
MotivoQual é o motivo?Trapaça
- InsultoTroll
- Manipulação de ratingOutroCole o link do(s) jogo(s) e explique o que há de errado com o comportamento do usuário. Não diga apenas \"ele trapaceia\", informe-nos como chegou a esta conclusão. Sua denúncia será processada mais rapidamente se escrita em inglês.Por favor forneça ao menos um link para um jogo com suspeita de trapaça.
@@ -594,6 +588,7 @@
LentoDentro do tabuleiroFora do tabuleiro
+ Todas as casas do tabuleiroEm partidas lentasSempreNunca
diff --git a/translation/dest/site/pt-PT.xml b/translation/dest/site/pt-PT.xml
index b6e72e924705f..1557a2e6d3731 100644
--- a/translation/dest/site/pt-PT.xml
+++ b/translation/dest/site/pt-PT.xml
@@ -468,9 +468,6 @@ análise de computador, sala de chat do jogo e link de partilha.
Escolhe um nome totalmente seguro para o torneio.Até uma linguagem ligeiramente inadequada pode levar ao encerramento da tua conta.Deixe em branco e será atribuído um nome aleatório de um jogador notável ao torneio.
- Recomendamos que não mechas nestas oções.
- Se definies condições de participação, o teu torneio terá menos jogadores.
- Mostrar as definições avançadasTorna o torneio privado e restrinje o acesso com uma palavra-passeEntrarSair
@@ -510,8 +507,7 @@ análise de computador, sala de chat do jogo e link de partilha.
Se não existir, deixa em brancoPerfilEditar o perfil
- Nome próprio
- Apelido
+ Nome RealDefina o teu estiloEstiloHá uma opção para ocultar todos os estilos dos utilizadores em todo o site.
@@ -558,9 +554,7 @@ análise de computador, sala de chat do jogo e link de partilha.
MotivoQual é o motivo?Batota
- InsultoTroll
- Manipulação do EloOutroInclui o link do(s) jogo(s) e explica o que há de errado com o comportamento deste utilizador. Não digas apenas \"ele faz batota\"; informa-nos como chegaste a essa conclusão. A tua denúncia será processada mais rapidamente se for escrita em inglês.Por favor, fornece-nos pelo menos um link para um jogo onde tenha havido batota.
@@ -595,6 +589,7 @@ análise de computador, sala de chat do jogo e link de partilha.
LentoDentro do tabuleiroFora do tabuleiro
+ Todas as casas do tabuleiroEm jogos lentosSempreNunca
diff --git a/translation/dest/site/ro-RO.xml b/translation/dest/site/ro-RO.xml
index 1aea4d893578d..77b1278e2097a 100644
--- a/translation/dest/site/ro-RO.xml
+++ b/translation/dest/site/ro-RO.xml
@@ -498,9 +498,6 @@
Alege un nume foarte sigur pentru turneu.Orice nume care este chiar și ușor nepotrivit poate cauza închiderea contului tău.Lăsați necompletat pentru a numi turneul după un jucător bun de șah.
- Iți recomandăm să nu modifici aceste setări.
- Dacă stabilești condiții de intrare, turneul tău va avea mai puțini jucători.
- Afișează setările avansateFaceți competiția privată și restricționați accesul cu o parolăIntrăRetrage-te
@@ -540,8 +537,7 @@
Dacă nu există, nu completațiProfilEditează profilul
- Prenume
- Nume
+ Nume realPictograma personalizatăBiografieȚara sau regiunea
@@ -586,9 +582,7 @@
MotivCare este problema?Trișează
- InsultăTroll
- Manipularea evaluăriiAltcevaAdaugă link-ul de la joc(uri) și arată ce este greșit cu privire la acest comportament al utilizatorului. Nu preciza doar ”trișează”, ci spune-ne cum ai ajuns la această concluzie. Raportul tău va fi procesat mai rapid dacă este scris în engleză.Te rugăm să furnizezi cel puțin un link către un joc în care s-a trișat.
diff --git a/translation/dest/site/ru-RU.xml b/translation/dest/site/ru-RU.xml
index 97db45e465e21..e6a96b18d12aa 100644
--- a/translation/dest/site/ru-RU.xml
+++ b/translation/dest/site/ru-RU.xml
@@ -533,9 +533,6 @@
Выберите для турнира как можно более безопасное название.Если название хотя бы немного покажется неуместным, вас могут заблокировать.Оставьте пустым, чтобы назвать турнир в честь случайного гроссмейстера.
- Мы не рекомендуем задавать эти условия.
- Если вы зададите условия участия, то в вашем турнире сможет принять участие меньше игроков.
- Показать дополнительные настройкиСделать турнир закрытым и ограничить доступ паролемУчаствоватьПокинуть
@@ -575,8 +572,6 @@
Если нет, оставьте пустымПрофильРедактировать профиль
- Имя
- ФамилияЗадайте свой эмодзиЭмодзиЭта настройка скрывает все эмодзи пользователей на всём сайте.
@@ -625,9 +620,7 @@
ПричинаЧто это было?Жульничество
- ОскорблениеТроллинг
- Махинации с рейтингомДругоеПоделитесь с нами ссылками на игры, где, как вам кажется, были нарушены правила, и опишите, в чём дело. Недостаточно просто написать «он мухлюет», пожалуйста, опишите, как вы пришли к такому выводу. Мы сработаем оперативнее, если вы напишете на английском языке.Пожалуйста, добавьте ссылку хотя бы на одну игру, где по вашему мнению были нарушены правила.
diff --git a/translation/dest/site/ry-UA.xml b/translation/dest/site/ry-UA.xml
index cf0068068e27a..8dbcab2447c67 100644
--- a/translation/dest/site/ry-UA.xml
+++ b/translation/dest/site/ry-UA.xml
@@ -429,7 +429,6 @@
ТриманяПобідникТурнірна табела
- Кідь покладете условія, менше зможе бавити на турнірови.Прикапчати сяЛишитиБалув
@@ -444,7 +443,6 @@
ЗакрытыйРейтінґ %sПрофіл
- ПрозвищеЗа сяЗахарити ходыУспіх
@@ -471,7 +469,6 @@
ХосновачПричинаЧітерство
- ОскорбаТролінґИншакоєПодїліт ся из нами одкликованями на бавкы, де вам ся видит, были нарушені правила, ай опишіт, у чому дїло. Не доста просто написати \"ун чітер\", уповічте чому сьте так рішили. Наріканя достане одвіт скорше, кідь оно на анґлійськув бисідї.
diff --git a/translation/dest/site/sco-GB.xml b/translation/dest/site/sco-GB.xml
index 2be0b84d6f4b8..ebb9e7f81180e 100644
--- a/translation/dest/site/sco-GB.xml
+++ b/translation/dest/site/sco-GB.xml
@@ -310,9 +310,6 @@
Wale a gey mensefu name for the kemp.E\'en o barelins menseless cuild gar yer accoont ill end.Let abe tae caw the kemp efter a faur-kent chess pleyyer.
- We rede ye no titch thir.
- If ye set entry perconnons, yer kemp maun gaither fewer pleyyers.
- Shaw pernicketie setsMak the kemp preevat, an stent access wae a trystwirdJineResile
@@ -340,9 +337,7 @@
RaisonWhit\'s wrang?Cleek
- LichtlieFash
- Ratin maneepulatitItherPaste the link tae the gemm(s) an expone whit\'s wrang anent this uiser\'s behaviour. Dinnae juist say \"they cleek\", but tell us whitwey ye\'d cam tae this end. Yer clype will be processit faster gin scrievit wae English.Please provide least ane line tae a cleekit gemm.
diff --git a/translation/dest/site/si-LK.xml b/translation/dest/site/si-LK.xml
index a0d17df83072d..a95bfa55f2b69 100644
--- a/translation/dest/site/si-LK.xml
+++ b/translation/dest/site/si-LK.xml
@@ -417,9 +417,6 @@ You are playing chess.
තරඟාවලිය සඳහා ඉතා ආරක්ෂිත නමක් තෝරන්න.තරමක් නුසුදුසු ඕනෑම දෙයක් නිසා ඔබගේ ගිණුම වසා දැමිය හැක.කැපී පෙනෙන චෙස් ක්රීඩකයෙකුගේ නමින් තරඟාවලිය නම් කිරීමට හිස්ව තබන්න.
- මේවා ඇල්ලීම නොකරන ලෙස අපි නිර්දේශ කරමු.
- ඔබ ප්රවේශ අවශ්යතා සකසන්නේ නම්, ඔබේ තරඟාවලියට ක්රීඩකයින් සංඛ්යාව අඩු වනු ඇත.
- උසස් සැකසුම් පෙන්වන්නතරඟාවලිය පුද්ගලික කරන්න, මුරපදයකින් ප්රවේශය සීමා කරන්නඑකතු වන්නඉල්ලා අස් වෙන්න
@@ -459,8 +456,6 @@ You are playing chess.
කිසිවක් නොමැති නම්, හිස්ව තබන්නපැතිකඩපැතිකඩ සංස්කරණය කරන්න
- මුල් නම
- වාසගමඔබේ ෆ්ලෙයාර්ය සකසන්නෆ්ලෙයාරයසම්පූර්ණ වෙබ් අඩවිය හරහා සියලුම පරිශීලක ෆ්ලෙයාර සැඟවීමට සැකසීමක් ඇත.
@@ -507,9 +502,7 @@ You are playing chess.
හේතුවකාරණය කුමක් ද?වංචාකරණය
- අපහාස කිරීමට්රෝල් කිරීම
- ශ්රේණිගත කිරීම් වංචාවවෙනත්ක්රීඩා(ව) වෙත සබැඳිය අලවා මෙම පරිශීලකයාගේ හැසිරීමේ ඇති වරද කුමක්දැයි පැහැදිලි කරන්න. \"ඔවුන් වංචා කරනවා\" පමණක් නොකියන්න, නමුත් ඔබ මෙම නිගමනයට පැමිණියේ කෙසේදැයි අපට කියන්න. ඔබේ වාර්තාව ඉංග්රීසියෙන් ලියා ඇත්නම් වේගයෙන් සකසනු ලැබේ.වංචා කළ ක්රීඩාව සඳහා එක් සබැඳියක්වත් දීමට කාරුණික වන්න.
diff --git a/translation/dest/site/sk-SK.xml b/translation/dest/site/sk-SK.xml
index f7eb9ef00fe9f..426d9c1ad92c3 100644
--- a/translation/dest/site/sk-SK.xml
+++ b/translation/dest/site/sk-SK.xml
@@ -532,9 +532,6 @@
Názov turnaja vyberajte s rozvahou!Čokoľvek čo i len mierne nevhodné môže mať za následok uzavretie Vášho účtu.Ak názov nevyplníte, turnaj bude pomenovaný po náhodnom veľmajstrovi.
- Tieto nastavenia odporúčame ponechať nedotknuté.
- Ak nastavíte podmienky účasti, Váš turnaj bude mať menej hráčov.
- Zobraziť pokročilé nastaveniaNastav turnaj ako súkromný a obmedz prístup k nemu pomocou heslaPripojiťOdstúpiť
@@ -574,8 +571,7 @@
Ak nemáte, nevyplňujteProfilUpraviť profil
- Meno
- Priezvisko
+ Skutočné menoNastavte si svoju ikonku štýluIkonka štýluV nastaveniach je možné skryť všetky ikonky štýlu používateľov na celej stránke.
@@ -623,9 +619,7 @@
DôvodČo sa deje?Podvod
- UrážkaTroll
- Ovplyvňovanie ratinguInéVložte odkaz na hru/y, a vysvetlite, čo je zlé na tomto správaní používateľa.Prosím, uveďte aspoň jeden odkaz na partiu, v ktorej sa podvádzalo.
@@ -660,6 +654,7 @@
PomalyVnútri šachovniceMimo šachovnice
+ Všetky políčka šachovnicePri pomalých hráchVždyNikdy
diff --git a/translation/dest/site/sl-SI.xml b/translation/dest/site/sl-SI.xml
index 45b0341f50a14..434cf8d83832d 100644
--- a/translation/dest/site/sl-SI.xml
+++ b/translation/dest/site/sl-SI.xml
@@ -532,9 +532,6 @@
Izberite zelo varno ime za turnir.Že zelo majhna neprimernost lahko povzroči ukinitev vašega računa.Pustite prazno, da bo turnir imenovan po naključnem velemojstru.
- Priporočamo, da se tega ne dotikate.
- Če nastavite pogoje za vstop, bo imel vaš turnir manj igralcev.
- Prikaži napredne nastavitveNaredi turnir zaseben in zaščiti dostop z geslomPridruži seZapusti turnir
@@ -574,8 +571,6 @@
Če ni, pustite praznoProfilUredi profil
- Ime
- PriimekDoločite svoj okusSimbolObstaja nastavitev za skrivanje vseh uporabniških čustev na celotnem spletnem mestu.
@@ -624,9 +619,7 @@
RazlogKaj je narobe?Goljufija
- ŽalitevProvokacija
- Manipulacija z ratingiDrugoPrilepite povezave do igre (ali iger) in pojasnite kaj je narobe z obnašanjem uporabnika. Ne napišite samo \"uporabnik goljufa\" temveč pojasnite zakaj mislite tako. Prijava bo obdelana hitreje če bo napisana v angleščini.Navedite vsaj eno povezavo do igre s primerom goljufanja.
diff --git a/translation/dest/site/sq-AL.xml b/translation/dest/site/sq-AL.xml
index 81ebc24c7f7be..18b90e7552ea6 100644
--- a/translation/dest/site/sq-AL.xml
+++ b/translation/dest/site/sq-AL.xml
@@ -468,9 +468,6 @@ loje dhe URL për ta ndarë me të tjerë.
Zgjidhni një emër shumë të sigurt për turneun.Çfarëdo gjëje qoftë edhe pakëz e papërshtatshme mund të sjellë mbylljen e llogarisë tuaj.Për ta emërtuar turneun me emrin e një lojtari të njohur shahu, lëreni të zbrazët.
- Rekomandojmë të mos i prekni këto.
- Nëse ujdisni domosdoshmëri pjesëmarrjeje, turneu juaj do të ketë më pak lojtarë.
- Shfaq rregullimet të thelluaraBëjeni turneun privat dhe kufizojeni hyrjen me një fjalëkalimMerrni pjesëTërhiquni
@@ -509,8 +506,7 @@ loje dhe URL për ta ndarë me të tjerë.
Në mos pastë, lëreni të zbrazëtProfilPërpunoni profilin
- Emër
- Mbiemër
+ Emër i njëmendtëJetëshkrimVend ose rajonFaleminderit!
@@ -554,9 +550,7 @@ loje dhe URL për ta ndarë me të tjerë.
ArsyeSi është puna?Hile
- FyerjeTroll
- Manipulim vlerësimiTjetërNgjitni lidhjen për te loja(ra) dhe shpjegoni çfarë nuk shkon me sjelljen e këtij përdoruesi. Mos shkruani thjesht “mashtrojnë”, por na tregoni si mbërritët në këtë përfundim. Raportimi juaj do të përpunohet më shpejt, nëse shkruhet në anglisht.Ju lutemi, jepni të paktën një lidhje te një lojë me hile.
@@ -591,6 +585,7 @@ loje dhe URL për ta ndarë me të tjerë.
NgadalëBrenda fushësJashtë fushës
+ Në krejt katrorët e fushësNë lojëra të ngadaltaPërherëKurrë
diff --git a/translation/dest/site/sr-SP.xml b/translation/dest/site/sr-SP.xml
index 301b6ca9a1575..722949d859423 100644
--- a/translation/dest/site/sr-SP.xml
+++ b/translation/dest/site/sr-SP.xml
@@ -474,9 +474,6 @@
Изаберите веома сигурно име за турнир.Било које име које је бар мало неприкладно може да вам затвори налог.Оставите празно како би назвали турнир по насумично изабраном Велемајстору.
- Препоручујемо да немењате ове.
- Ако ставите услове за улаз, ваш турнир ће имати мање играча.
- Покажи напредна подешавањаУчини турнир приватним и ограничи приступ са шифромПридружи сеПовуци се
@@ -516,8 +513,6 @@
Ако немате рејтинг, оставите празноПрофилУредите профил
- Име
- ПрезимеПостави своју значкуЗначкаПостоји подешавање којим се сакривају све корисникове значке на читавом сајту.
@@ -565,9 +560,7 @@
РазлогY чему је проблем?Варање
- УвредаТрол
- Манипулација рејтингомОсталоЗалијепите везу до игре и објасните шта није у реду са понашањем корисника. Немојте само рећи \"варао\", али реците како сте дошли до тог закључка. Ваша пријава ће бити обрађена брже ако је напишете на енглеском језику.Наведите барем једну везу игре у којој је играч варао.
diff --git a/translation/dest/site/sv-SE.xml b/translation/dest/site/sv-SE.xml
index e302fa1d8f27a..b7724b7fa146c 100644
--- a/translation/dest/site/sv-SE.xml
+++ b/translation/dest/site/sv-SE.xml
@@ -464,9 +464,6 @@
Välj ett mycket säkert namn för turneringen.Någonting, om än bara lite, olämpligt skulle kunna få ditt konto att stängas.Lämna tom för att namnge turneringen efter en slumpmässig stormästare.
- Vi rekommenderar att inte röra dessa.
- Om du anger inträdesvillkor kommer din turnering att ha färre spelare.
- Visa avancerade inställningarGör turneringen privat, och begränsa åtkomst med ett lösenordDeltaLämna
@@ -506,8 +503,7 @@
Om ingen, lämna tomtProfilÄndra profil
- Förnamn
- Efternamn
+ Verkligt namnStäll in din flairFlairDet finns en inställning för att dölja alla användarflairs över hela webbplatsen.
@@ -554,9 +550,7 @@
AnledningVad är problemet?Fusk
- FörolämpningTroll
- Manipulation av ratingAnnatKlistra in länken till partiet och förklara vad som är fel med den här användarens beteende. Säg inte bara \"de fuskar\", utan förklara hur du dragit denna slutsats. Din rapport kommer att behandlas fortare om den är skriven på engelska.Ange minst en länk till ett spel där användaren fuskade.
diff --git a/translation/dest/site/ta-IN.xml b/translation/dest/site/ta-IN.xml
index accd138ff7c49..a0e53d8f46fe9 100644
--- a/translation/dest/site/ta-IN.xml
+++ b/translation/dest/site/ta-IN.xml
@@ -449,9 +449,6 @@
போட்டிக்கு மிகவும் பாதுகாப்பான பெயரைத் தேர்ந்தெடுக்கவும்.சற்று பொருத்தமற்றது கூட உங்கள் கணக்கை மூடக்கூடும்.ஒரு குறிப்பிடத் தக்க சதுரங்க வீரரின் பெயரைப் போட்டிக்குப் பெயரிட காலியாக விடவும்.
- இவற்றில் மாற்றம் செய்யவேண்டாமெனப் பரிந்துரைக்கின்றோம்.
- நீங்கள் போட்டியாளர்களுக்கான நிபந்தனைகளை உருவாக்கினால், உங்கள் போட்டிகளில் குறைவான வீரர்களே பங்குபற்றுவார்கள்.
- மேம்பட்ட அமைப்புகளைப் பார்க்கவும்போட்டியைத் தனிப்பட்டதாக்க, கடவுச்சொல் கொண்டு அணுக்கத்தைக் கட்டுப்படுத்தவும்சேர்விலகு
@@ -491,8 +488,6 @@
இல்லையென்றால் காலியாக விடலாம்குறிப்புகள்தகவல்களை மாற்று
- முதல் பெயர்
- கடைசி பெயர்உங்கள் திறமையை அமைக்கவும்தளம் முழுவதும் அனைத்து பயனர் திறமைகளையும் மறைக்க ஒரு அமைப்பு உள்ளது.வாழ்க்கை சரித்திரம்
@@ -537,9 +532,7 @@
காரணம்என்ன விஷயம்?வஞ்சகன்
- அவமதிப்புஅக்கிரமி
- மதிப்பீட்டைச் சூழ்ச்சியுடன் திரித்தல்வேறுவிளையாட்டு (கள்) இணைப்பை ஒட்டவும் மேலும் இந்த பயனர் நடத்தை பற்றி தவறு என்ன என்பதை விளக்க. வெறும் \"அவர்கள் ஏமாற்றுகின்றனர்\" சொல்ல வேண்டாம், ஆனால் நீங்கள் இந்த முடிவுக்கு வந்தது எப்படி எங்களுக்கு சொல்ல. ஆங்கிலத்தில் எழுதப்பட்ட என்றால் உங்கள் அறிக்கை வேகமாக செயல்படுத்தப்படும்.ஏமாற்றப்பட்ட விளையாட்டிற்கு குறைந்தபட்சம் ஒரு இணைப்பை வழங்கவும்.
diff --git a/translation/dest/site/te-IN.xml b/translation/dest/site/te-IN.xml
index 6b765aa214823..9397e6bc2c7a0 100644
--- a/translation/dest/site/te-IN.xml
+++ b/translation/dest/site/te-IN.xml
@@ -394,9 +394,6 @@
టోర్నమెంట్ కోసం చాలా సురక్షితమైన పేరును ఎంచుకోండి.కొంచెం అనుచితమైన ఏదైనా మీ ఖాతా మూసివేయబడుతుంది.చెస్ ఆటగాడి పేరు మీద టోర్నమెంట్ పేరు పెట్టడానికి ఖాళీగా ఉండండి.
- వీటిని తాకవద్దని మేము సిఫార్సు చేస్తున్నాము.
- మీరు ప్రవేశ అవసరాలను సెట్ చేస్తే, మీ టోర్నమెంట్లో తక్కువ మంది ఆటగాళ్ళు ఉంటారు.
- అధునాతన సెట్టింగ్లను చూపించుటోర్నమెంట్ను ప్రైవేట్గా చేయండి మరియు పాస్వర్డ్తో ప్రాప్యతను పరిమితం చేయండిచేరండిఉపసంహరించుకోండి
@@ -433,8 +430,6 @@
ఏదీ లేకుంటే, ఖాళీగా వదిలివేయండిప్రొఫైల్ప్రొఫైల్ మార్చాలి
- ఇచ్చిన పేరు
- ఇంటిపేరుజీవిత చరిత్రధన్యవాదాలు!సోషల్ మీడియా లింక్లు
@@ -474,9 +469,7 @@
కారణంమీరు ఎందుకు రిపోర్టు చేస్తున్నారు?మోసం
- అవమానంఎగతాళి చేయండి
- రేటింగ్ మానిప్యులేషన్ఇతరగేమ్/గేమ్ల లింక్ను పంపండి మరియు ఈ వినియోగదారు ప్రవర్తనలో తప్పు ఏమిటో వివరించండి. \"వారు మోసం చేసారు\" అని చెప్పకండి, కానీ మీరు ఈ నిర్ణయానికి ఎలా వచ్చారో మాకు చెప్పండి. మీ నివేదికను ఆంగ్లంలో వ్రాస్తే వేగంగా ప్రాసెస్ చేయబడుతుంది.దయచేసి కనీసం మోసం చేసిన ఆట ఒక లింక్నైనౌ అందించండి.
diff --git a/translation/dest/site/th-TH.xml b/translation/dest/site/th-TH.xml
index b328f6e008a10..784bbc5fe4060 100644
--- a/translation/dest/site/th-TH.xml
+++ b/translation/dest/site/th-TH.xml
@@ -432,9 +432,6 @@
เลือกชื่อที่ปลอดภัยสุดสำหรับทัวร์นาเมนต์อะไรที่ไม่เหมาะสมแม้เพียงเล็กน้อย ก็สามารถทำให้บัญชีของคุณถูกปิดได้ปล่อยว่างไว้เพื่อตั้งชื่อทัวร์นาเมนต์หลังจากสุ่มแกรนด์มาสเตอร์
- เราแนะนำว่าอย่าแตะต้องสิ่งเหล่านี้
- ถ้าคุณตั้งค่าเงื่อนไขการเข้าร่วม ทัวร์นาเมนต์ของคุณจะมีผู้เข้าเล่นได้น้อยลง
- แสดงการตั้งค่าขั้นสูงทำทัวร์นาเมนต์ให้เป็นส่วนตัว และจำกัดการเข้าถึงด้วยรหัสผ่านเข้าร่วมถอนตัว
@@ -474,8 +471,6 @@
ถ้าไม่มี, จงเว้นว่างข้อมูลประจำตัวแก้ไขข้อมูลประจำตัว
- ชื่อจริง
- นามสกุลตั้งค่ารูปตกแต่งรูปตกแต่งมันมีการตั้งค่าที่ทำให้ไม่สามารถเห็นรูปตกแต่งของผู้ใช้ได้ทั้งเวบไซต์
@@ -521,9 +516,7 @@
เหตุผลเกิดอะไรขึ้น?โกง
- ดูหมิ่นป่วน
- การปรับแต่งระดับคะแนนอื่นๆวางลิงค์ที่ไปสู่เกม และอธิบายว่าผู้ใช้นี้มีพฤติกรรมที่ผิดอะไร อย่าบอกเพียงว่า \"พวกเขาโกง\" แต่บอกเราว่าคุณสรุปแบบนี้เพราะอะไร การรายงานของคุณจะเร็วขึ้นถ้าเขียนด้วยภาษาอังกฤษโปรดระบุอย่างน้อยหนึ่งลิงก์ เพื่อเชื่อมโยงไปยังเกมที่มีการโกง
diff --git a/translation/dest/site/tk-TM.xml b/translation/dest/site/tk-TM.xml
index 18a47a2938391..5e7fadb5c95b5 100644
--- a/translation/dest/site/tk-TM.xml
+++ b/translation/dest/site/tk-TM.xml
@@ -362,9 +362,6 @@ kompýuter derňewi, oýun çäti we paýlaşmaga URL alýaňyz.
Bäsleşik üçin diýseň howpsuz at saýlaň.Sähelçe bijaý zat hem hasabyňyzyň ýapylmagyna eltip biler.Bäsleşigi çem gelen bir grossmeýster şanyna atlandyrmak üçin bu bölümi boş goýuň.
- Muny ellemezligi ündeýäs.
- Gatnaşma şertleri goýsaňyz bäsleşigiňize az oýunçy gatnaşar.
- Çuňlaşdyrylan sazlamalary görkezGatnaşÇekilUtuklar
@@ -398,8 +395,6 @@ kompýuter derňewi, oýun çäti we paýlaşmaga URL alýaňyz.
Ýok bolsa boş goýuňProfilProfili özgert
- Ady
- FamilýasyBiografiýaMinnetdar!Notasiýa şol bir setirde
@@ -435,7 +430,6 @@ kompýuter derňewi, oýun çäti we paýlaşmaga URL alýaňyz.
SebäpNäme bolýär?Kezzaplyk
- KemsitmeTrolBaşgaOýnyň çelgisini üpjün ediň we bu ulanyjynyň özüni alyp barşynda näme ýerliksizlik bardygyny hem düşündiriň. Diňe bir \"ol kezzaplyk edýär\" diýmek bilen çäklenmäň, nädip beýle netijä gelendigiňizem aýdyň. Iňlis dilinde ýazylan bolsa reportyňyz has çalt ýola goýular.
diff --git a/translation/dest/site/tl-PH.xml b/translation/dest/site/tl-PH.xml
index bbe901f46bdcf..62645128476b5 100644
--- a/translation/dest/site/tl-PH.xml
+++ b/translation/dest/site/tl-PH.xml
@@ -406,9 +406,6 @@
Pumili ka ng angkop na pangalan ng paligsahan.Maaaring masara ang iyong account kapag naglagay ka ng kahit anong hindi naaangkop na bagay.Pabayaang walang laman upang pangalanan ang paligsahang ito sa isang Grandmaster.
- Payo naming huwag pakialaman ang mga ito.
- Kung maglagay ka ng mga kondisyon upang makapasok, kakaunti ang mga maglalaro ng iyong paligsahan.
- Ipakita ang mga masulong na settingGawing pribado ang paligsahan, at higpitan ang access sa pamamagitan ng isang passwordSumaliUmalis
@@ -447,8 +444,6 @@
Kung wala, iwang walang lamanProfileI-edit ang profile
- Pangalan
- ApelyidoTalambuhaySalamat!Mga link ng social media
@@ -490,9 +485,7 @@
DahilanAno ang problema?Pandaraya
- InsultoAwitin
- Pagmamanipula ng ratingIba paI-paste ang link sa mga laro at ipaliwanag kung ano ang mali tungkol sa ugali ng gumagamit. Huwag mo lamang sabihin na \"sila\'y nandaya\", pero sabihin mo sa amin kung paano mo ito nasabi. Ang iyong report ay ipoproseso ng mas mabilis kapag nakasulat sa English.Magbigay ng kahit na isang link sa dinayang laro.
diff --git a/translation/dest/site/tp-TP.xml b/translation/dest/site/tp-TP.xml
index a689b1a38132f..30966952a0b6b 100644
--- a/translation/dest/site/tp-TP.xml
+++ b/translation/dest/site/tp-TP.xml
@@ -446,9 +446,6 @@ o musi lon lipu pona. sina wile ala pana e nimi li wile ala e ilo. sitelen esun
o pana e nimi pona tawa utala musi ni. o kepeken e nimi ike, e nimi ni: ona li ike tawa jan antesina pana e nimi ike tawa utala musi la, lipu lawa sina li ken kama pakala.sina pana ala e nimi la, nimi li kama tan jan musi suli pi musi pi lawa mije moli.
- mi toki insa e ni: sina wile ala ante e ona.
- utala musi sina li jo e nasin open, jan musi pi mute lili li kama tawa ona.
- o pana lukin e ante nasin muteo pana e nimi awen tawa utala musi sina tawa ni: jan pona sina taso li ken kama tawa ona.kamatawa weka
@@ -487,8 +484,6 @@ o musi lon lipu pona. sina wile ala pana e nimi li wile ala e ilo. sitelen esun
ala li lon la, o sitelen alalipu janante e sona jan
- nimi jan
- nimi mamasitelen namakosona jan sinapona tawa sina!
@@ -530,9 +525,7 @@ o musi lon lipu pona. sina wile ala pana e nimi li wile ala e ilo. sitelen esun
tan seme?jan ni li ike seme?musi ike
- toki ikepakala e musi
- jan li ante ike e nanpaijo anteo pana e nimi nasin tawa musi. o toki e ni: jan li musi ike lon nasin seme? o toki ala e \"ona li toki kepeken ilo ike\". o toki e ni: sina kama sona e ni tan seme? sina toki kepeken toki Inli la, mi lukin e toki sina lon tenpo lili.o pana e nimi nasin tawa musi pi pali ike.
diff --git a/translation/dest/site/tr-TR.xml b/translation/dest/site/tr-TR.xml
index b05f639832607..480605f989c43 100644
--- a/translation/dest/site/tr-TR.xml
+++ b/translation/dest/site/tr-TR.xml
@@ -70,6 +70,8 @@
Bu varyanttan devam etAna devam yolu yapBu hamleden sonrasını sil
+ Varyasyonları daralt
+ Varyasyonları genişlerVaryant olarak gösterVaryasyon PGN\'sini kopyalaHamle
@@ -465,9 +467,6 @@
Turnuva için oldukça güvenli bir isim seçin.Herhangi bir uygunsuz isim, hesabınızın yasaklanmasına yol açabilir.Kutuyu boş bırakarak turnuvaya rastgele bir Büyükusta\'nın ismini verebilirsiniz.
- Bu ayarlara dokunmamanızı öneririz.
- Turnuvaya katılım şartı koyarsanız, daha az oyuncu katılacaktır.
- Gelişmiş ayarları gösterTurnuvayı özel olarak ayarlayın ve şifre koyarak erişimi kısıtlayınKatılÇekil
@@ -507,8 +506,7 @@
Eğer yoksa, boş bırakınProfilProfili düzenle
- Ad
- Soyad
+ Gerçek isimRozetinizi seçinRozetAyarlardan oyuncu rozetlerini gizleyebilirsiniz.
@@ -555,9 +553,7 @@
SebepProblem nedir?Hile
- HakaretTrol
- Puan manipülasyonuDiğerRaporlamak istediğiniz oyunun linkini yapıştırın ve sorununuzu açıklayın. Lütfen sadece \"hile yapıyor\" gibisinden açıklama yazmayın, hile olduğunu nasıl anladığınızı açıklayın. Rapor edeceğiniz kişiyi ya da oyunu \"İngilizce\" açıklarsanız, daha hızlı sonuca ulaşırsınız.Lütfen hileli gördüğünüz en az 1 adet oyun linki verin.
diff --git a/translation/dest/site/tt-RU.xml b/translation/dest/site/tt-RU.xml
index f2172f631cc4a..82671c730c73c 100644
--- a/translation/dest/site/tt-RU.xml
+++ b/translation/dest/site/tt-RU.xml
@@ -368,9 +368,6 @@
Бәйге өчен хуп имин исем куегыз.Әз генә дә килешми торган исем аккаунтыгызның ябылуына китерә ала.Бәйгегә берәр атаклы шаһматчының исемен бирү өчен буш калдырыгыз.
- Боларны тимәскә кинәш итәбез.
- Бәйгегә керү тәлапләрен куйсагыз, уенчылар саны әзрәк булыр.
- Кушылма көйләүләрне күрсәтүБәйгегә серсүз буенча гына керү куя аласызКатнашуУеннан чыгу
@@ -407,8 +404,6 @@
Булмаса, буш калдырыгызПрофильПрофильны үзгәртү
- Исем
- ФамилияҮзең турындаРәхмәт!Социаль медиа сылтамалары
@@ -446,9 +441,7 @@
СәбабНәрсә булды?Алдамак
- ХурламакТроль
- Рейтинг белән уйнамакБүтәнУен(нар) сылтамаларын кертегез һәм бу кулланучының тәртибендә дөрес булмаганны аңлатыгыз. \"Алдакчы\" дип кенә әйтмәгез, бу нәтиҗәгә ничек килгәнегезне әйтегез. Сезнең җибәрүегез инглизчә язылган очракта тизрәк эшкәртеләчәк.Зинһар, алданган уенга ким дигәндә бер сылтама бирегез.
diff --git a/translation/dest/site/uk-UA.xml b/translation/dest/site/uk-UA.xml
index 316293925f55b..051f900c72711 100644
--- a/translation/dest/site/uk-UA.xml
+++ b/translation/dest/site/uk-UA.xml
@@ -72,6 +72,8 @@
Підвищити пріоритет варіантаЗробити варіант основнимВидалити з цього місця
+ Згорнути варіанти
+ Розгорнути варіантиЗробити варіантомСкопіювати PGN варіантуХід
@@ -531,9 +533,6 @@
Оберіть пристойну назву для турніру.Все, що навіть трохи виявиться недоречним, може призвести до блокування.Залиште пустим, щоб назвати турнір на честь випадкового гросмейстера.
- Ми радимо не змінювати їх.
- Якщо ви встановите умови вступу, у вашому турнірі буде менше гравців.
- Показати додаткові налаштуванняЗробити турнір приватним та обмежити доступ паролемПриєднатисьВідступити
@@ -573,8 +572,7 @@
Якщо немає, то залиште порожнімПрофільРедагувати профіль
- Ім\'я
- Прізвище
+ Справжнє ім\'яОберіть свій символСимволЦе налаштування вимикає символи всіх користувачів сайту.
@@ -623,9 +621,7 @@
ПричинаЩо трапилося?Нечесна гра
- ОбразаТролінг
- Маніпуляції з рейтингомІншеВставте посилання на гру (ігри) та поясніть, що не так із поведінкою цього користувача. Не пишіть просто \"він шахраює\", а розкажіть, як ви дійшли до такого висновку. Вашу скаргу розглянуть швидше, якщо ви напишете її англійською.Будь ласка, додайте посилання на хоча б одну нечесну гру.
@@ -660,6 +656,7 @@
ПовільнаУсередині шахівниціПоза шахівницею
+ Усі поля дошкиУ повільних іграхЗавждиНіколи
diff --git a/translation/dest/site/ur-PK.xml b/translation/dest/site/ur-PK.xml
index 526d2eccbe05f..bde29359525f3 100644
--- a/translation/dest/site/ur-PK.xml
+++ b/translation/dest/site/ur-PK.xml
@@ -398,9 +398,6 @@
ٹورنامنٹ کا ایک محتاط نام رکھیں.کسی قسم کی نا مناسب حرکت کی وجہ سے آپ کا اکاونٹ بند ہو سکتا ہے۔.خانے کو خالی چھوڑنے سے ٹورنامنٹ کا نام کسی مشہور کھلاڑی پر رکھ دیا جائے گا.
- ہمارہ مشورہ ہے کہ اس کے ساتھ چھیڑ چھاڑ نہ کریں.
- اگر آپ داخلے کی شرائط مقرر کریں گے تو ٹورنامنٹ میں کم کھلاڑی آئیں گے.
- اعلی ترتیبات دکھائیںٹورنامنٹ کی حیثیت ذاتی کر دیں، اور رسائی صرف پاس ورڈ کے ذریعے ہو سکے گیشامل ہوںدستبردار ہوں
@@ -437,8 +434,6 @@
اگر کوئی نہیں تو خالی چھوڑ دیںاکاؤنٹاکاؤنٹ میں ترمیم کریں
- پہلا نام
- آخری نامسوانح حیاتآپ کا شکریہ!سوشل میڈیا کے لنکس
@@ -476,7 +471,6 @@
شکایت کی وجہمعاملہ؟بدعنوانی
- ہتک آمیز گفتگوسیاپہ فروشیدیگرمتاثرہ مقابلوں کے رابطے یہاں داخل کریں اور شکایت کی وجوہات بیان کریں
diff --git a/translation/dest/site/uz-UZ.xml b/translation/dest/site/uz-UZ.xml
index 548d68b4af6cd..b275b42e4b21c 100644
--- a/translation/dest/site/uz-UZ.xml
+++ b/translation/dest/site/uz-UZ.xml
@@ -5,6 +5,7 @@
Kimnidir o\'yinga taklif qilish uchun ushbu URL ni olib unga beringO‘yin tugadiSherik tanlanishi kutilayabdi
+ Yoki ushbu QR kodni skanerlash uchun opponentingizga beringKutib turingSizni yurishingiz%1$s daraja %2$s
@@ -69,7 +70,10 @@
O\'zgarishlarni qo\'llashAsosiy chiziqni yaratishBu yerdan o\'chirish
+ Variantlarni yashirish
+ Variantlarni koʻrsatishMajburiy o\'zgartirish
+ Variantning PGN ini nusxalashYurishYo\'qotish variantiYutuq varianti
@@ -115,6 +119,7 @@
Ochiq ta\'limYoqishYaxshi yo\'l ko\'rsatmasi
+ Variantlar strelkalarini koʻrsatishBaholash ko\'rsatkichiBir nechta chiziqlarMarkaziy protsessorlar soni
@@ -273,6 +278,7 @@
O\'yinni bekor qilishO\'yin bekor qilindiStandart
+ Foydalanuvchi joyidanChegaralanmaganHolatNorasmiy
@@ -402,6 +408,7 @@
O\'yinni import qilishPGN o\'yinni qo\'ying va qayta o\'ynashlar, kompyuter tahlili, o\'yin chati va ulashish linkiga ega bo\'ling.Variantlar o‘chiriladi. Ularni saqlash uchun PGN yordamida \"ta‘lim\"da saqlang.
+ Ushbu PGN ommaga ochiq boʻladi. Oʻyinni yopiq holatda import qilish uchun study - oʻrganish boʻlimidan foydalaning.%s import qilingan o\'yin%s import qilingan o\'yinlar
@@ -414,6 +421,7 @@
Qoralar bitta yurishda motQayta urinishQaytadan ulanmoqda
+ Oflayn%s ta o\'rtoq onlayn%s ta o\'rtoqlar onlayn
@@ -459,9 +467,6 @@
Turnir uchun juda ham xavfsiz nom tanlash.Sal noqulayku lekin so\'rashimiz joiz, balkim sizni akkountingizni yopish kerak.Turnir nomini tasodifiy Grassmeyster nomiga moslab qo\'yish uchun ochiq qoldiring.
- Biz sizga bu joyda teginmaslikni maslahat beramiz.
- Agar siz kirish shartlarini sozlagan bo\'lsangiz, sizni turniringiz kam kishidan iborat bo\'ladi.
- Qo\'shimcha shartlarni namoyish qilishYopiq turnir yarating va ishtirokchilarga parol yordamida kirishga huquq beringQo\'shilishChekinish
@@ -482,6 +487,7 @@
Yurilgan yo\'llarOqlar g\'alabalariQoralar g\'alabalari
+ Oʻyin tezligiDurranglarKeyingi %s turnir:O\'rtacha raqiblar soni
@@ -500,8 +506,9 @@
Agar yo\'q bo\'lsa bo\'sh qoldiringProfilProfilni o\'zgartirish
- Berilgan nom
- Familiya
+ Haqiqiy nomi
+ Oʻz kulgichingizni belgilang
+ KulgichBiografiyaRahmat!Ijtimoiy media linklari
@@ -543,9 +550,7 @@
SababNima gap?Firibgarlik
- HaqoratYo\'q joydan janjal chiqarish
- Reyting nayrangliklariBoshqaO\'yin(lar)ga murojaatni bering va ushbu o\'yinchini tutishini nimasi yaxshi emas izohlang. Faqatgina \"u aldayabdi\" deb qo\'ya qolmasdan, balkim nima uchun bunday xulosaga kelganingizni ingliz tilida tushuntirsangiz uni ko\'rib chiqishimiz tezlashadi.Iltimos kamida bitta o\'yinga murojatni keltiring.
diff --git a/translation/dest/site/vi-VN.xml b/translation/dest/site/vi-VN.xml
index d74461afe3a23..43046700c5cca 100644
--- a/translation/dest/site/vi-VN.xml
+++ b/translation/dest/site/vi-VN.xml
@@ -31,7 +31,7 @@
Vua ở trung tâmBa lần chiếuCuộc đua kết thúc
- Hết cờ theo luật
+ Hết cờ theo luật biến thểĐối thủ mớiĐối thủ muốn chơi một ván cờ mới với bạnTham gia ván cờ
@@ -53,7 +53,7 @@
Bên đen không đi quânYêu cầu máy tính phân tíchMáy tính phân tích
- Máy tính phân tích có sẵn
+ Có sẵn máy tính phân tíchPhân tích máy tính bị vô hiệu hóaBàn cờ phân tíchĐộ sâu %s
@@ -65,17 +65,17 @@
Phân tích sâu hơnHiện các mối đe dọatrong trình duyệt cục bộ
- Kích hoạt đánh giá địa phương
- Thay đổi biến
- Biến chính
+ Bật/Tắt đánh giá cục bộ
+ Về biến chính
+ Trở thành biến chínhXoá từ đây
- Thu gọn các biến
- Mở rộng các biến
+ Thu gọn các biến
+ Mở rộng các biếnĐổi biếnSao chép biến PGNNước cờNước đi dẫn đến hết cờ
- Nước chiếu hết theo luật
+ Thắng theo luật biến thểThiếu quân để chiếu hếtTiến tốtĂn quân
@@ -176,7 +176,7 @@
Hôm quaSố phút cho mỗi bênBiến thể
- Biến chơi
+ Biến thểKiểu thời gianThời gian thựcCờ qua thư
@@ -193,7 +193,7 @@
Thời gianHệ số
- Thống kê hệ số
+ Các thống kê hệ sốTên đăng nhậpTên đăng nhập hoặc emailThay đổi tên đăng nhập
@@ -435,9 +435,6 @@ trò chuyện trong ván đấu và có một URL có thể chia sẻ công khai
Hãy chọn tên chuẩn mực cho giải đấu.Một hành động dù chỉ một chút không thích hợp, tài khoản của bạn có thể bị khoá.Hãy để trống để lấy tên theo tên một kỳ thủ cờ vua nổi tiếng.
- Chúng tôi khuyên bạn không nên thay đổi.
- Nếu bạn thiết lập điều kiện tham gia, giải của bạn sẽ có ít người chơi hơn.
- Hiện các thiết lập nâng caoĐặt giải đấu ở chế độ riêng tư và giới hạn tham gia bởi mật khẩuTham giaRút lui
@@ -447,7 +444,7 @@ trò chuyện trong ván đấu và có một URL có thể chia sẻ công khai
Tạo bởiGiải đấu đang diễn raĐã đóng việc sắp xếp cặp đấu.
- Cặp đấu đang được xếp, %s hãy sẵn sàng!
+ %s chờ nhé, đang xếp cặp đấu, chuẩn bị sẵn sàng!Tạm rútTiếp tụcBạn đã vào ván!
@@ -477,8 +474,7 @@ trò chuyện trong ván đấu và có một URL có thể chia sẻ công khai
Nếu không có, hãy để trốngHồ sơChỉnh sửa thông tin cá nhân
- Tên
- Họ
+ Tên thậtĐặt biểu tượng của bạnBiểu tượngCó một cài đặt để ẩn tất cả biểu tượng của người dùng trên toàn bộ trang web.
@@ -524,9 +520,7 @@ trò chuyện trong ván đấu và có một URL có thể chia sẻ công khai
Lý doCó chuyện gì vậy?Gian lận
- Xúc phạmChọc tức, chơi khăm
- Thao túng xếp hạngKhácDán đường dẫn đến (các) ván cờ và giải thích về vấn đề của kỳ thủ này. Đừng chỉ nói \"họ gian lận\" mà hãy miêu tả chi tiết nhất có thể. Vấn đề sẽ được giải quyết nhanh hơn nếu bạn viết bằng tiếng Anh.Hãy cung cấp ít nhất một đường dẫn đến ván cờ bị gian lận.
@@ -561,6 +555,7 @@ trò chuyện trong ván đấu và có một URL có thể chia sẻ công khai
ChậmBên trong bàn cờBên ngoài bàn cờ
+ Tất cả ô vuông của bàn cờChỉ khi chơi cờ chậmLuôn luônKhông bao giờ
diff --git a/translation/dest/site/zh-CN.xml b/translation/dest/site/zh-CN.xml
index e899a5ac84c21..4bb20eed8e11c 100644
--- a/translation/dest/site/zh-CN.xml
+++ b/translation/dest/site/zh-CN.xml
@@ -69,8 +69,8 @@
提升变着做为主线从此处开始删除
- 折叠变着
- 展开变着
+ 折叠变着
+ 展开变着强制作为变着复制变着的PGN着法
@@ -434,9 +434,6 @@
为锦标赛提出一个无争议的名称。即使只有一点点违规的内容都可能导致你的账户被封禁。若留空,将会随机选择一位著名的大师的名字作为锦标赛名称。
- 我们建议你不更改这些设置。
- 如果你设置参赛条件,锦标赛的玩家将会更少。
- 显示高级设置设置比赛私有,并用密码限制访问参与锦标赛退出锦标赛
@@ -476,8 +473,7 @@
如果没有,请留空个人资料编辑个人资料
- 名
- 姓
+ 真名设置你的图标头像有一个设置可以隐藏整个站点上的所有用户图标。
@@ -523,9 +519,7 @@
原因举报原因?作弊
- 侮辱捣乱
- 操纵等级分其他请附上棋局链接解释该用户的行为问题。例如如果你怀疑某用户作弊,请不要只说 “对手作弊”。请解释为什么你认为对手作弊。如果你用英语举报,我们将会更快作出答复。请提供至少一局作弊的棋局的链接。
diff --git a/translation/dest/site/zh-TW.xml b/translation/dest/site/zh-TW.xml
index 00c20a428bac9..80477679c7840 100644
--- a/translation/dest/site/zh-TW.xml
+++ b/translation/dest/site/zh-TW.xml
@@ -428,9 +428,6 @@
幫錦標賽挑選一個適合的名字即便只是一點點的違規都有可能導致您的帳號被封鎖。若不填入錦標賽的名稱,將會用一位著名的棋手名字來做為錦標賽名稱。
- 我們建議您不要調整這些數據
- 如果你設定入場限制,你的錦標賽選手會比較少。
- 顯示進階設定把錦標賽設定為私人,並設定密碼來限制進入。加入離開
@@ -470,8 +467,6 @@
如果沒有,請留空資料編輯資料
- 名
- 姓設置你的圖標圖標有一個設置可以隱藏整個網站上所有用户圖標。
@@ -516,9 +511,7 @@
原因举报原因?作弊
- 侮辱钓鱼
- 操縱積分其他附上游戏的网址解释该用户的行为问题請提供至少一局作弊棋局的連結。
diff --git a/translation/dest/streamer/fa-IR.xml b/translation/dest/streamer/fa-IR.xml
index f23040f050ec2..22e1f28a71152 100644
--- a/translation/dest/streamer/fa-IR.xml
+++ b/translation/dest/streamer/fa-IR.xml
@@ -21,7 +21,7 @@
%s ما را بخوانید تا در مدت استریم شما از بازی جوانمردانه برای همه اطمینان حاصل شود.پرسشها و پاسخهای متداول درباره استریم نمودن به صورت منصفانهمزایای جریان با کلمه کلیدی
- یک نقشک بَرخَط-محتواساز شعلهور در نمایه Lichessتان دریافت کنید.
+ یک نقشک بَرخَط-محتواساز شعلهور در رُخنمای Lichessتان دریافت کنید.در بالای لیست پخش کننده ها پرش کنید.به فالوور های خود در لیچس اطلاع دهیدجریان خود را در بازی ها مسابقات و مطالعات خود نشان دهید
diff --git a/translation/dest/streamer/fi-FI.xml b/translation/dest/streamer/fi-FI.xml
index 455d4c34902f2..84b1a47ad806a 100644
--- a/translation/dest/streamer/fi-FI.xml
+++ b/translation/dest/streamer/fi-FI.xml
@@ -2,9 +2,9 @@
Lichess-striimaajatLichess-striimaaja
- JUURI NYT!
+ MENEILLÄÄN!POISSA
- Parhaillaan striimaavat: %s
+ Striimaa parhaillaan: %sViimeisin striimi %sRyhdy Lichess-striimaajaksiOnko sinulla Twitch- tai YouTube-kanava?
diff --git a/translation/dest/streamer/he-IL.xml b/translation/dest/streamer/he-IL.xml
index ab2c79156782c..36e7759187bfd 100644
--- a/translation/dest/streamer/he-IL.xml
+++ b/translation/dest/streamer/he-IL.xml
@@ -1,12 +1,12 @@
- שדרני ליצ׳ס
- שדרן ליצ׳ס
+ שדרני Lichess
+ שדרן Lichessבשידור חי!מנותקמשדרים כרגע: %sמשדר אחרון %s
- הפכו לשדרני ליצ׳ס
+ הפכו לשדרני Lichessיש לך ערוץ יוטיוב או טוויץ\'?יוצאים לדרך!כל השדרנים
@@ -15,26 +15,26 @@
הורדת ערכת משדר%s משדר/תחוקי שידור
- יש לכלול את מילת המפתח \"lichess.org\" בכותרת המשדר שלכם ולהשתמש בקטגוריית \"Chess\", כשאתם משדרים בליצ׳ס.
- יש להסיר את מילת המפתח כשאתם משדרים תוכן שאינו קשור לליצ׳ס.
- ליצ׳ס יזהה את המשדר שלכם בצורה אוטומטית ויפעיל את ההטבות הבאות:
+ יש לכלול את מילת המפתח \"lichess.org\" בכותרת המשדר שלכם ולהשתמש בקטגוריית \"Chess\", כשאתם משדרים ב־Lichess.
+ יש להסיר את מילת המפתח כשאתם משדרים תוכן שאינו קשור ל־Lichess.
+ Lichess יזהה את המשדר שלכם בצורה אוטומטית ויפעיל את ההטבות הבאות:קראו את %s כדי לאפשר משחק הוגן לכולם בזמן המשדר שלכם.המדריך שלנו לשידור הוגןהטבות שידור עם מילת המפתח
- תקבלו אייקון משדר בוער בפרופיל הליצ׳ס שלכם.
+ תקבלו אייקון משדר בוער בפרופיל ה־Lichessשלכם.תועלו למעלה ברשימת המשדרים.
- העוקבים שלכם בליצ׳ס יקבלו הודעה.
+ העוקבים שלכם ב־Lichessיקבלו הודעה.תוכלו להציג את השידור שלכם במשחקים, טורנירים ובלוחות הלמידה שלכם.המשדר שלכם אושר.המשדר שלכם עובר בדיקת מנהלים.אנא מלאו את פרטי המשדר שלכם והעלו תמונה.
- כאשר אתם מוכנים להיכנס לרשימת שדרני ליצ׳ס, %s
+ כאשר אתם מוכנים להיכנס לרשימת שדרני Lichess, %sבקשו בדיקת מנהלים
- עמוד השדרנים של ליצ׳ס מכוון את הקהל שלך לפי השפה שבימת השידור שלך סיפקה לנו. הגדירו את השפה הנכונה באפליקציה או בשירות המשמשים אתכם לשידור.
+ עמוד השדרנים של Lichess מכוון את הקהל שלך לפי השפה שבימת השידור שלך סיפקה לנו. הגדירו את השפה הנכונה באפליקציה או בשירות המשמשים אתכם לשידור.שם המשתמש או כתובת הTwitch שלכםאופציונאלי. אם אין, השאירו את השדה ריק
- המזהה (ID) של ערוץ ה-YouTube שלך
- השם שלכם כשדרנים בליצ׳ס
+ המזהה (ID) של ערוץ ה־YouTube שלך
+ השם שלכם כשדרנים ב־Lichessעד תו %sעד %s תווים
diff --git a/translation/dest/study/fa-IR.xml b/translation/dest/study/fa-IR.xml
index 6ea7f494e9887..e9b1372cd043f 100644
--- a/translation/dest/study/fa-IR.xml
+++ b/translation/dest/study/fa-IR.xml
@@ -58,7 +58,7 @@
پیشینبعدیآخرین
- اشتراک & صدور
+ همرسانی و برونبُردنمونه سازیPGN درسبارگیری تمام بازی ها
@@ -70,7 +70,7 @@
برای جاسازی این نوشته، این کد را در تالار گفت و گو قرار دهیددر موقعیت آغازین شروع نماییدشروع از %s
- در وبسایت یا وبلاگ خود قرار دهید
+ در وبگاهتان قرار دهیددرباره قرار دادن (در سایت) بیشتر بخوانیدفقط مطالعاتِ عمومی میتوانند جایگذاری شوند!بگشایید
diff --git a/translation/dest/study/he-IL.xml b/translation/dest/study/he-IL.xml
index 345bff3128ebc..f5f3566f3dbd7 100644
--- a/translation/dest/study/he-IL.xml
+++ b/translation/dest/study/he-IL.xml
@@ -69,7 +69,7 @@
הPGN של לוח הלמידההורדת כל המשחקיםהPGN של הפרק
- העתקת ה-PGN
+ העתקת ה־PGNהורדת המשחקכתובת לוח הלמידהכתובת האינטרנט של הפרק הנוכחי
diff --git a/translation/dest/study/vi-VN.xml b/translation/dest/study/vi-VN.xml
index 50240b54fbbe5..62dadeefea094 100644
--- a/translation/dest/study/vi-VN.xml
+++ b/translation/dest/study/vi-VN.xml
@@ -133,7 +133,7 @@
Nước đi thiên tàiSai lầm nghiêm trọngNước đi hay
- Nước cần suy tính thêm
+ Nước đi mơ hồNước duy nhấtZugzwangThế trận cân bằng
diff --git a/translation/dest/swiss/fa-IR.xml b/translation/dest/swiss/fa-IR.xml
index 713cdf9f5474a..87df9c4f5efcd 100644
--- a/translation/dest/swiss/fa-IR.xml
+++ b/translation/dest/swiss/fa-IR.xml
@@ -39,6 +39,15 @@
فاصله بین دورهارویاروییهای ممنوعنام کاربری بازیکنانی که نباید با هم بازی کنند (مثلا خواهر و برادرها). دو نام کاربری در هر خط، با فاصله از هم جدا شوند.
+ رویارویی دستی در دور پسین
+ همه رویاروییهای دور پسین را دستی مشخص کنید. یک جفت بازیکن در هر خط. نمونه:
+بازیکنآ بازیکنب
+بازیکنپ بازیکنت
+برای استراحت دادن (یک امتیاز) به یک بازیکن به جای رویارویی، یک خط مانند این بیفزایید:
+بازیکنث ۱
+بازیکنان نبوده، غایب در نظر گرفته میشوند و صفر امتیاز میگیرند.
+اگر این خانه را خالی گذارید، Lichess خودکار رویاروییها را میچیند.
+ باید آخرین بازی سوییسیشان را کرده باشندمسابقات سوئیسی جدیدچه زمانی از مسابقات با ساختار سوئیسی به جای آرنا استفاده کنیم؟در مسابقه با فرم سوئیسی، تمام شرکت کننده ها به تعداد برابر بازی انجام می دهند و هر دو بازیکن فقط یک بار با یکدیگر بازی می کنند.
diff --git a/translation/dest/swiss/he-IL.xml b/translation/dest/swiss/he-IL.xml
index 081f92e91e867..ea008dce94db9 100644
--- a/translation/dest/swiss/he-IL.xml
+++ b/translation/dest/swiss/he-IL.xml
@@ -89,7 +89,7 @@ PlayerE 1
מה קורה אם שחקן לא משחק?השעון שלו יתקתק, ״יפול לו הדגל״ והוא יפסיד את המשחק. לאחר מכן הוא יוצא מהטורניר כדי לא להפסיד משחקנים נוספים. הוא יוכל להצטרף מחדש בכל שלב.מה נעשה באשר לשחקים שלא מופיעים למשחק?
- שחקנים שנרשמים לטורנירים שוויצריים אבל לא משחקים כנדרש יכולים להוות בעיה. כדי למנוע את זה, ליצ׳ס מונע משחקים שלא מופיעים להצטרף לטורנירים שוויצריים למשך זמן מסויים. היוצר של הטורניר יכול לבחור לאשר את הצטרפותם בכל זאת.
+ שחקנים שנרשמים לטורנירים שוויצריים אבל לא משחקים כנדרש יכולים להוות בעיה. כדי למנוע את זה, Lichess מונע משחקים שלא מופיעים להצטרף לטורנירים שוויצריים למשך זמן מסויים. היוצר של הטורניר יכול לבחור לאשר את הצטרפותם בכל זאת.האם ניתן להצטרף באיחור?כן, עד אשר שוחקו יותר ממחצית הסבבים. לדוגמה, בטורניר של 11 סבבים ניתן להצטרף לפני שסיבוב 6 מתחיל ואם יש 12 סבבים ניתן להצטרף לפני שסיבוב 7 מתחיל. מצטרפים באיחור מקבלים חצי נקודה בלבד, אף אם החמיצו מספר סבבים.האם טורנירים שוויצריים יחליפו את טורנירי הזירה?
diff --git a/translation/dest/swiss/vi-VN.xml b/translation/dest/swiss/vi-VN.xml
index 1db024a122804..6719e4bdf2d5a 100644
--- a/translation/dest/swiss/vi-VN.xml
+++ b/translation/dest/swiss/vi-VN.xml
@@ -24,7 +24,7 @@
Bắt đầu trongVòng đấu tiếp theo
- Ván cờ hiện đang chơi
+ Ván đấu đang diễn raThời gian bắt đầu giải đấuSố vòng đấu
@@ -117,7 +117,7 @@ Thứ gần nhất bạn có thể có với một giải đấu vòng tròn là
Chỉ cho phép những người dùng được chỉ định trước tham giaNgoại trừ những người trong danh sách này, những người khác đều bị cấm tham gia. Mỗi dòng một tên người dùng.Chơi các ván đấu của bạn
- Miễn
+ Được miễnVắng mặtĐiểm số phụ
diff --git a/translation/dest/team/fa-IR.xml b/translation/dest/team/fa-IR.xml
index faf93c170d6c4..fb5bf2b3f6578 100644
--- a/translation/dest/team/fa-IR.xml
+++ b/translation/dest/team/fa-IR.xml
@@ -55,6 +55,7 @@
درخواستهای رد شدهبرای دسترسی به اخبار و رویداد ها در تیم رسمی %s عضو شویدصفحه تیم ها
+ این مسابقات به پایان رسیدهاست و تیمها دیگر نمیتوانند بهروز شوند.تیمهایی که در این نبرد با یکدیگر رقابت خواهند کرد را لیست کنید.هر تیم در یک خط. از تکمیل خودکار استفاده کنید.میتوانید این لیست را از یک مسابقه به مسابقات دیگر کپی کنید!
diff --git a/translation/dest/tfa/he-IL.xml b/translation/dest/tfa/he-IL.xml
index c7f03260caac6..6772f38fdf9dc 100644
--- a/translation/dest/tfa/he-IL.xml
+++ b/translation/dest/tfa/he-IL.xml
@@ -1,7 +1,7 @@
אימות דו־שלבי
- אימות דו-שלבי מוסיף עוד שכבה של אבטחה לחשבון שלך.
+ אימות דו־שלבי מוסיף עוד שכבה של אבטחה לחשבון שלך.התקינו אפליקציה לאימות דו־שלבי. אנו ממליצים על היישומים הבאים:סרקו את הברקוד עם האפליקציה.הכניסו את הסיסמה ואת קוד האימות שנוצר על ידי האפליקציה כדי להשלים את הרישום. תזדקק/י לקוד אימות בכל התחברות מחדש.
@@ -10,10 +10,10 @@
הערה: אם איבדתם את הגישה לקודים המשמשים אתכם לאימות דו־שלבי, השתמשו ב%s באמצעות אימייל.הפעלת אימות דו־שלביהשבתת אימות דו־שלבי
- אימות דו-שלבי הופעל
+ אימות דו־שלבי הופעליש צורך בסיסמה ובקוד אימות מהאפליקציה שאתם משתמשים בה כדי לבטל אימות דו־שלבי.פתחו את אפליקציית האימות הדו־שלבי שברשותכם להצגת קוד האימות ואמתו את זהותכם.
- אנא הפעל/י אימות דו־שלבי כדי לאבטח את חשבונך ב-https://lichess.org/account/twofactor.
+ אנא הפעל/י אימות דו־שלבי כדי לאבטח את חשבונך ב־https://lichess.org/account/twofactor.
קיבלת את ההודעה הזאת כיוון שיש לך אחריות מיוחדת כמו מוביל/ה של קבוצה, מאמן/ת, מורה או שדרן/ית
diff --git a/translation/dest/timeago/de-DE.xml b/translation/dest/timeago/de-DE.xml
index 3f4be9ab072bd..f0004f2e69bf6 100644
--- a/translation/dest/timeago/de-DE.xml
+++ b/translation/dest/timeago/de-DE.xml
@@ -59,8 +59,8 @@
%s Minuten verbleibend
- %s Stunden verbleiben
- %s Stunden übrig
+ %s Stunde verbleiben
+ %s Stunden verbleibenabgeschlossen
diff --git a/translation/dest/timeago/uz-UZ.xml b/translation/dest/timeago/uz-UZ.xml
index 5f328e6bef923..47b37e4303212 100644
--- a/translation/dest/timeago/uz-UZ.xml
+++ b/translation/dest/timeago/uz-UZ.xml
@@ -54,4 +54,13 @@
%s yil avval%s yil avval
+
+ %s daqiqa qoldi
+ %s daqiqa qoldi
+
+
+ %s soat qoldi
+ %s soat qoldi
+
+ tugallangan
diff --git a/translation/dest/ublog/af-ZA.xml b/translation/dest/ublog/af-ZA.xml
index 25e1ac466b595..1ae52f5f860f1 100644
--- a/translation/dest/ublog/af-ZA.xml
+++ b/translation/dest/ublog/af-ZA.xml
@@ -48,5 +48,5 @@
Plaas slegs veilige en bedagsame inhoud. Moenie iemand anders se inhoud kopieer nie.Enigiets onvanpas kan lei tot die sluiting van jou rekening.Ons eenvoudige wenke vir goeie plasings
- Jy word deur die blog-outeur geblokkeer.
+ Jy word deur die blog-outeur geblokkeer.
diff --git a/translation/dest/ublog/bg-BG.xml b/translation/dest/ublog/bg-BG.xml
index 877cec25adc3b..a92941f0d03a5 100644
--- a/translation/dest/ublog/bg-BG.xml
+++ b/translation/dest/ublog/bg-BG.xml
@@ -43,5 +43,5 @@
Моля, публикувайте само безопасно и уважително съдържание. Не копирайте чуждо съдържание.За всяко неподходящо действие акаунтът ви може да бъде закрит.Нашите прости съвети за писане на страхотни публикации в блогове
- Блокирани сте от автора на блога.
+ Блокирани сте от автора на блога.
diff --git a/translation/dest/ublog/ca-ES.xml b/translation/dest/ublog/ca-ES.xml
index 4606dbe115c5f..bc1cee1dd17b0 100644
--- a/translation/dest/ublog/ca-ES.xml
+++ b/translation/dest/ublog/ca-ES.xml
@@ -52,5 +52,5 @@
Qualsevol contingut inapropiat podria implicar el tancament del teu compte.Els nostres senzills consells per escriure bones entrades al blogDiscuteix aquesta publicació del blog en el fòrum
- Estàs bloquejat per l\'autor del blog.
+ Estàs bloquejat per l\'autor del blog.
diff --git a/translation/dest/ublog/ckb-IR.xml b/translation/dest/ublog/ckb-IR.xml
index e2ab71cf41938..a5f3b4fb45c16 100644
--- a/translation/dest/ublog/ckb-IR.xml
+++ b/translation/dest/ublog/ckb-IR.xml
@@ -44,5 +44,5 @@
هەرشتێکی نەگوونجاو دەشێت ببێتە هۆی داخستنی هەژمارەکەت.پێشنیارە سادەکانی ئێمە بۆ نوسینی پەیامێکی کەسی بەهێزلە مەکۆدا باسی ئەم پۆستەی بلۆگەکە بکەن
- تۆ لەلایەن نووسەری بلۆگەکەوە بلۆک کراویت.
+ تۆ لەلایەن نووسەری بلۆگەکەوە بلۆک کراویت.
diff --git a/translation/dest/ublog/cs-CZ.xml b/translation/dest/ublog/cs-CZ.xml
index da5d6d5865464..3b77935941b1c 100644
--- a/translation/dest/ublog/cs-CZ.xml
+++ b/translation/dest/ublog/cs-CZ.xml
@@ -58,5 +58,5 @@
Cokoliv nevhodného může způsobit smazání vašeho účtu.Naše jednoduché rady, jak psát skvělé příspěvky do bloguDiskutujte o tomto příspěvku blogu ve fóru
- Jste zablokováni autorem blogu.
+ Jste zablokováni autorem blogu.
diff --git a/translation/dest/ublog/da-DK.xml b/translation/dest/ublog/da-DK.xml
index cc4170b52c02e..096c1eb5e64c1 100644
--- a/translation/dest/ublog/da-DK.xml
+++ b/translation/dest/ublog/da-DK.xml
@@ -52,5 +52,5 @@
Alt upassende kan medføre, at din konto lukkes.Vores enkle tips til at skrive gode blogindlægDiskutér dette blogindlæg i forummet
- Du er blokeret af blogforfatteren.
+ Du er blokeret af blogforfatteren.
diff --git a/translation/dest/ublog/de-DE.xml b/translation/dest/ublog/de-DE.xml
index 710a729caccb6..1b8643ea509c0 100644
--- a/translation/dest/ublog/de-DE.xml
+++ b/translation/dest/ublog/de-DE.xml
@@ -52,5 +52,5 @@
Jegliche unangemessenen Inhalte können zur Schließung deines Benutzerkontos führen.Unsere einfachen Tipps, um tolle Blog-Beiträge zu schreibenDiesen Blog-Beitrag im Forum diskutieren
- Du wurdest vom Blog-Author gesperrt.
+ Du wurdest vom Blog-Author gesperrt.
diff --git a/translation/dest/ublog/en-US.xml b/translation/dest/ublog/en-US.xml
index cfec443280d00..092f859872c97 100644
--- a/translation/dest/ublog/en-US.xml
+++ b/translation/dest/ublog/en-US.xml
@@ -52,5 +52,5 @@
Anything inappropriate could get your account closed.Our simple tips to write great blog postsDiscuss this blog post in the forum
- You are blocked by the blog author.
+ You are blocked by the blog author.
diff --git a/translation/dest/ublog/es-ES.xml b/translation/dest/ublog/es-ES.xml
index 9e0226b5aa54e..db2487577c1a0 100644
--- a/translation/dest/ublog/es-ES.xml
+++ b/translation/dest/ublog/es-ES.xml
@@ -52,5 +52,5 @@
Cualquier cosa inapropiada puede causar el cierre de tu cuenta.Nuestros sencillos consejos para escribir buenas entradas en el blogDiscutir esta publicación en el foro
- Estás bloqueado por el autor del blog.
+ Estás bloqueado por el autor del blog.
diff --git a/translation/dest/ublog/eu-ES.xml b/translation/dest/ublog/eu-ES.xml
index f2bd9dac25ad9..8b6ac4dd24c42 100644
--- a/translation/dest/ublog/eu-ES.xml
+++ b/translation/dest/ublog/eu-ES.xml
@@ -52,5 +52,5 @@
Errespetua galduz gero, zure kontua itxiko dugu.Blogeko sarrerak idazteko gure aholkuakEztabaidatu artikulu honi buruz foroan
- Blogaren egileak blokeatu egin zaitu.
+ Blogaren egileak blokeatu egin zaitu.
diff --git a/translation/dest/ublog/fi-FI.xml b/translation/dest/ublog/fi-FI.xml
index 9ec1042d94ec6..c0b2caf28d537 100644
--- a/translation/dest/ublog/fi-FI.xml
+++ b/translation/dest/ublog/fi-FI.xml
@@ -52,5 +52,5 @@
Epäasiallisen sisällön julkaisu voi johtaa käyttäjätunnuksesi sulkemiseen.Yksinkertaiset vinkkimme erinomaisten blogikirjoitusten laatimiseenKeskustele tästä blogikirjoituksesta foorumissa
- Blogin tekijä on estänyt sinut.
+ Blogin tekijä on estänyt sinut.
diff --git a/translation/dest/ublog/fr-FR.xml b/translation/dest/ublog/fr-FR.xml
index b071c660909ad..a8170b0761f77 100644
--- a/translation/dest/ublog/fr-FR.xml
+++ b/translation/dest/ublog/fr-FR.xml
@@ -52,5 +52,5 @@
Toute conduite inappropriée peut aboutir à la fermeture de votre compte.Conseils pratiques pour rédiger de bons messagesDiscuter de cet article de blogue dans le forum
- Vous êtes bloqué par l\'auteur du blogue.
+ Vous êtes bloqué par l\'auteur du blogue.
diff --git a/translation/dest/ublog/gl-ES.xml b/translation/dest/ublog/gl-ES.xml
index 6d24b1956c1ac..c8b80cdcd2de7 100644
--- a/translation/dest/ublog/gl-ES.xml
+++ b/translation/dest/ublog/gl-ES.xml
@@ -52,5 +52,5 @@
Calquera cousa inadecuada pode facer que pechemos a túa conta.Os nosos sinxelos consellos para escribir boas publicaciónsFalar desta publicación no foro
- Estás bloqueado polo autor do blog.
+ Estás bloqueado polo autor do blog.
diff --git a/translation/dest/ublog/gsw-CH.xml b/translation/dest/ublog/gsw-CH.xml
index 018671d2a3a27..c3e2528b1ac2f 100644
--- a/translation/dest/ublog/gsw-CH.xml
+++ b/translation/dest/ublog/gsw-CH.xml
@@ -52,5 +52,5 @@
Irgendwelchi unagmässeni Inhält, chönd zur Schlüssig vu dim Konto fühere.Eusi simple Tips, zum tolli Tagebuech-Biträg poschteDiskutier de Tagebuech-Bitrag im Forum
- De Autor - vu dem Tagebuech - hät dich blockiert.
+ De Autor - vu dem Tagebuech - hät dich blockiert.
diff --git a/translation/dest/ublog/he-IL.xml b/translation/dest/ublog/he-IL.xml
index fbd90e430e0b8..938317aac177a 100644
--- a/translation/dest/ublog/he-IL.xml
+++ b/translation/dest/ublog/he-IL.xml
@@ -53,10 +53,10 @@
מחיקת התמונהמומלץ להשתמש בתמונות מהאתרים הבאים: בחר/י את הנושאים שהפוסט שלך עוסק בהם
- תוכל להשתמש בתמונות שצילמת או יצרת, צילומי מסך מתוך ליצ׳ס... כל מה שלא מוגן בזכויות יוצרים ושייך למישהו אחר.
+ תוכל להשתמש בתמונות שצילמת או יצרת, צילומי מסך מתוך Lichess... כל מה שלא מוגן בזכויות יוצרים ושייך למישהו אחר.נא לפרסם רק תוכן מכבד ובטוח. אין להעתיק תוכן של מישהו אחר.כל דבר לא הולם עלול להוביל לסגירת חשבונך.הטיפים שלנו לכתיבת פוסטים מעוליםשיחה על הבלוג הזה בפורומים
- נחסמת על-ידי כותב הבלוג.
+ נחסמת על־ידי כותב הבלוג.
diff --git a/translation/dest/ublog/it-IT.xml b/translation/dest/ublog/it-IT.xml
index f6f23330fac43..fa38acdc5eff5 100644
--- a/translation/dest/ublog/it-IT.xml
+++ b/translation/dest/ublog/it-IT.xml
@@ -52,5 +52,5 @@
Qualsiasi contenuto inappropriato potrebbe portare alla chiusura del tuo account.I nostri suggerimenti per scrivere ottimi messaggi sul blogDiscuti di questo post del blog nel forum
- Sei stato bloccato dall\'autore del blog.
+ Sei stato bloccato dall\'autore del blog.
diff --git a/translation/dest/ublog/ja-JP.xml b/translation/dest/ublog/ja-JP.xml
index 510091069a880..5c9588cd856e3 100644
--- a/translation/dest/ublog/ja-JP.xml
+++ b/translation/dest/ublog/ja-JP.xml
@@ -49,5 +49,5 @@
不適切な内容の場合、あなたのアカウントを停止することがあります。すばらしいブログを書くための簡単なヒントこのブログ記事についてフォーラムで話す
- ブログの筆者によってブロックされています。
+ ブログの筆者によってブロックされています。
diff --git a/translation/dest/ublog/ko-KR.xml b/translation/dest/ublog/ko-KR.xml
index a8ac1cc1eb4df..b52b1b0765061 100644
--- a/translation/dest/ublog/ko-KR.xml
+++ b/translation/dest/ublog/ko-KR.xml
@@ -49,5 +49,5 @@
부적절한 행위로 인해 계정이 폐쇄될 수 있습니다.멋진 블로그 게시물을 작성하기 위한 간단한 팁포럼에서 이 게시글에 대해 토론하기
- 이 블로그 글의 작성자가 당신을 차단했습니다.
+ 이 블로그 글의 작성자가 당신을 차단했습니다.
diff --git a/translation/dest/ublog/lb-LU.xml b/translation/dest/ublog/lb-LU.xml
index d784b5419225a..78710b95b58d5 100644
--- a/translation/dest/ublog/lb-LU.xml
+++ b/translation/dest/ublog/lb-LU.xml
@@ -52,5 +52,5 @@
Alles, wat net ubruecht ass, kann dozou féieren, datt däi Kont zougemaach gëtt.Eis einfach Tuyaue fir flott Blog-Bäiträg ze schreiwenIwwert dëse Blog-Bäitrag am Forum diskutéieren
- Du goufs vum Auteur vum Blog blockéiert.
+ Du goufs vum Auteur vum Blog blockéiert.
diff --git a/translation/dest/ublog/lt-LT.xml b/translation/dest/ublog/lt-LT.xml
index e5334ae374787..fa520b1295604 100644
--- a/translation/dest/ublog/lt-LT.xml
+++ b/translation/dest/ublog/lt-LT.xml
@@ -56,5 +56,5 @@
Bet koks nepriimtinas turinys privers mus uždaryti jūsų paskyrą.Keli patarimai kaip rašyti puikius tinklaraščio įrašusDiskutuoti apie šį įrašą forume
- Jūs buvote tinklaraščio autoriaus užblokuotas.
+ Jūs buvote tinklaraščio autoriaus užblokuotas.
diff --git a/translation/dest/ublog/nb-NO.xml b/translation/dest/ublog/nb-NO.xml
index 336cda7f20382..dd9ace69ae92b 100644
--- a/translation/dest/ublog/nb-NO.xml
+++ b/translation/dest/ublog/nb-NO.xml
@@ -52,5 +52,5 @@
Upassende innhold kan føre til at brukerkontoen din blir stengt.Våre enkle tips for å skrive gode blogginnleggDiskuter dette blogginnlegget i forumet
- Bloggforfatteren har blokkert deg.
+ Bloggforfatteren har blokkert deg.
diff --git a/translation/dest/ublog/nl-NL.xml b/translation/dest/ublog/nl-NL.xml
index 57389749aa1d0..7eeb892605363 100644
--- a/translation/dest/ublog/nl-NL.xml
+++ b/translation/dest/ublog/nl-NL.xml
@@ -52,5 +52,5 @@
Alles wat ongepast is kan sluiting van je account tot gevolg hebben.Onze simpele tips om geweldige blogberichten te schrijvenBespreek dit blogbericht in het forum
- U bent geblokkeerd door de auteur van de blog.
+ U bent geblokkeerd door de auteur van de blog.
diff --git a/translation/dest/ublog/nn-NO.xml b/translation/dest/ublog/nn-NO.xml
index f459cfc6e255d..99b7511bb9660 100644
--- a/translation/dest/ublog/nn-NO.xml
+++ b/translation/dest/ublog/nn-NO.xml
@@ -52,5 +52,5 @@
Upassande innhald kan føre til at brukarkontoen din blir stengd.Våre enkle tips for å skriva gode blogginnleggDiskuter dette blogginnlegget i forumet
- Bloggforfattaren har blokkert deg.
+ Bloggforfattaren har blokkert deg.
diff --git a/translation/dest/ublog/pl-PL.xml b/translation/dest/ublog/pl-PL.xml
index 8b07f334b43c2..54a0e7055ec86 100644
--- a/translation/dest/ublog/pl-PL.xml
+++ b/translation/dest/ublog/pl-PL.xml
@@ -58,5 +58,5 @@
Każda niestosowna rzecz może spowodować zamknięcie Twojego konta.Nasze proste rady dotyczące pisania dobrych wpisów na bloguOmów ten wpis na forum
- Jesteś zablokowany przez autora bloga.
+ Jesteś zablokowany przez autora bloga.
diff --git a/translation/dest/ublog/pt-BR.xml b/translation/dest/ublog/pt-BR.xml
index 04c8bdd261bf1..62034c442f326 100644
--- a/translation/dest/ublog/pt-BR.xml
+++ b/translation/dest/ublog/pt-BR.xml
@@ -52,5 +52,5 @@
Qualquer coisa inapropriada pode levar ao encerramento da sua conta.Nossas dicas simples para escrever ótimas postagensDiscutir esta postagem no fórum
- Você está bloqueado pelo autor do blog.
+ Você está bloqueado pelo autor do blog.
diff --git a/translation/dest/ublog/pt-PT.xml b/translation/dest/ublog/pt-PT.xml
index 381c4f5f6d338..f098c4b406042 100644
--- a/translation/dest/ublog/pt-PT.xml
+++ b/translation/dest/ublog/pt-PT.xml
@@ -52,5 +52,5 @@
Qualquer coisa inapropriada pode levar ao encerramento da tua conta.As nossas dicas simples para escrever ótimas publicações no blogueDiscutir esta publicação no fórum
- Estás bloqueado pelo autor do blog.
+ Estás bloqueado pelo autor do blog.
diff --git a/translation/dest/ublog/ro-RO.xml b/translation/dest/ublog/ro-RO.xml
index 7010b750e3efd..13696ad07c681 100644
--- a/translation/dest/ublog/ro-RO.xml
+++ b/translation/dest/ublog/ro-RO.xml
@@ -55,5 +55,5 @@
Orice lucru nepotrivit ar putea duce la închiderea contului tău.Sfaturile noastre simple pentru a scrie cele mai bune postări pe blogDiscută această postare pe forum
- Ești blocat de autorul blogului.
+ Ești blocat de autorul blogului.
diff --git a/translation/dest/ublog/ru-RU.xml b/translation/dest/ublog/ru-RU.xml
index d6b48a5fb1a84..48246cb8a2c42 100644
--- a/translation/dest/ublog/ru-RU.xml
+++ b/translation/dest/ublog/ru-RU.xml
@@ -58,5 +58,5 @@
Неуместное содержание может стать причиной закрытия вашего аккаунта.Наши простые советы по написанию отличных записей в блогеОбсудить эту запись в блоге на форуме
- Вы заблокированы автором блога.
+ Вы заблокированы автором блога.
diff --git a/translation/dest/ublog/sk-SK.xml b/translation/dest/ublog/sk-SK.xml
index 073e37e19337e..0623ea4923432 100644
--- a/translation/dest/ublog/sk-SK.xml
+++ b/translation/dest/ublog/sk-SK.xml
@@ -58,5 +58,5 @@
Akýkoľvek nevhodný obsah môže mať za následok zrušenie Vášho účtu.Naše jednoduché tipy ako písať skvelé blogové príspevkyDiskutovať o tomto príspevku na fóre
- Autor blogu Vás zablokoval.
+ Autor blogu Vás zablokoval.
diff --git a/translation/dest/ublog/sl-SI.xml b/translation/dest/ublog/sl-SI.xml
index f18b27a0e9843..f8e79e63395e3 100644
--- a/translation/dest/ublog/sl-SI.xml
+++ b/translation/dest/ublog/sl-SI.xml
@@ -48,5 +48,5 @@
Naložite sliko za svojo objavoRazpravljajte o tej objavi v spletnem dnevniku na forumu
- Avtor bloga vas je blokiral.
+ Avtor bloga vas je blokiral.
diff --git a/translation/dest/ublog/sq-AL.xml b/translation/dest/ublog/sq-AL.xml
index 63a365640b257..93abaaeb3576a 100644
--- a/translation/dest/ublog/sq-AL.xml
+++ b/translation/dest/ublog/sq-AL.xml
@@ -52,5 +52,5 @@
Çfarëdo gjëje e papërshtatshme mund të sjellë mbylljen e llogarisë tuaj.Ndihmëzat tona të thjeshta për shkrim postimesh të goditura bloguDiskutojeni në forum këtë postim blogu
- Jeni bllokuar nga autori i blogut.
+ Jeni bllokuar nga autori i blogut.
diff --git a/translation/dest/ublog/ta-IN.xml b/translation/dest/ublog/ta-IN.xml
index 332be3627f954..32ddefd415fc0 100644
--- a/translation/dest/ublog/ta-IN.xml
+++ b/translation/dest/ublog/ta-IN.xml
@@ -52,5 +52,5 @@
முறையற்ற எதுவும் உங்கள் கணக்கை மூடக்கூடும்.சிறந்த வலைப்பதிவு இடுகைகளை எழுத எங்கள் எளிய குறிப்புகள்இந்த வலைப்பதிவு இடுகையை மன்றத்தில் விவாதிக்கவும்
- வலைப்பதிவாளரால் நீங்கள் தடைசெய்யப் பட்டுள்ளீர்கள்.
+ வலைப்பதிவாளரால் நீங்கள் தடைசெய்யப் பட்டுள்ளீர்கள்.
diff --git a/translation/dest/ublog/th-TH.xml b/translation/dest/ublog/th-TH.xml
index 1beb15eec991d..025f734cb48f3 100644
--- a/translation/dest/ublog/th-TH.xml
+++ b/translation/dest/ublog/th-TH.xml
@@ -24,5 +24,5 @@
เครดิตภาพลบรูปภาพหารือเรื่องบล็อกโพสต์ในฟอรั่ม
- คุณถูกปิดกั้นโดยผู้เขียนบล็อก
+ คุณถูกปิดกั้นโดยผู้เขียนบล็อก
diff --git a/translation/dest/ublog/uk-UA.xml b/translation/dest/ublog/uk-UA.xml
index 965aa04013282..93e8b5ba6ecb4 100644
--- a/translation/dest/ublog/uk-UA.xml
+++ b/translation/dest/ublog/uk-UA.xml
@@ -58,5 +58,5 @@
Невідповідності в дописі можуть спричинити блокування профілю.Наші прості поради для написання хороших дописівОбговорити цей допис блогу на форумі
- Ви заблоковані автором блогу.
+ Ви заблоковані автором блогу.
diff --git a/translation/dest/ublog/vi-VN.xml b/translation/dest/ublog/vi-VN.xml
index d51216fd55b28..cbb4e5aa718fd 100644
--- a/translation/dest/ublog/vi-VN.xml
+++ b/translation/dest/ublog/vi-VN.xml
@@ -49,5 +49,5 @@
Chỉ một hành động không phù hợp, tài khoản của bạn có thể bị đóng.Vài mẹo đơn giản để giúp viết ra một bài blog tuyệt vờiThảo luận về bài blog này trong diễn đàn
- Bạn đã bị chặn bởi tác giả blog.
+ Bạn đã bị chặn bởi tác giả blog.
diff --git a/translation/dest/ublog/zh-CN.xml b/translation/dest/ublog/zh-CN.xml
index 48f0257bd2f42..296cd30990baf 100644
--- a/translation/dest/ublog/zh-CN.xml
+++ b/translation/dest/ublog/zh-CN.xml
@@ -49,5 +49,5 @@
任何违规的内容都可能导致你的账户被封禁。写出好博文的小提示在论坛讨论这篇博客
- 您被博客作者拉黑了
+ 您被博客作者拉黑了
diff --git a/translation/dest/voiceCommands/bg-BG.xml b/translation/dest/voiceCommands/bg-BG.xml
index 3ea04e700dfa8..fc0309cc1ba46 100644
--- a/translation/dest/voiceCommands/bg-BG.xml
+++ b/translation/dest/voiceCommands/bg-BG.xml
@@ -1,2 +1,6 @@
-
+
+ Гласови команди
+ Гледайте видео урока
+ Покажи решението на задачата
+
diff --git a/translation/dest/voiceCommands/he-IL.xml b/translation/dest/voiceCommands/he-IL.xml
index d9c51b6a982b4..629e56917cd01 100644
--- a/translation/dest/voiceCommands/he-IL.xml
+++ b/translation/dest/voiceCommands/he-IL.xml
@@ -5,11 +5,11 @@
השתמשו בכפתור ״%1$s״ כדי להפעיל את הזיהוי הקולי של המהלכים, בכפתור ״%2$s״ כדי לגשת למסך העזרה הזה ובכפתור ״%3$s כדי לשנות את הגדרות הזיהוי הקולי.אנו מציגים מספר חצים כשאנו לא בטוחים. אמרו את הצבע או המספר של החץ כדי לבחור אותו.אם מופיע סימן מסתובב של מכ״ם ליד החץ, המהלך יבוצע כשהעיגול יושלם. במשך הזמן הזה, תוכלו לומר ״%1$s״ כדי לשחק את המהלך באופן מיידי או ״%2$s״ כדי לבטל. תוכלו גם לומר מספר או סימן של חץ אחר. ניתן לבטל את הטיימר או להתאים אותו לצרכיכם בהגדרות.
- הפעילו %s בסביבה רועשת. לחצו באופן מתמשך על כפתור ה-Shift כשאתם משתמשים בזיהוי הקולי במצב זה.
+ הפעילו %s בסביבה רועשת. לחצו באופן מתמשך על כפתור ה־Shift כשאתם משתמשים בזיהוי הקולי במצב זה.השתמשו באלפבית הפונטי כדי לשפר את הזיהוי של טורים בלוח. ה%s מסבירות את הגדרות הזיהוי הקולי באופן מפורט.הפוסט הזה בבלוג
- זוזו ל-e4 או בחרו כלי שנמצא ב-e4
+ זוזו ל־e4 או בחרו כלי שנמצא ב־e4בחרו רץ או הכו אותוהכו את הצריח עם המלכהבצעו הצרחה (לאחד הצדדים)
diff --git a/translation/source/broadcast.xml b/translation/source/broadcast.xml
index daa6188910282..78a963fd0f486 100644
--- a/translation/source/broadcast.xml
+++ b/translation/source/broadcast.xml
@@ -16,7 +16,7 @@
OngoingUpcomingCompleted
- Lichess detects round completion based on the source games. Use this toggle if there is no source.
+ Lichess detects round completion, but can get it wrong. Use this to set it manually.Round nameRound numberTournament name
@@ -29,8 +29,6 @@
Start date in your own timezoneOptional, if you know when the event startsCredit the source
- Broadcast URL
- Current round URLCurrent game URLDownload all roundsReset this round
@@ -45,4 +43,13 @@
Optional: replace player names, ratings and titlesPeriod in secondsOptional, how long to wait between requests. Min 2s, max 60s. Defaults to automatic based on the number of viewers.
+ FIDE federations
+ Top 10 rating
+ FIDE players
+ FIDE player not found
+ FIDE profile
+ Federation
+ Age this year
+ Unrated
+ Recent tournaments
diff --git a/translation/source/contact.xml b/translation/source/contact.xml
index 40c918c238163..58165b14468f5 100644
--- a/translation/source/contact.xml
+++ b/translation/source/contact.xml
@@ -55,9 +55,7 @@
In certain circumstances when playing against a bot account, a rated game may not award points if it is determined that the player is abusing the bot for rating points.Error pageIf you faced an error page, you may report it:
- I want to broadcast a tournamentLearn how to make your own broadcasts on Lichess
- You can also contact the broadcast team about official broadcasts.Appeal for a ban or IP restrictionEngine or cheat markYou may send an appeal to %s.
diff --git a/translation/source/site.xml b/translation/source/site.xml
index d3bfc03e4e9e6..17beb5a640b3a 100644
--- a/translation/source/site.xml
+++ b/translation/source/site.xml
@@ -467,9 +467,6 @@
Pick a very safe name for the tournament.Anything even slightly inappropriate could get your account closed.Leave empty to name the tournament after a notable chess player.
- We recommend not touching these.
- If you set entry requirements, your tournament will have fewer players.
- Show advanced settingsMake the tournament private, and restrict access with a passwordJoinWithdraw
@@ -509,8 +506,7 @@
If none, leave emptyProfileEdit profile
- First name
- Surname
+ Real nameSet your flairFlairThere is a setting to hide all user flairs across the entire site.
@@ -557,9 +553,7 @@
ReasonWhat's the matter?Cheat
- InsultTroll
- Rating manipulationOtherPaste the link to the game(s) and explain what is wrong about this user's behaviour. Don't just say "they cheat", but tell us how you came to this conclusion. Your report will be processed faster if written in English.Please provide at least one link to a cheated game.
@@ -594,6 +588,7 @@
SlowInside the boardOutside the board
+ All squares of the boardOn slow gamesAlwaysNever
@@ -939,8 +934,7 @@
Cancel the tournamentTournament descriptionAnything special you want to tell the participants? Try to keep it short. Markdown links are available: [name](https://url)
- Games are rated
-and impact players ratings
+ Games are rated and impact players ratingsOnly members of teamNo restrictionMinimum rated games
diff --git a/ui/.build/src/build.ts b/ui/.build/src/build.ts
index 75373bf48f4a6..23aeeb81ffb0b 100644
--- a/ui/.build/src/build.ts
+++ b/ui/.build/src/build.ts
@@ -7,7 +7,7 @@ import { sass, stopSass } from './sass';
import { esbuild, stopEsbuild } from './esbuild';
import { copies, stopCopies } from './copies';
import { startMonitor, stopMonitor } from './monitor';
-import { initManifest } from './manifest';
+import { initManifest, writeManifest } from './manifest';
import { clean } from './clean';
import { LichessModule, env, errorMark, colors as c } from './main';
@@ -50,6 +50,7 @@ export async function stop() {
}
export function postBuild() {
+ writeManifest();
for (const mod of env.building) {
mod.post.forEach((args: string[]) => {
env.log(`[${c.grey(mod.name)}] exec - ${c.cyanBold(args.join(' '))}`);
diff --git a/ui/.build/src/clean.ts b/ui/.build/src/clean.ts
index 4a0e54a2bd788..441188b18b0e5 100644
--- a/ui/.build/src/clean.ts
+++ b/ui/.build/src/clean.ts
@@ -9,7 +9,7 @@ const globOpts: fg.Options = {
markDirectories: true,
};
-const globs = [
+const allGlobs = [
'**/node_modules',
'**/css/**/gen',
'ui/.build/dist/css',
@@ -20,7 +20,7 @@ const globs = [
'public/css',
];
-export async function clean() {
+export async function clean(globs: string[] = allGlobs) {
if (!env.clean) return;
for (const glob of globs) {
diff --git a/ui/.build/src/esbuild.ts b/ui/.build/src/esbuild.ts
index b8be7a30a7195..43b74b4c37d26 100644
--- a/ui/.build/src/esbuild.ts
+++ b/ui/.build/src/esbuild.ts
@@ -58,12 +58,11 @@ export async function esbuild(tsc?: Promise): Promise {
const onEndPlugin = {
name: 'onEnd',
setup(build: es.PluginBuild) {
- build.onEnd((result: es.BuildResult) => {
+ build.onEnd(async (result: es.BuildResult) => {
for (const err of result.errors) esbuildMessage(err, true);
for (const warn of result.warnings) esbuildMessage(warn);
+ if (result.errors.length === 0) await jsManifest(result.metafile!);
env.done(result.errors.length, 'esbuild');
- if (result.errors.length) return;
- jsManifest(result.metafile!);
});
},
};
diff --git a/ui/.build/src/manifest.ts b/ui/.build/src/manifest.ts
index 074fa5dcd289d..169edc8524df9 100644
--- a/ui/.build/src/manifest.ts
+++ b/ui/.build/src/manifest.ts
@@ -9,12 +9,12 @@ import { allSources } from './sass';
type Manifest = { [key: string]: { hash?: string; imports?: string[] } };
-const current: { js: Manifest; css: Manifest } = { js: {}, css: {} };
+const current: { js: Manifest; css: Manifest; dirty: boolean } = { js: {}, css: {}, dirty: false };
let writeTimer: NodeJS.Timeout;
export async function initManifest() {
if (env.building.length === env.modules.size) return;
- // we're building a subset of modules. if possible reuse the previously built full manifest to give us
+ // we're building a subset of modules. reuse the previousl full manifest for
// a shot at changes viewable in the browser, otherwise punt.
if (!fs.existsSync(env.manifestFile)) return;
if (Object.keys(current.js).length && Object.keys(current.css).length) return;
@@ -24,15 +24,21 @@ export async function initManifest() {
current.css = manifest.css;
}
+export async function writeManifest() {
+ if (!current.dirty) return;
+ clearTimeout(writeTimer);
+ writeTimer = setTimeout(write, 500);
+}
+
export async function css() {
const files = await globArray(path.join(env.cssTempDir, '*.css'), { abs: true });
const css: { name: string; hash: string }[] = await Promise.all(files.map(hashMove));
const newCssManifest: Manifest = {};
for (const { name, hash } of css) newCssManifest[name] = { hash };
- if (enumerableEquivalence(newCssManifest, current.css)) return;
+ if (isEquivalent(newCssManifest, current.css)) return;
current.css = shallowSort({ ...current.css, ...newCssManifest });
- clearTimeout(writeTimer);
- writeTimer = setTimeout(write, 500);
+ current.dirty = true;
+ writeManifest();
}
export async function js(meta: es.Metafile) {
@@ -53,10 +59,9 @@ export async function js(meta: es.Metafile) {
}
newJsManifest[out.name].imports = imports;
}
- if (enumerableEquivalence(newJsManifest, current.js) && fs.existsSync(env.manifestFile)) return;
+ if (isEquivalent(newJsManifest, current.js) && fs.existsSync(env.manifestFile)) return;
current.js = shallowSort({ ...current.js, ...newJsManifest });
- clearTimeout(writeTimer);
- writeTimer = setTimeout(write, 500);
+ current.dirty = true;
}
async function write() {
@@ -98,6 +103,7 @@ async function write() {
JSON.stringify(serverManifest, null, env.prod ? undefined : 2),
),
]);
+ current.dirty = false;
env.log(`Manifest hash ${c.green(hash)}`);
}
@@ -142,20 +148,16 @@ function parsePath(path: string) {
return match ? { name: match[1], hash: match[2] } : undefined;
}
-function enumerableEquivalence(a: any, b: any): boolean {
+function isEquivalent(a: any, b: any): boolean {
if (a === b) return true;
if (typeof a !== typeof b) return false;
if (Array.isArray(a))
- return (
- Array.isArray(b) &&
- a.length === b.length &&
- a.every(x => b.find((y: any) => enumerableEquivalence(x, y)))
- );
+ return Array.isArray(b) && a.length === b.length && a.every(x => b.find((y: any) => isEquivalent(x, y)));
if (typeof a !== 'object') return false;
const [aKeys, bKeys] = [Object.keys(a), Object.keys(b)];
if (aKeys.length !== bKeys.length) return false;
for (const key of aKeys) {
- if (!bKeys.includes(key) || !enumerableEquivalence(a[key], b[key])) return false;
+ if (!bKeys.includes(key) || !isEquivalent(a[key], b[key])) return false;
}
return true;
}
diff --git a/ui/.build/src/monitor.ts b/ui/.build/src/monitor.ts
index 85d5e31682764..96b7ca5375cc9 100644
--- a/ui/.build/src/monitor.ts
+++ b/ui/.build/src/monitor.ts
@@ -4,6 +4,7 @@ import * as ps from 'node:process';
import { build, stop } from './build';
import { env } from './main';
import { globArray } from './parse';
+import { clean } from './clean';
import { stopTsc, tsc } from './tsc';
import { stopEsbuild, esbuild } from './esbuild';
@@ -30,7 +31,9 @@ export async function startMonitor(mods: string[]) {
stopEsbuild();
clearTimeout(tscTimeout);
tscTimeout = setTimeout(() => {
- if (!reinitTimeout) esbuild(tsc());
+ if (reinitTimeout) return;
+ clean(['ui/*/tsconfig.tsbuildinfo']);
+ esbuild(tsc());
}, 2000);
};
const packageChange = async () => {
diff --git a/ui/@types/lichess/dialog.d.ts b/ui/@types/lichess/dialog.d.ts
deleted file mode 100644
index 440e5ee879d5b..0000000000000
--- a/ui/@types/lichess/dialog.d.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-// implementation: file://./../../site/src/component/dialog.ts
-
-interface Dialog {
- readonly open: boolean; // is visible?
- readonly view: HTMLElement; // your content div
- readonly returnValue?: 'ok' | 'cancel' | string; // how did we close?
-
- showModal(): Promise