diff --git a/COPYING.md b/COPYING.md index d9e814fa09..a7908a319e 100644 --- a/COPYING.md +++ b/COPYING.md @@ -39,6 +39,7 @@ public/font/lichess.{sfd,woff,woff2} | [Dave Gandy](http://fontawesome.io/), [Gi public/font/lichess.chess.{sfd,woff,woff2} | the [pgn4web](http://pgn4web.casaschi.net/home.html) authors | [GPLv2+](https://www.gnu.org/licenses/gpl-2.0.txt) Noto Sans in public/font | [Google](https://fonts.google.com/specimen/Noto+Sans) | [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) Roboto in public/font | [Christian Robertson](https://fonts.google.com/specimen/Roboto) | [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) +Segment7 in public/font | [Cedders](https://www.fontspace.com/cedders) | [SIL Open Font License](https://www.fontspace.com/help#license-17) public/images/staunton | [James Clarke](https://github.com/clarkerubber/Staunton-Pieces) | [MIT](https://github.com/clarkerubber/Staunton-Pieces/blob/master/LICENSE) public/images/staunton/piece/CubesAndPi | CubesAndPi | AGPLv3+ public/images/trophy | [James Clarke](https://github.com/clarkerubber/Staunton-Pieces/tree/master/Trophies) | [MIT](https://github.com/clarkerubber/Staunton-Pieces/blob/master/LICENSE) diff --git a/app/AppLoader.scala b/app/AppLoader.scala index 47d03c6dd6..ad8c3d7e5c 100644 --- a/app/AppLoader.scala +++ b/app/AppLoader.scala @@ -153,6 +153,7 @@ final class LilaComponents(ctx: ApplicationLoader.Context) extends BuiltInCompon lazy val video: Video = wire[Video] lazy val swiss: Swiss = wire[Swiss] lazy val dgt: DgtCtrl = wire[DgtCtrl] + lazy val storm: Storm = wire[Storm] // eagerly wire up all controllers val router: Router = { diff --git a/app/Env.scala b/app/Env.scala index 0f6a501ec9..c2bbe70682 100644 --- a/app/Env.scala +++ b/app/Env.scala @@ -79,6 +79,7 @@ final class Env( val evalCache: lila.evalCache.Env, val rating: lila.rating.Env, val swiss: lila.swiss.Env, + val storm: lila.storm.Env, val lilaCookie: lila.common.LilaCookie, val net: NetConfig, val controllerComponents: ControllerComponents @@ -261,6 +262,7 @@ final class EnvBoot( lazy val evalCache: lila.evalCache.Env = wire[lila.evalCache.Env] lazy val rating: lila.rating.Env = wire[lila.rating.Env] lazy val swiss: lila.swiss.Env = wire[lila.swiss.Env] + lazy val storm: lila.storm.Env = wire[lila.storm.Env] lazy val api: lila.api.Env = wire[lila.api.Env] lazy val lilaCookie = wire[lila.common.LilaCookie] diff --git a/app/controllers/Storm.scala b/app/controllers/Storm.scala new file mode 100644 index 0000000000..7ce818f7f0 --- /dev/null +++ b/app/controllers/Storm.scala @@ -0,0 +1,59 @@ +package controllers + +import play.api.mvc._ +import views._ + +import lila.api.Context +import lila.app._ + +final class Storm(env: Env)(implicit mat: akka.stream.Materializer) extends LilaController(env) { + + def home = + Open { implicit ctx => + NoBot { + env.storm.selector.apply flatMap { puzzles => + ctx.userId.?? { u => env.storm.highApi.get(u) dmap some } map { high => + NoCache { + Ok( + views.html.storm.home( + env.storm.json(puzzles), + env.storm.json.pref(ctx.pref.copy(coords = lila.pref.Pref.Coords.NONE)), + high + ) + ) + } + } + } + } + } + + def record = + OpenBody { implicit ctx => + NoBot { + implicit val req = ctx.body + env.storm.forms.run + .bindFromRequest() + .fold( + _ => fuccess(none), + data => env.storm.dayApi.addRun(data, ctx.me) + ) map env.storm.json.newHigh map { json => + Ok(json) as JSON + } + } + } + + def dashboard(page: Int) = + Auth { implicit ctx => me => + get("u") + .ifTrue(isGranted(_.Hunter)) + .??(env.user.repo.named) + .map(_ | me) + .flatMap { user => + env.storm.dayApi.history(user.id, page) flatMap { history => + env.storm.highApi.get(user.id) map { high => + Ok(views.html.storm.dashboard(user, history, high)) + } + } + } + } +} diff --git a/app/views/activity.scala b/app/views/activity.scala index 8ca6c1a0f6..64e688bd34 100644 --- a/app/views/activity.scala +++ b/app/views/activity.scala @@ -1,5 +1,7 @@ package views.html +import controllers.routes + import lila.activity.activities._ import lila.activity.model._ import lila.api.Context @@ -7,8 +9,6 @@ import lila.app.templating.Environment._ import lila.app.ui.ScalatagsTemplate._ import lila.user.User -import controllers.routes - object activity { def apply(u: User, as: Iterable[lila.activity.ActivityView])(implicit ctx: Context) = @@ -20,6 +20,7 @@ object activity { a.patron map renderPatron, a.practice map renderPractice, a.puzzles map renderPuzzles, + a.storm map renderStorm, a.games map renderGames, a.posts map renderPosts, a.corresMoves map { case (nb, povs) => @@ -84,6 +85,16 @@ object activity { ) ) + private def renderStorm(s: Storm)(implicit ctx: Context) = + entryTag( + iconTag("~"), + scoreTag(winTag(trans.storm.highscoreX(strong(s.score)))), + div( + trans.storm.playedNbRunsOfPuzzleStorm + .plural(s.runs, s.runs.localize, a(href := routes.Storm.home())("Puzzle Storm")) + ) + ) + private def renderGames(games: Games)(implicit ctx: Context) = games.value.toSeq.sortBy(-_._2.size).map { case (pt, score) => entryTag( @@ -270,6 +281,8 @@ object activity { private val entryTag = div(cls := "entry") private val subTag = div(cls := "sub") + private val scoreTag = tag("score") + private val winTag = tag("win") private def scoreFrag(s: Score)(implicit ctx: Context) = raw { diff --git a/app/views/base/topnav.scala b/app/views/base/topnav.scala index c7b74b70cb..c0951dcd66 100644 --- a/app/views/base/topnav.scala +++ b/app/views/base/topnav.scala @@ -1,11 +1,11 @@ package views.html.base +import controllers.routes + import lila.api.Context import lila.app.templating.Environment._ import lila.app.ui.ScalatagsTemplate._ -import controllers.routes - object topnav { private def linkTitle(url: String, name: Frag)(implicit ctx: Context) = @@ -35,12 +35,19 @@ object topnav { ) ) ), + ctx.noBot option st.section( + linkTitle(routes.Puzzle.home().path, trans.puzzles()), + div(role := "group")( + a(href := routes.Puzzle.home())(trans.puzzles()), + a(href := routes.Puzzle.dashboard(30, "home"))(trans.puzzle.puzzleDashboard()), + a(href := routes.Storm.home())("Puzzle storm") + ) + ), st.section( - linkTitle(routes.Puzzle.home().path, trans.learnMenu()), + linkTitle(routes.Practice.index().path, trans.learnMenu()), div(role := "group")( ctx.noBot option frag( a(href := routes.Learn.index())(trans.chessBasics()), - a(href := routes.Puzzle.home())(trans.puzzles()), a(href := routes.Practice.index())(trans.practice()), a(href := routes.Coordinate.home())(trans.coordinates.coordinates()) ), diff --git a/app/views/plan/features.scala b/app/views/plan/features.scala index e7dcc5b5d5..fba1693fa7 100644 --- a/app/views/plan/features.scala +++ b/app/views/plan/features.scala @@ -74,6 +74,9 @@ object features { tr(unlimited)( a(href := routes.Puzzle.home())("Tactical puzzles from user games") ), + tr(unlimited)( + a(href := routes.Storm.home())("Puzzle Storm") + ), tr(unlimited)( a(href := s"${routes.UserAnalysis.index()}#explorer")("Opening explorer"), " (62 million games!)" @@ -88,7 +91,7 @@ object features { ), tr(unlimited)( a(href := routes.Search.index(1))("Advanced search"), - " through Lichess 1.5 billion games" + " through Lichess 3 billion games" ), tr(unlimited)( a(href := routes.Video.index())("Chess video library") diff --git a/app/views/storm.scala b/app/views/storm.scala new file mode 100644 index 0000000000..7309c2eea9 --- /dev/null +++ b/app/views/storm.scala @@ -0,0 +1,134 @@ +package views.html + +import controllers.routes +import play.api.i18n.Lang +import play.api.libs.json._ + +import lila.api.Context +import lila.app.templating.Environment._ +import lila.app.ui.ScalatagsTemplate._ +import lila.common.paginator.Paginator +import lila.common.String.html.safeJsonValue +import lila.storm.{ StormDay, StormHigh } +import lila.user.User + +object storm { + + def home(data: JsObject, pref: JsObject, high: Option[StormHigh])(implicit ctx: Context) = + views.html.base.layout( + moreCss = frag(cssTag("storm")), + moreJs = frag( + jsModule("storm"), + embedJsUnsafeLoadThen( + s"""LichessStorm.start(${safeJsonValue( + Json.obj( + "data" -> data, + "pref" -> pref, + "i18n" -> i18nJsObject(i18nKeys) + ) + )})""" + ) + ), + title = "Puzzle Storm", + zoomable = true + ) { + main( + div(cls := "storm storm-app"), + high map { h => + frag( + div(cls := "storm-play-scores")( + span("Puzzle storm highscores"), + a(href := routes.Storm.dashboard())("View best runs »") + ), + div(cls := "storm-dashboard__high__periods")( + renderHigh(h) + ) + ) + }, + div(cls := "storm__about__link")( + a(href := routes.Page.loneBookmark("storm"))("About Puzzle Storm") + ) + ) + } + + private def renderHigh(high: StormHigh)(implicit lang: Lang) = + frag( + List( + (high.allTime, "All-time"), + (high.month, "This month"), + (high.week, "This week"), + (high.day, "Today") + ).map { case (value, name) => + div(cls := "storm-dashboard__high__period")( + strong(value), + span(name) + ) + } + ) + + private val numberTag = tag("number") + + def dashboard(user: User, history: Paginator[StormDay], high: StormHigh)(implicit ctx: Context) = + views.html.base.layout( + moreCss = frag(cssTag("storm.dashboard")), + title = s"${user.username} Puzzle Storm" + )( + main(cls := "storm-dashboard page-small")( + div(cls := "storm-dashboard__high box box-pad")( + h1( + userLink(user), + " • Puzzle Storm highscores" + ), + div(cls := "storm-dashboard__high__periods highlight-alltime")( + renderHigh(high) + ) + ), + a(cls := "storm-play-again button", href := routes.Storm.home())(trans.storm.playAgain()), + div(cls := "storm-dashboard__history box")( + table(cls := "slist slist-pad")( + thead( + tr( + th("Best run of day"), + th("Score"), + th("Moves"), + th("Accuracy"), + th("Combo"), + th("Time"), + th("Highest solved"), + th("Runs") + ) + ), + tbody( + history.currentPageResults.map { day => + tr( + td(showDate(day._id.day.toDate)), + td(numberTag(cls := "score")(day.score)), + td(numberTag(day.moves)), + td(numberTag(f"${day.accuracyPercent}%1.1f"), "%"), + td(numberTag(day.combo)), + td(numberTag(day.time), "s"), + td(numberTag(day.highest)), + td(numberTag(day.runs)) + ) + }, + pagerNextTable(history, np => addQueryParameter(routes.Storm.dashboard().url, "page", np)) + ) + ) + ) + ) + ) + + private val i18nKeys = { + import lila.i18n.I18nKeys.{ storm => t } + List( + t.moveToStart, + t.puzzlesSolved, + t.newDailyHighscore, + t.newWeeklyHighscore, + t.newMonthlyHighscore, + t.newAllTimeHighscore, + t.previousHighscoreWasX, + t.playAgain + ).map(_.key) + } +} diff --git a/app/views/user/show/side.scala b/app/views/user/show/side.scala index 2656162545..8f45e97086 100644 --- a/app/views/user/show/side.scala +++ b/app/views/user/show/side.scala @@ -1,12 +1,13 @@ package views.html.user.show +import controllers.routes + import lila.api.Context import lila.app.templating.Environment._ import lila.app.ui.ScalatagsTemplate._ import lila.rating.PerfType import lila.user.User - -import controllers.routes +import play.api.i18n.Lang object side { @@ -55,7 +56,7 @@ object side { ) } ), - !isPuzzle option iconTag("G") + iconTag("G") ) } @@ -77,8 +78,29 @@ object side { showNonEmptyPerf(u.perfs.horde, PerfType.Horde), showNonEmptyPerf(u.perfs.racingKings, PerfType.RacingKings), br, - u.noBot option showPerf(u.perfs.puzzle, PerfType.Puzzle) + u.noBot option showPerf(u.perfs.puzzle, PerfType.Puzzle), + u.noBot option showStorm(u.perfs.storm) ) ) } + + private def showStorm(storm: lila.rating.Perf.Storm)(implicit lang: Lang) = + a( + dataIcon := '~', + cls := List( + "empty" -> !storm.nonEmpty + ), + href := routes.Storm.dashboard(), + span( + h3("Puzzle Storm"), + st.rating( + strong(storm.score), + storm.nonEmpty option frag( + " ", + span(trans.storm.xRuns.plural(storm.runs, storm.runs.localize)) + ) + ) + ), + iconTag("G") + ) } diff --git a/bin/trans-dump.js b/bin/trans-dump.js index 23b5107151..aba729d0a3 100644 --- a/bin/trans-dump.js +++ b/bin/trans-dump.js @@ -2,7 +2,7 @@ const fs = require('fs').promises; const parseString = require('xml2js').parseString; const baseDir = 'translation/source'; -const dbs = 'site arena emails learn activity coordinates study clas contact patron coach broadcast streamer tfa settings preferences team perfStat search tourname faq lag swiss puzzle puzzleTheme challenge'.split(' '); +const dbs = 'site arena emails learn activity coordinates study clas contact patron coach broadcast streamer tfa settings preferences team perfStat search tourname faq lag swiss puzzle puzzleTheme challenge storm'.split(' '); function ucfirst(s) { return s.charAt(0).toUpperCase() + s.slice(1); diff --git a/build.sbt b/build.sbt index 71685e768f..49231805df 100644 --- a/build.sbt +++ b/build.sbt @@ -38,7 +38,7 @@ lazy val modules = Seq( playban, insight, perfStat, slack, quote, challenge, study, studySearch, fishnet, explorer, learn, plan, event, coach, practice, evalCache, irwin, - activity, relay, streamer, bot, clas, swiss + activity, relay, streamer, bot, clas, swiss, storm ) lazy val moduleRefs = modules map projectToRef @@ -60,7 +60,7 @@ lazy val i18n = smallModule("i18n", MessageCompiler( sourceDir = new File("translation/source"), destDir = new File("translation/dest"), - dbs = "site arena emails learn activity coordinates study class contact patron coach broadcast streamer tfa settings preferences team perfStat search tourname faq lag swiss puzzle puzzleTheme challenge".split(' ').toList, + dbs = "site arena emails learn activity coordinates study class contact patron coach broadcast streamer tfa settings preferences team perfStat search tourname faq lag swiss puzzle puzzleTheme challenge storm".split(' ').toList, compileTo = (sourceManaged in Compile).value ) }.taskValue @@ -71,6 +71,11 @@ lazy val puzzle = module("puzzle", reactivemongo.bundle ) +lazy val storm = module("storm", + Seq(common, memo, hub, puzzle, db, user, rating, pref, tree), + reactivemongo.bundle +) + lazy val quote = smallModule("quote", Seq(), Seq(play.json) diff --git a/conf/routes b/conf/routes index b77824ed98..80e39e1ba2 100644 --- a/conf/routes +++ b/conf/routes @@ -99,6 +99,11 @@ POST /training/$id<\w{5}>/vote/:theme controllers.Puzzle.voteTheme(id: String, POST /training/complete/:theme/$id<\w{5}> controllers.Puzzle.complete(theme: String, id: String) POST /training/difficulty/:theme controllers.Puzzle.setDifficulty(theme: String) +# Puzzle Storm +GET /storm controllers.Storm.home +POST /storm controllers.Storm.record +GET /storm/dashboard controllers.Storm.dashboard(page: Int ?= 1) + # User Analysis GET /analysis/help controllers.UserAnalysis.help GET /analysis/*something controllers.UserAnalysis.parseArg(something: String) diff --git a/modules/activity/src/main/Activity.scala b/modules/activity/src/main/Activity.scala index 9a2bf7b96b..f1aa8f4be5 100644 --- a/modules/activity/src/main/Activity.scala +++ b/modules/activity/src/main/Activity.scala @@ -11,6 +11,7 @@ case class Activity( games: Option[Games] = None, posts: Option[Posts] = None, puzzles: Option[Puzzles] = None, + storm: Option[Storm] = None, learn: Option[Learn] = None, practice: Option[Practice] = None, simuls: Option[Simuls] = None, @@ -27,7 +28,20 @@ case class Activity( def interval = new Interval(date, date plusDays 1) def isEmpty = - !stream && List(games, posts, puzzles, learn, practice, simuls, corres, patron, follows, studies, teams) + !stream && List( + games, + posts, + puzzles, + storm, + learn, + practice, + simuls, + corres, + patron, + follows, + studies, + teams + ) .forall(_.isEmpty) } diff --git a/modules/activity/src/main/ActivityReadApi.scala b/modules/activity/src/main/ActivityReadApi.scala index e06f99c929..26ce4804b9 100644 --- a/modules/activity/src/main/ActivityReadApi.scala +++ b/modules/activity/src/main/ActivityReadApi.scala @@ -110,6 +110,7 @@ final class ActivityReadApi( interval = a.interval, games = a.games, puzzles = a.puzzles, + storm = a.storm, practice = practice, posts = postView, simuls = simuls, diff --git a/modules/activity/src/main/ActivityView.scala b/modules/activity/src/main/ActivityView.scala index a62cce8b68..f509c7e3d4 100644 --- a/modules/activity/src/main/ActivityView.scala +++ b/modules/activity/src/main/ActivityView.scala @@ -15,6 +15,7 @@ case class ActivityView( interval: Interval, games: Option[Games] = None, puzzles: Option[Puzzles] = None, + storm: Option[Storm] = None, practice: Option[Map[PracticeStudy, Int]] = None, simuls: Option[List[Simul]] = None, patron: Option[Patron] = None, diff --git a/modules/activity/src/main/ActivityWriteApi.scala b/modules/activity/src/main/ActivityWriteApi.scala index f450f209dc..3663657414 100644 --- a/modules/activity/src/main/ActivityWriteApi.scala +++ b/modules/activity/src/main/ActivityWriteApi.scala @@ -70,6 +70,17 @@ final class ActivityWriteApi( .void } + def storm(userId: User.ID, score: Int): Funit = + getOrCreate(userId) flatMap { a => + coll.update + .one( + $id(a.id), + $set(ActivityFields.storm -> { ~a.storm + score }), + upsert = true + ) + .void + } + def learn(userId: User.ID, stage: String) = update(userId) { a => a.copy(learn = Some(~a.learn + Learn.Stage(stage))).some diff --git a/modules/activity/src/main/BSONHandlers.scala b/modules/activity/src/main/BSONHandlers.scala index 64b5f7821a..937156d263 100644 --- a/modules/activity/src/main/BSONHandlers.scala +++ b/modules/activity/src/main/BSONHandlers.scala @@ -77,6 +77,11 @@ private object BSONHandlers { implicit lazy val puzzlesHandler = isoHandler[Puzzles, Score]((p: Puzzles) => p.score, Puzzles.apply _) + implicit lazy val stormHandler = new lila.db.BSON[Storm] { + def reads(r: lila.db.BSON.Reader) = Storm(r.intD("r"), r.intD("s")) + def writes(w: lila.db.BSON.Writer, s: Storm) = BSONDocument("r" -> s.runs, "s" -> s.score) + } + implicit private lazy val learnHandler = typedMapHandler[Learn.Stage, Int](Iso.string(Learn.Stage.apply, _.value)) .as[Learn](Learn.apply, _.value) @@ -117,6 +122,7 @@ private object BSONHandlers { val games = "g" val posts = "p" val puzzles = "z" + val storm = "m" val learn = "l" val practice = "r" val simuls = "s" @@ -138,6 +144,7 @@ private object BSONHandlers { games = r.getO[Games](games), posts = r.getO[Posts](posts), puzzles = r.getO[Puzzles](puzzles), + storm = r.getO[Storm](storm), learn = r.getO[Learn](learn), practice = r.getO[Practice](practice), simuls = r.getO[Simuls](simuls), diff --git a/modules/activity/src/main/Env.scala b/modules/activity/src/main/Env.scala index ca9a1c7a0b..99d36766cc 100644 --- a/modules/activity/src/main/Env.scala +++ b/modules/activity/src/main/Env.scala @@ -41,7 +41,8 @@ final class Env( "plan", "relation", "startStudy", - "streamStart" + "streamStart", + "stormRun" ) { case lila.game.actorApi.FinishGame(game, _, _) if !game.aborted => write.game(game).unit case lila.forum.actorApi.CreatePost(post) => write.forumPost(post).unit @@ -57,6 +58,7 @@ final class Env( case lila.hub.actorApi.team.CreateTeam(id, _, userId) => write.team(id, userId).unit case lila.hub.actorApi.team.JoinTeam(id, userId) => write.team(id, userId).unit case lila.hub.actorApi.streamer.StreamStart(userId) => write.streamStart(userId).unit + case lila.hub.actorApi.storm.StormRun(userId, score) => write.storm(userId, score).unit case lila.user.User.GDPRErase(user) => write.erase(user).unit } } diff --git a/modules/activity/src/main/activities.scala b/modules/activity/src/main/activities.scala index 6e4bcc5490..bd5707b563 100644 --- a/modules/activity/src/main/activities.scala +++ b/modules/activity/src/main/activities.scala @@ -31,6 +31,11 @@ object activities { } implicit val PuzzlesZero = Zero.instance(Puzzles(ScoreZero.zero)) + case class Storm(runs: Int, score: Int) { + def +(s: Int) = Storm(runs = runs + 1, score = score atLeast s) + } + implicit val StormZero = Zero.instance(Storm(0, 0)) + case class Learn(value: Map[Learn.Stage, Int]) { def +(stage: Learn.Stage) = copy( diff --git a/modules/common/src/main/Day.scala b/modules/common/src/main/Day.scala index 5bba01e48f..77b95c29fe 100644 --- a/modules/common/src/main/Day.scala +++ b/modules/common/src/main/Day.scala @@ -14,6 +14,10 @@ object Day { def today = Day(Days.daysBetween(genesis, DateTime.now.withTimeAtStartOfDay).getDays) + def daysAgo(days: Int) = Day( + Days.daysBetween(genesis, DateTime.now.minusDays(days).withTimeAtStartOfDay).getDays + ) + def recent(nb: Int): List[Day] = (0 until nb).toList.map { delta => Day(Days.daysBetween(genesis, DateTime.now.minusDays(delta).withTimeAtStartOfDay).getDays) diff --git a/modules/common/src/main/mon.scala b/modules/common/src/main/mon.scala index 952fd993ec..b1dd5608fd 100644 --- a/modules/common/src/main/mon.scala +++ b/modules/common/src/main/mon.scala @@ -484,6 +484,17 @@ object mon { ) val crazyGlicko = counter("puzzle.crazyGlicko").withoutTags() } + object storm { + object selector { + val time = timer("storm.selector.time").withoutTags() + val count = histogram("storm.selector.count").withoutTags() + val rating = histogram("storm.selector.rating").withoutTags() + def ratingSlice(index: Int) = histogram("storm.selector.ratingSlice").withTag("index", index) + } + object run { + def score(auth: Boolean) = histogram("storm.run.score").withTag("auth", auth) + } + } object game { def finish(variant: String, speed: String, source: String, mode: String, status: String) = counter("game.finish").withTags( diff --git a/modules/hub/src/main/actorApi.scala b/modules/hub/src/main/actorApi.scala index 523d5706e4..f0947ecc56 100644 --- a/modules/hub/src/main/actorApi.scala +++ b/modules/hub/src/main/actorApi.scala @@ -62,6 +62,10 @@ package msg { case class SystemMsg(userId: String, text: String) } +package storm { + case class StormRun(userId: String, score: Int) +} + package shutup { case class RecordPublicForumMessage(userId: String, text: String) case class RecordTeamForumMessage(userId: String, text: String) diff --git a/modules/i18n/src/main/I18nKeys.scala b/modules/i18n/src/main/I18nKeys.scala index c64af4338f..9dd3db714a 100644 --- a/modules/i18n/src/main/I18nKeys.scala +++ b/modules/i18n/src/main/I18nKeys.scala @@ -1972,4 +1972,18 @@ val `declineNoBot` = new I18nKey("challenge:declineNoBot") val `declineOnlyBot` = new I18nKey("challenge:declineOnlyBot") } +object storm { +val `moveToStart` = new I18nKey("storm:moveToStart") +val `puzzlesSolved` = new I18nKey("storm:puzzlesSolved") +val `newDailyHighscore` = new I18nKey("storm:newDailyHighscore") +val `newWeeklyHighscore` = new I18nKey("storm:newWeeklyHighscore") +val `newMonthlyHighscore` = new I18nKey("storm:newMonthlyHighscore") +val `newAllTimeHighscore` = new I18nKey("storm:newAllTimeHighscore") +val `previousHighscoreWasX` = new I18nKey("storm:previousHighscoreWasX") +val `playAgain` = new I18nKey("storm:playAgain") +val `highscoreX` = new I18nKey("storm:highscoreX") +val `xRuns` = new I18nKey("storm:xRuns") +val `playedNbRunsOfPuzzleStorm` = new I18nKey("storm:playedNbRunsOfPuzzleStorm") +} + } diff --git a/modules/puzzle/src/main/BsonHandlers.scala b/modules/puzzle/src/main/BsonHandlers.scala index 1397455fd3..60e11530a8 100644 --- a/modules/puzzle/src/main/BsonHandlers.scala +++ b/modules/puzzle/src/main/BsonHandlers.scala @@ -2,21 +2,20 @@ package lila.puzzle import chess.format.{ FEN, Uci } import reactivemongo.api.bson._ -import scala.util.Success -import scala.util.Try +import scala.util.{ Success, Try } import lila.db.BSON import lila.db.dsl._ import lila.game.Game import lila.rating.Glicko -private[puzzle] object BsonHandlers { +object BsonHandlers { implicit val PuzzleIdBSONHandler = stringIsoHandler(Puzzle.idIso) import Puzzle.BSONFields._ - implicit val PuzzleBSONReader = new BSONDocumentReader[Puzzle] { + implicit private[puzzle] val PuzzleBSONReader = new BSONDocumentReader[Puzzle] { def readDocument(r: BSONDocument) = for { id <- r.getAsTry[Puzzle.Id](id) gameId <- r.getAsTry[Game.ID](gameId) @@ -39,7 +38,7 @@ private[puzzle] object BsonHandlers { ) } - implicit val RoundIdHandler = tryHandler[PuzzleRound.Id]( + implicit private[puzzle] val RoundIdHandler = tryHandler[PuzzleRound.Id]( { case BSONString(v) => v split PuzzleRound.idSep match { case Array(userId, puzzleId) => Success(PuzzleRound.Id(userId, Puzzle.Id(puzzleId))) @@ -49,7 +48,7 @@ private[puzzle] object BsonHandlers { id => BSONString(id.toString) ) - implicit val RoundThemeHandler = tryHandler[PuzzleRound.Theme]( + implicit private[puzzle] val RoundThemeHandler = tryHandler[PuzzleRound.Theme]( { case BSONString(v) => PuzzleTheme .find(v.tail) @@ -60,7 +59,7 @@ private[puzzle] object BsonHandlers { rt => BSONString(s"${if (rt.vote) "+" else "-"}${rt.theme}") ) - implicit val RoundHandler = new BSON[PuzzleRound] { + implicit private[puzzle] val RoundHandler = new BSON[PuzzleRound] { import PuzzleRound.BSONFields._ def reads(r: BSON.Reader) = PuzzleRound( id = r.get[PuzzleRound.Id](id), @@ -81,7 +80,11 @@ private[puzzle] object BsonHandlers { ) } - implicit val PathIdBSONHandler: BSONHandler[PuzzlePath.Id] = stringIsoHandler(PuzzlePath.pathIdIso) + implicit private[puzzle] val PathIdBSONHandler: BSONHandler[PuzzlePath.Id] = stringIsoHandler( + PuzzlePath.pathIdIso + ) - implicit val ThemeKeyBSONHandler: BSONHandler[PuzzleTheme.Key] = stringIsoHandler(PuzzleTheme.keyIso) + implicit private[puzzle] val ThemeKeyBSONHandler: BSONHandler[PuzzleTheme.Key] = stringIsoHandler( + PuzzleTheme.keyIso + ) } diff --git a/modules/puzzle/src/main/PuzzlePath.scala b/modules/puzzle/src/main/PuzzlePath.scala index c95a46b357..21696373ef 100644 --- a/modules/puzzle/src/main/PuzzlePath.scala +++ b/modules/puzzle/src/main/PuzzlePath.scala @@ -67,6 +67,6 @@ final private class PuzzlePathApi( def select(theme: PuzzleTheme.Key, tier: PuzzleTier, rating: Range) = $doc( "min" $lte f"${theme}_${tier}_${rating.max}%04d", - "max" $gt f"${theme}_${tier}_${rating.min}%04d" + "max" $gte f"${theme}_${tier}_${rating.min}%04d" ) } diff --git a/modules/puzzle/src/main/PuzzleTier.scala b/modules/puzzle/src/main/PuzzleTier.scala index baab268203..37ea1b72ed 100644 --- a/modules/puzzle/src/main/PuzzleTier.scala +++ b/modules/puzzle/src/main/PuzzleTier.scala @@ -1,13 +1,13 @@ package lila.puzzle -sealed abstract private class PuzzleTier(val key: String) { +sealed abstract class PuzzleTier(val key: String) { def stepDown = PuzzleTier stepDown this override def toString = key } -private object PuzzleTier { +object PuzzleTier { case object Top extends PuzzleTier("top") case object Good extends PuzzleTier("good") diff --git a/modules/rating/src/main/Perf.scala b/modules/rating/src/main/Perf.scala index ed09bb66a0..bee3566801 100644 --- a/modules/rating/src/main/Perf.scala +++ b/modules/rating/src/main/Perf.scala @@ -2,7 +2,7 @@ package lila.rating import org.goochjs.glicko2.Rating import org.joda.time.DateTime -import reactivemongo.api.bson.BSONDocument +import reactivemongo.api.bson.{ BSONDocument, Macros } import lila.db.BSON @@ -98,6 +98,14 @@ case object Perf { val recentMaxSize = 12 + case class Storm(score: Int, runs: Int) { + def nonEmpty = runs > 0 + } + + object Storm { + val default = Storm(0, 0) + } + implicit val perfBSONHandler = new BSON[Perf] { import Glicko.glickoBSONHandler @@ -120,4 +128,6 @@ case object Perf { "la" -> o.latest.map(w.date) ) } + + implicit val stormBSONHandler = Macros.handler[Storm] } diff --git a/modules/storm/src/main/Env.scala b/modules/storm/src/main/Env.scala new file mode 100644 index 0000000000..cd281504bf --- /dev/null +++ b/modules/storm/src/main/Env.scala @@ -0,0 +1,31 @@ +package lila.storm + +import com.softwaremill.macwire._ +import play.api.Configuration + +import lila.common.config._ +import lila.user.UserRepo + +@Module +final class Env( + appConfig: Configuration, + db: lila.db.Db, + colls: lila.puzzle.PuzzleColls, + cacheApi: lila.memo.CacheApi, + userRepo: UserRepo +)(implicit + ec: scala.concurrent.ExecutionContext +) { + + private lazy val dayColl = db(CollName("storm_day")) + + lazy val selector = wire[StormSelector] + + lazy val json = wire[StormJson] + + lazy val highApi = wire[StormHighApi] + + lazy val dayApi = wire[StormDayApi] + + val forms = StormForm +} diff --git a/modules/storm/src/main/StormBsonHandlers.scala b/modules/storm/src/main/StormBsonHandlers.scala new file mode 100644 index 0000000000..0bbe28af48 --- /dev/null +++ b/modules/storm/src/main/StormBsonHandlers.scala @@ -0,0 +1,40 @@ +package lila.storm + +import chess.format.{ FEN, Uci } +import reactivemongo.api.bson._ + +import lila.db.dsl._ +import lila.puzzle.Puzzle +import scala.util.Success +import lila.common.Day + +private object StormBsonHandlers { + + import lila.puzzle.BsonHandlers.{ PuzzleIdBSONHandler } + + implicit val StormPuzzleBSONReader = new BSONDocumentReader[StormPuzzle] { + def readDocument(r: BSONDocument) = for { + id <- r.getAsTry[Puzzle.Id]("_id") + fen <- r.getAsTry[FEN]("fen") + lineStr <- r.getAsTry[String]("line") + line <- lineStr.split(' ').toList.flatMap(Uci.Move.apply).toNel.toTry("Empty move list?!") + rating <- r.getAsTry[Int]("rating") + } yield StormPuzzle(id, fen, line, rating) + } + + implicit lazy val stormDayIdHandler = { + import StormDay.Id + val sep = ':' + tryHandler[Id]( + { case BSONString(v) => + v split sep match { + case Array(userId, dayStr) => Success(Id(userId, Day(Integer.parseInt(dayStr)))) + case _ => handlerBadValue(s"Invalid storm day id $v") + } + }, + id => BSONString(s"${id.userId}$sep${id.day.value}") + ) + } + + implicit val stormDayBSONHandler = Macros.handler[StormDay] +} diff --git a/modules/storm/src/main/StormDay.scala b/modules/storm/src/main/StormDay.scala new file mode 100644 index 0000000000..cd7896c060 --- /dev/null +++ b/modules/storm/src/main/StormDay.scala @@ -0,0 +1,99 @@ +package lila.storm + +import org.joda.time.DateTime +import org.joda.time.Days +import scala.concurrent.ExecutionContext + +import lila.common.Bus +import lila.common.config.MaxPerPage +import lila.common.Day +import lila.common.paginator.Paginator +import lila.db.dsl._ +import lila.db.paginator.Adapter +import lila.user.User +import lila.user.UserRepo + +// stores data of the best run of the day +// plus the number of runs +case class StormDay( + _id: StormDay.Id, + score: Int, + moves: Int, + errors: Int, + combo: Int, + time: Int, + highest: Int, + runs: Int +) { + + def add(run: StormForm.RunData) = { + if (run.score > score) + copy( + score = run.score, + moves = run.moves, + errors = run.errors, + combo = run.combo, + time = run.time, + highest = run.highest + ) + else this + }.copy(runs = runs + 1) + + def accuracyPercent: Float = 100 * (moves - errors) / moves.toFloat +} + +object StormDay { + + case class Id(userId: User.ID, day: Day) + object Id { + def today(userId: User.ID) = Id(userId, Day.today) + def lastWeek(userId: User.ID) = Id(userId, Day daysAgo 7) + def lastMonth(userId: User.ID) = Id(userId, Day daysAgo 30) + def allTime(userId: User.ID) = Id(userId, Day(0)) + } + + def empty(id: Id) = StormDay(id, 0, 0, 0, 0, 0, 0, 0) +} + +final class StormDayApi(coll: Coll, highApi: StormHighApi, userRepo: UserRepo)(implicit + ctx: ExecutionContext +) { + + import StormDay._ + import StormBsonHandlers._ + + def addRun(data: StormForm.RunData, user: Option[User]): Fu[Option[StormHigh.NewHigh]] = { + lila.mon.storm.run.score(user.isDefined).record(data.score).unit + user ?? { u => + Bus.publish(lila.hub.actorApi.storm.StormRun(u.id, data.score), "stormRun") + highApi get u.id flatMap { prevHigh => + val todayId = Id today u.id + coll + .one[StormDay]($id(todayId)) + .map { + _.getOrElse(StormDay empty todayId) add data + } + .flatMap { day => + coll.update.one($id(day._id), day, upsert = true) + } + .flatMap { _ => + val (high, newHigh) = highApi.update(u.id, prevHigh, data.score) + userRepo.addStormRun(u.id, high.allTime.some.filter(prevHigh.allTime <)) inject newHigh + } + } + } + } + + def history(userId: User.ID, page: Int): Fu[Paginator[StormDay]] = + Paginator( + adapter = new Adapter[StormDay]( + collection = coll, + selector = $doc("_id" $startsWith s"${userId}:"), + projection = none, + sort = $sort desc "_id" + ), + page, + MaxPerPage(30) + ) + +} diff --git a/modules/storm/src/main/StormForm.scala b/modules/storm/src/main/StormForm.scala new file mode 100644 index 0000000000..a0ccf081ff --- /dev/null +++ b/modules/storm/src/main/StormForm.scala @@ -0,0 +1,36 @@ +package lila.storm + +import play.api.data._ +import play.api.data.Forms._ + +import lila.common.Form.{ numberIn, stringIn } + +object StormForm { + + case class RunData( + puzzles: Int, + score: Int, + moves: Int, + errors: Int, + combo: Int, + time: Int, + highest: Int, + notAnExploit: String + ) + + val run = Form( + mapping( + "puzzles" -> number(min = 1, max = 200), + "score" -> number(min = 1, max = 200), + "moves" -> number(min = 1, max = 900), + "errors" -> number(min = 1, max = 50), + "combo" -> number(min = 1, max = 900), + "time" -> number(min = 1, max = 900), + "highest" -> number(min = lila.rating.Glicko.minRating, max = 4000), + "notAnExploit" -> nonEmptyText.verifying(_ == notAnExploit) + )(RunData.apply)(RunData.unapply) + ) + + val notAnExploit = + "Yes, we know that you can send whatever score you like. That's why there's no leaderboards and no competition." +} diff --git a/modules/storm/src/main/StormHigh.scala b/modules/storm/src/main/StormHigh.scala new file mode 100644 index 0000000000..e06ab28728 --- /dev/null +++ b/modules/storm/src/main/StormHigh.scala @@ -0,0 +1,91 @@ +package lila.storm + +import scala.concurrent.duration._ +import scala.concurrent.ExecutionContext + +import lila.db.dsl._ +import lila.memo.CacheApi +import lila.user.User + +case class StormHigh(day: Int, week: Int, month: Int, allTime: Int) { + + def update(score: Int) = copy( + day = day atLeast score, + week = week atLeast score, + month = month atLeast score, + allTime = allTime atLeast score + ) +} + +object StormHigh { + val default = StormHigh(0, 0, 0, 0) + + sealed abstract class NewHigh(val key: String) { + val previous: Int + } + object NewHigh { + case class Day(previous: Int) extends NewHigh("day") + case class Week(previous: Int) extends NewHigh("week") + case class Month(previous: Int) extends NewHigh("month") + case class AllTime(previous: Int) extends NewHigh("allTime") + } +} + +final class StormHighApi(coll: Coll, cacheApi: CacheApi)(implicit ctx: ExecutionContext) { + + import StormBsonHandlers._ + import StormHigh.NewHigh + + def get(userId: User.ID): Fu[StormHigh] = cache get userId + + def update(userId: User.ID, prev: StormHigh, score: Int): (StormHigh, Option[NewHigh]) = { + val newHigh = prev update score + newHigh -> { + (newHigh != prev) ?? { + cache.put(userId, fuccess(newHigh)) + import NewHigh._ + if (newHigh.allTime > prev.allTime) AllTime(prev.allTime).some + else if (newHigh.month > prev.month) Month(prev.month).some + else if (newHigh.week > prev.week) Week(prev.week).some + else Day(prev.day).some + } + } + } + + private val cache = cacheApi[User.ID, StormHigh](8192, "storm.high") { + _.expireAfterAccess(1 hour).buildAsyncFuture(compute) + } + + private def compute(userId: User.ID): Fu[StormHigh] = + coll + .aggregateOne() { framework => + import framework._ + val todayId = StormDay.Id today userId + val project = Project($doc("_id" -> false, "score" -> true)) + def bestSince(sinceId: StormDay.Id) = List( + Match($doc("_id" $lte todayId $gt sinceId)), + Sort(Descending("score")), + Limit(1), + project + ) + Facet( + List( + "day" -> List(Match($id(todayId)), project), + "week" -> bestSince(StormDay.Id.lastWeek(userId)), + "month" -> bestSince(StormDay.Id.lastMonth(userId)), + "allTime" -> bestSince(StormDay.Id.allTime(userId)) + ) + ) -> Nil + } + .map2 { doc => + def readScore(doc: Bdoc, field: String) = + ~doc.getAsOpt[List[Bdoc]](field).flatMap(_.headOption).flatMap(_.getAsOpt[Int]("score")) + StormHigh( + day = readScore(doc, "day"), + week = readScore(doc, "week"), + month = readScore(doc, "month"), + allTime = readScore(doc, "allTime") + ) + } + .map(_ | StormHigh.default) +} diff --git a/modules/storm/src/main/StormJson.scala b/modules/storm/src/main/StormJson.scala new file mode 100644 index 0000000000..3adca70284 --- /dev/null +++ b/modules/storm/src/main/StormJson.scala @@ -0,0 +1,49 @@ +package lila.storm + +import play.api.libs.json._ + +import lila.common.Json._ + +final class StormJson { + + import StormJson.puzzleWrites + + def apply(puzzles: List[StormPuzzle]): JsObject = Json.obj( + "puzzles" -> puzzles, + "notAnExploit" -> StormForm.notAnExploit + ) + + def pref(p: lila.pref.Pref) = + Json.obj( + "coords" -> p.coords, + "rookCastle" -> p.rookCastle, + "destination" -> p.destination, + "moveEvent" -> p.moveEvent, + "highlight" -> p.highlight, + "is3d" -> p.is3d + ) + + def newHigh(n: Option[StormHigh.NewHigh]) = + Json + .obj() + .add("newHigh" -> n.map { nh => + Json.obj( + "key" -> nh.key, + "prev" -> nh.previous + ) + }) +} + +object StormJson { + + import lila.puzzle.JsonView.puzzleIdWrites + + implicit val puzzleWrites: OWrites[StormPuzzle] = OWrites { p => + Json.obj( + "id" -> p.id, + "fen" -> p.fen.value, + "line" -> p.line.toList.map(_.uci).mkString(" "), + "rating" -> p.rating + ) + } +} diff --git a/modules/storm/src/main/StormPuzzle.scala b/modules/storm/src/main/StormPuzzle.scala new file mode 100644 index 0000000000..aa9736be6c --- /dev/null +++ b/modules/storm/src/main/StormPuzzle.scala @@ -0,0 +1,28 @@ +package lila.storm + +import cats.data.NonEmptyList +import chess.format.{ FEN, Forsyth, Uci } + +import lila.puzzle.Puzzle + +case class StormPuzzle( + id: Puzzle.Id, + fen: FEN, + line: NonEmptyList[Uci.Move], + rating: Int +) { + // ply after "initial move" when we start solving + def initialPly: Int = + fen.fullMove ?? { fm => + fm * 2 - color.fold(1, 2) + } + + lazy val fenAfterInitialMove: FEN = { + for { + sit1 <- Forsyth << fen + sit2 <- sit1.move(line.head).toOption.map(_.situationAfter) + } yield Forsyth >> sit2 + } err s"Can't apply puzzle $id first move" + + def color = fen.color.fold[chess.Color](chess.White)(!_) +} diff --git a/modules/storm/src/main/StormSelector.scala b/modules/storm/src/main/StormSelector.scala new file mode 100644 index 0000000000..b9756cfc47 --- /dev/null +++ b/modules/storm/src/main/StormSelector.scala @@ -0,0 +1,141 @@ +package lila.storm + +import reactivemongo.api.bson.BSONNull +import scala.concurrent.duration._ +import scala.concurrent.ExecutionContext + +import lila.db.AsyncColl +import lila.db.dsl._ +import lila.memo.CacheApi +import lila.puzzle.PuzzleColls + +/* The difficulty of storm should remain constant! + * Be very careful when adjusting the selector. + * Use the grafana average rating per slice chart. + */ +final class StormSelector(colls: PuzzleColls, cacheApi: CacheApi)(implicit ec: ExecutionContext) { + + import StormBsonHandlers._ + + def apply: Fu[List[StormPuzzle]] = current.get {} + + private val theme = lila.puzzle.PuzzleTheme.mix.key.value + private val tier = lila.puzzle.PuzzleTier.Good.key + private val maxDeviation = 90 + + private val ratingBuckets = + List( + 1000 -> 7, + 1150 -> 7, + 1300 -> 8, + 1450 -> 9, + 1600 -> 10, + 1750 -> 11, + 1900 -> 13, + 2050 -> 15, + 2200 -> 17, + 2350 -> 19, + 2500 -> 21, + 2650 -> 23 + ) + private val poolSize = ratingBuckets.foldLeft(0) { case (acc, (_, nb)) => + acc + nb + } + + private val current = cacheApi.unit[List[StormPuzzle]] { + _.refreshAfterWrite(6 seconds) + .buildAsyncFuture { _ => + colls + .path { + _.aggregateList(poolSize) { framework => + import framework._ + val fenColorRegex = $doc( + "$regexMatch" -> $doc( + "input" -> "$fen", + "regex" -> { if (scala.util.Random.nextBoolean()) " w " else " b " } + ) + ) + Facet( + ratingBuckets.map { case (rating, nbPuzzles) => + rating.toString -> List( + Match( + $doc( + "min" $lte f"${theme}_${tier}_${rating}%04d", + "max" $gte f"${theme}_${tier}_${rating}%04d" + ) + ), + Sample(1), + Project($doc("_id" -> false, "ids" -> true)), + UnwindField("ids"), + // ensure we have enough after filtering deviation & color + Sample(nbPuzzles * 7), + PipelineOperator( + $doc( + "$lookup" -> $doc( + "from" -> colls.puzzle.name.value, + "as" -> "puzzle", + "let" -> $doc("id" -> "$ids"), + "pipeline" -> $arr( + $doc( + "$match" -> $doc( + "$expr" -> $doc( + "$and" -> $arr( + $doc("$eq" -> $arr("$_id", "$$id")), + $doc("$lte" -> $arr("$glicko.d", maxDeviation)), + fenColorRegex + ) + ) + ) + ), + $doc( + "$project" -> $doc( + "fen" -> true, + "line" -> true, + "rating" -> $doc("$toInt" -> "$glicko.r") + ) + ) + ) + ) + ) + ), + UnwindField("puzzle"), + Sample(nbPuzzles), + ReplaceRootField("puzzle") + ) + } + ) -> List( + Project($doc("all" -> $doc("$setUnion" -> ratingBuckets.map(r => s"$$${r._1}")))), + UnwindField("all"), + ReplaceRootField("all"), + Sort(Ascending("rating")) + ) + }.map { + _.flatMap(StormPuzzleBSONReader.readOpt) + } + } + .mon(_.storm.selector.time) + .addEffect { puzzles => + monitor(puzzles.toVector, poolSize) + } + } + } + + private def monitor(puzzles: Vector[StormPuzzle], poolSize: Int): Unit = { + val nb = puzzles.size + lila.mon.storm.selector.count.record(nb) + if (nb < poolSize * 0.9) + logger.warn(s"Selector wanted $poolSize puzzles, only got $nb") + if (nb > 1) { + val rest = puzzles.toVector drop 1 + lila.common.Maths.mean(rest.map(_.rating)) foreach { r => + lila.mon.storm.selector.rating.record(r.toInt).unit + } + (0 to poolSize by 10) foreach { i => + val slice = rest drop i take 10 + lila.common.Maths.mean(slice.map(_.rating)) foreach { r => + lila.mon.storm.selector.ratingSlice(i).record(r.toInt) + } + } + } + } +} diff --git a/modules/storm/src/main/package.scala b/modules/storm/src/main/package.scala new file mode 100644 index 0000000000..d628c104b3 --- /dev/null +++ b/modules/storm/src/main/package.scala @@ -0,0 +1,8 @@ +package lila + +import lila.user.User + +package object storm extends PackageObject { + + private[storm] val logger = lila.log("swiss") +} diff --git a/modules/user/src/main/Perfs.scala b/modules/user/src/main/Perfs.scala index efb3c93b30..d5fa3ced48 100644 --- a/modules/user/src/main/Perfs.scala +++ b/modules/user/src/main/Perfs.scala @@ -23,7 +23,8 @@ case class Perfs( rapid: Perf, classical: Perf, correspondence: Perf, - puzzle: Perf + puzzle: Perf, + storm: Perf.Storm ) { def perfs = @@ -187,7 +188,7 @@ case object Perfs { val default = { val p = Perf.default - Perfs(p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p) + Perfs(p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, Perf.Storm.default) } val defaultManaged = { @@ -250,7 +251,8 @@ case object Perfs { rapid = perf("rapid"), classical = perf("classical"), correspondence = perf("correspondence"), - puzzle = perf("puzzle") + puzzle = perf("puzzle"), + storm = r.getO[Perf.Storm]("storm") getOrElse Perf.Storm.default ) } @@ -273,7 +275,8 @@ case object Perfs { "rapid" -> notNew(o.rapid), "classical" -> notNew(o.classical), "correspondence" -> notNew(o.correspondence), - "puzzle" -> notNew(o.puzzle) + "puzzle" -> notNew(o.puzzle), + "storm" -> (o.storm.nonEmpty option o.storm) ) } diff --git a/modules/user/src/main/UserRepo.scala b/modules/user/src/main/UserRepo.scala index 8a0035a2dc..6302b98827 100644 --- a/modules/user/src/main/UserRepo.scala +++ b/modules/user/src/main/UserRepo.scala @@ -205,6 +205,17 @@ final class UserRepo(val coll: Coll)(implicit ec: scala.concurrent.ExecutionCont ) .void + private val incStormRuns = $inc("perfs.storm.runs" -> 1) + def addStormRun(userId: User.ID, newHighScore: Option[Int]): Funit = + coll.update + .one( + $id(userId), + newHighScore.fold(incStormRuns) { score => + incStormRuns ++ $set("perfs.storm.score" -> score) + } + ) + .void + def setProfile(id: ID, profile: Profile): Funit = coll.update .one( diff --git a/package.json b/package.json index c783dbcb26..f1e40337b6 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "ui/tree", "ui/msg", "ui/dgt", + "ui/storm", "ui/@build/rollupProject", "ui/@types/lichess", "ui/@types/cash" diff --git a/public/font/Segment7.sfd b/public/font/Segment7.sfd new file mode 100644 index 0000000000..04a1238fde --- /dev/null +++ b/public/font/Segment7.sfd @@ -0,0 +1,5563 @@ +SplineFontDB: 3.2 +FontName: Segment7Standard +FullName: Segment7 +FamilyName: Segment7 +Weight: Standard +Copyright: Strictly seven-segment (plus point) calculator display face, fixed-width and free. (c) Cedric Knight 2014. Licensed under SIL Open Font Licence v1.1. Reserved name: Segment7. +Version: +ItalicAngle: -3 +UnderlinePosition: 0 +UnderlineWidth: 0 +Ascent: 800 +Descent: 200 +InvalidEm: 0 +sfntRevision: 0x00010000 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 529 -1452314064 6938706] +BaseHoriz: 0 +StyleMap: 0x0001 +FSType: 8 +OS2Version: 3 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 0 +CreationTime: 1401560787 +ModificationTime: 1611684494 +PfmFamily: 17 +TTFWeight: 600 +TTFWidth: 5 +LineGap: 90 +VLineGap: 0 +Panose: 2 0 5 9 0 0 0 0 0 0 +OS2TypoAscent: 800 +OS2TypoAOffset: 0 +OS2TypoDescent: -200 +OS2TypoDOffset: 0 +OS2TypoLinegap: 90 +OS2WinAscent: 800 +OS2WinAOffset: 0 +OS2WinDescent: 200 +OS2WinDOffset: 0 +HheadAscent: 800 +HheadAOffset: 0 +HheadDescent: -200 +HheadDOffset: 0 +OS2SubXSize: 650 +OS2SubYSize: 699 +OS2SubXOff: 7 +OS2SubYOff: 140 +OS2SupXSize: 650 +OS2SupYSize: 699 +OS2SupXOff: -25 +OS2SupYOff: 479 +OS2StrikeYSize: 49 +OS2StrikeYPos: 258 +OS2CapHeight: 450 +OS2XHeight: 450 +OS2Vendor: 'PfEd' +OS2CodePages: 00000001.00000000 +OS2UnicodeRanges: 00000003.00000000.00000000.00000000 +Lookup: 1 8 0 "Single Substitution lookup 0" { "Single Substitution lookup 0 subtable" } [] +Lookup: 257 0 0 "Single Positioning lookup 0" { "Single Positioning lookup 0 subtable" } [] +Lookup: 258 0 0 "'kern' Horizontal Kerning lookup 1" { "'kern' Horizontal Kerning lookup 1 subtable" } ['kern' ('DFLT' <'dflt' > ) ] +MarkAttachClasses: 3 +"MarkClass-1" 49 zero one two three four five six seven eight nine +"MarkClass-2" 64 question A E N X a b c d e f g h i j k l m n o p q r t u v w x y +DEI: 91125 +LangName: 1033 "" "" "" "FontForge 2.0 : Segment7 : 7-6-2014" +Encoding: UnicodeBmp +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -48 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 0 78 30 +BeginPrivate: 7 +BlueValues 23 [-2 36 717 762 779 780] +BlueScale 5 0.022 +BlueShift 1 0 +StdHW 4 [95] +StdVW 5 [977] +StemSnapH 25 [20 21 91 94 95 100 1000] +StemSnapV 20 [95 103 107 124 977] +EndPrivate +BeginChars: 65537 257 + +StartChar: .notdef +Encoding: 65536 -1 0 +Width: 585 +Flags: MW +HStem: 0 50<100 485 100 535> 483 50<100 485 100 100> +VStem: 50 50<50 50 50 483> 485 50<50 483 483 483> +LayerCount: 2 +Fore +SplineSet +50 0 m 1 + 50 533 l 1 + 535 533 l 1 + 535 0 l 1 + 50 0 l 1 +100 50 m 1 + 485 50 l 1 + 485 483 l 1 + 100 483 l 1 + 100 50 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: uni0000 +Encoding: 0 -1 1 +AltUni2: 000000.ffffffff.0 +Width: 585 +Flags: MW +HStem: -200 1000<0 977 0 977> +VStem: 0 977<-200 800 -200 800> +LayerCount: 2 +Fore +SplineSet +0 -200 m 1 + 0 800 l 1 + 977 800 l 1 + 977 -200 l 1 + 0 -200 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: uni0001 +Encoding: 1 1 2 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0002 +Encoding: 2 2 3 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0003 +Encoding: 3 3 4 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0004 +Encoding: 4 4 5 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0005 +Encoding: 5 5 6 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0006 +Encoding: 6 6 7 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0007 +Encoding: 7 7 8 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0008 +Encoding: 8 8 9 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0009 +Encoding: 9 9 10 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni000A +Encoding: 10 10 11 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni000B +Encoding: 11 11 12 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni000C +Encoding: 12 12 13 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni000D +Encoding: 13 13 14 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni000E +Encoding: 14 14 15 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni000F +Encoding: 15 15 16 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0010 +Encoding: 16 16 17 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0011 +Encoding: 17 17 18 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0012 +Encoding: 18 18 19 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0013 +Encoding: 19 19 20 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0014 +Encoding: 20 20 21 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0015 +Encoding: 21 21 22 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0016 +Encoding: 22 22 23 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0017 +Encoding: 23 23 24 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0018 +Encoding: 24 24 25 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0019 +Encoding: 25 25 26 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni001A +Encoding: 26 26 27 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni001B +Encoding: 27 27 28 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni001C +Encoding: 28 28 29 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni001D +Encoding: 29 29 30 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni001E +Encoding: 30 30 31 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni001F +Encoding: 31 31 32 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: space +Encoding: 32 32 33 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: exclam +Encoding: 33 33 34 +Width: 585 +Flags: MW +HStem: -21 100<549 573> 416 21<479 479> 742 20<525 525> +VStem: 423 107 513 95<15 43> +LayerCount: 2 +Fore +SplineSet +525 762 m 1x70 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x70 +563 79 m 0x88 + 588 79 608 58 608 30 c 0 + 608 0 587 -21 559 -21 c 0 + 534 -21 513 0 513 28 c 0 + 513 58 535 79 563 79 c 0x88 +EndSplineSet +Validated: 1 +EndChar + +StartChar: quotedbl +Encoding: 34 34 35 +Width: 585 +Flags: MW +HStem: 416 21G<77 77 479 479> 697 20G<82 82> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +82 717 m 1xd0 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xd0 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: numbersign +Encoding: 35 35 36 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 355 95<172 405 172 406 158 405> 416 21<479 479> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1x80 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +525 762 m 1xb0 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xb0 +EndSplineSet +Validated: 1 +EndChar + +StartChar: dollar +Encoding: 36 36 37 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 416 21<77 77> 685 95<155 423 155 168> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xa0 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1xa0 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x60 + 139 92 l 1xa0 +82 717 m 1x28 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x28 +155 780 m 1x30 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x30 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x60 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: percent +Encoding: 37 37 38 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 416 21G<77 77> 685 95<155 423 155 168> 697 20G<82 82> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xa0 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1xa0 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x60 + 139 92 l 1xa0 +82 717 m 1x28 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x28 +155 780 m 1x30 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x30 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x60 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: ampersand +Encoding: 38 38 39 +Width: 585 +Flags: MW +HStem: 36 21<472 472> 355 95<172 405 172 406 158 405> 416 21<479 479> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1xb0 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xb0 +EndSplineSet +Validated: 1 +EndChar + +StartChar: quotesingle +Encoding: 39 39 40 +Width: 585 +Flags: MW +HStem: 416 21G<479 479> 742 20G<525 525> 742 20G<525 525> +VStem: 423 107 +LayerCount: 2 +Fore +SplineSet +525 762 m 1xd0 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xd0 +EndSplineSet +Validated: 1 +EndChar + +StartChar: parenleft +Encoding: 40 40 41 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21G<47 47> 374 20G<77 77> 416 21G<77 77> 685 95<155 423 155 168> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xb0 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1xb0 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x70 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1x34 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x34 +155 780 m 1x38 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x38 +EndSplineSet +Validated: 1 +EndChar + +StartChar: parenright +Encoding: 41 41 42 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 416 21G<479 479> 685 95<155 423 155 168> 742 20G<525 525> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xa0 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1xa0 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x60 + 139 92 l 1xa0 +155 780 m 1x30 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x30 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x60 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x28 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x28 +EndSplineSet +Validated: 1 +EndChar + +StartChar: asterisk +Encoding: 42 42 43 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 355 95<172 405 172 406 158 405> 416 21G<479 479> 742 20G<525 525> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1x80 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +525 762 m 1xb0 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xb0 +EndSplineSet +Validated: 1 +EndChar + +StartChar: plus +Encoding: 43 43 44 +Width: 577 +VWidth: 2048 +Flags: HMW +HStem: 36 21G<472 472> 355 95<172 405 172 406 158 405> 416 21G<479 479> 742 20G<525 525> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +461.400390625 433.799804688 m 1x80 + 497.400390625 394.200195312 l 1 + 450 350.399414062 l 1 + 284.400390625 350.399414062 l 1 + 295.799804688 433.799804688 l 1 + 461.400390625 433.799804688 l 1x80 +120 350.399414062 m 1 + 78 396 l 1 + 128.400390625 433.799804688 l 1 + 286.200195312 433.799804688 l 1 + 274.200195312 350.399414062 l 1 + 120 350.399414062 l 1 +249.600585938 439.799804688 m 1 + 328.200195312 439.799804688 l 1 + 376.799804688 732 l 1 + 297 732 l 1 + 249.600585938 439.799804688 l 1 +241.799804688 343.799804688 m 1 + 318.600585938 343.799804688 l 1 + 272.400390625 51.599609375 l 1 + 192.600585938 51.599609375 l 1 + 241.799804688 343.799804688 l 1 +EndSplineSet +Validated: 524297 +EndChar + +StartChar: comma +Encoding: 44 44 45 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: hyphen +Encoding: 45 45 46 +Width: 585 +Flags: MW +HStem: 355 95<172 405 172 406 158 405> +LayerCount: 2 +Fore +SplineSet +172 450 m 1 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: period +Encoding: 46 46 47 +Width: 711 +Flags: MWO +HStem: -21 100<549 573> +VStem: 513 95<15 43> +LayerCount: 2 +Fore +SplineSet +563 79 m 0 + 588 79 608 58 608 30 c 0 + 608 0 587 -21 559 -21 c 0 + 534 -21 513 0 513 28 c 0 + 513 58 535 79 563 79 c 0 +EndSplineSet +Validated: 1 +Position2: "Single Positioning lookup 0 subtable" dx=0 dy=0 dh=-586 dv=0 +EndChar + +StartChar: slash +Encoding: 47 47 48 +Width: 585 +Flags: MW +HStem: 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<479 479> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa8 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa8 +172 450 m 1xc8 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc8 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x98 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: zero +Encoding: 48 48 49 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 374 20G<77 77> 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x98 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x98 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x58 + 139 92 l 1x98 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x38 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1x1a + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x1a +155 780 m 1x1c + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x1c +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x58 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x19 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x19 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: one +Encoding: 49 49 50 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 416 21G<479 479> 742 20G<525 525> 742 20G<525 525> +VStem: 406 124 +LayerCount: 2 +Fore +SplineSet +475 388 m 1xc8 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1xc8 +525 762 m 1xe8 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xe8 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: two +Encoding: 50 50 51 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<479 479> 685 95<155 423 155 168> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1x80 +77 394 m 1x50 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x50 +155 780 m 1x04 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x04 +172 450 m 1x20 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x20 +525 762 m 1x0a + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x0a +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: three +Encoding: 51 51 52 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 355 95<172 405 172 406 158 405> 416 21G<479 479> 685 95<155 423 155 168> 742 20G<525 525> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +155 780 m 1x08 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x08 +172 450 m 1x20 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x20 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x14 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x14 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: four +Encoding: 52 52 53 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 355 95<172 405 172 406 158 405> 416 21G<77 77 479 479> 697 20G<82 82> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +82 717 m 1xb4 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xb4 +172 450 m 1xc4 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc4 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1xa4 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: five +Encoding: 53 53 54 +Width: 585 +Flags: MW +HStem: -2 94<138 147 75 400 147 288 288 400 138 460> 36 21G<472 472> 356 94<171 404 171 406 158 404> 416 21G<77 77> 685 91<169 513> 697 20G<82 82> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +476 389 m 1x40 + 508 351 l 1 + 489 62 l 1 + 472 36 l 1 + 406 114 l 1 + 419 342 l 1 + 476 389 l 1x40 +171 450 m 1x20 + 404 450 l 1 + 470 399 l 1 + 406 356 l 1 + 158 356 l 1 + 136 374 114 389 92 406 c 1 + 171 450 l 1x20 +155 779 m 1 + 513 776 l 1 + 423 685 l 1 + 169 685 l 1x08 + 89 736 l 1 + 155 779 l 1 +82 717 m 1x14 + 168 662 l 1 + 157 463 l 1 + 77 416 l 1 + 67 441 l 1 + 82 717 l 1x14 +138 92 m 1x80 + 400 92 l 1 + 421 65 445 37 466 10 c 0 + 469 7 471 5 471 3 c 0 + 471 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 147 -2 l 1 + 75 -2 l 1 + 68 6 61 15 54 23 c 0 + 51 27 46 30 46 35 c 2 + 46 37 l 1 + 138 92 l 1x80 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: six +Encoding: 54 54 55 +Width: 585 +Flags: MW +HStem: -2 94<138 147 75 400 147 288 288 400 138 460> 36 21G<472 472> 58 21G<47 47> 356 94<171 404 171 406 158 404> 393 21G<76 76> 416 21G<77 77> 685 91<169 513> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +138 92 m 1x80 + 400 92 l 1 + 421 65 445 37 466 10 c 0 + 469 7 471 5 471 3 c 0 + 471 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 147 -2 l 1 + 75 -2 l 1 + 68 6 61 15 54 23 c 0 + 51 27 46 30 46 35 c 2 + 46 37 l 1 + 138 92 l 1x80 +82 717 m 1x05 + 168 662 l 1 + 157 463 l 1 + 77 416 l 1 + 67 441 l 1 + 82 717 l 1x05 +155 779 m 1 + 513 776 l 1 + 423 685 l 1 + 169 685 l 1x02 + 89 736 l 1 + 155 779 l 1 +171 450 m 1x10 + 404 450 l 1 + 470 399 l 1 + 406 356 l 1 + 158 356 l 1 + 136 374 114 389 92 406 c 1 + 171 450 l 1x10 +476 389 m 1 + 508 351 l 1 + 489 62 l 1 + 472 36 l 1x40 + 406 114 l 1 + 419 342 l 1 + 476 389 l 1 +76 393 m 1x28 + 151 342 l 1 + 139 109 l 1 + 47 58 l 1 + 63 363 l 2 + 67 373 72 383 76 393 c 1x28 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: seven +Encoding: 55 55 56 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 416 21G<479 479> 685 95<155 423 155 168> 742 20G<525 525> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +155 780 m 1xe0 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1xe0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1xd0 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xd0 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: eight +Encoding: 56 56 57 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +77 394 m 1x28 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x28 +82 717 m 1x05 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x05 +155 780 m 1x02 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x02 +172 450 m 1x10 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x10 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x0480 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x0480 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: nine +Encoding: 57 57 58 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 355 95<172 405 172 406 158 405> 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +82 717 m 1x14 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x14 +155 780 m 1x08 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x08 +172 450 m 1x20 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x20 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x11 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x11 +EndSplineSet +Validated: 1 +Kerns2: 47 -586 "'kern' Horizontal Kerning lookup 1 subtable" +EndChar + +StartChar: colon +Encoding: 58 58 59 +Width: 383 +VWidth: 2048 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +131.399414062 148.399414062 m 6 + 180.599609375 198.799804688 l 6 + 186.599609375 204.399414062 192.399414062 207.19921875 198 207.19921875 c 4 + 203.200195312 207.19921875 209.399414062 204 216.599609375 197.599609375 c 6 + 264.599609375 146 l 6 + 269.399414062 139.599609375 271.799804688 133.799804688 271.799804688 128.599609375 c 4 + 271.799804688 122.599609375 269 116.399414062 263.399414062 110 c 6 + 215.399414062 57.19921875 l 6 + 207.399414062 49.19921875 201.599609375 45.19921875 198 45.19921875 c 4 + 191.599609375 45.19921875 185.799804688 48 180.599609375 53.599609375 c 6 + 127.799804688 114.19921875 l 6 + 123.799804688 119.399414062 121.799804688 124.599609375 121.799804688 129.799804688 c 4 + 121.799804688 135.799804688 125 142 131.399414062 148.399414062 c 6 +131.399414062 564.19921875 m 6 + 180.599609375 614.599609375 l 6 + 186.599609375 620.19921875 192.399414062 623 198 623 c 4 + 203.200195312 623 209.399414062 619.799804688 216.599609375 613.399414062 c 6 + 264.599609375 561.799804688 l 6 + 269.399414062 555.399414062 271.799804688 549.599609375 271.799804688 544.399414062 c 4 + 271.799804688 538.399414062 269 532.19921875 263.399414062 525.799804688 c 6 + 215.399414062 473 l 6 + 207.399414062 465 201.599609375 461 198 461 c 4 + 191.599609375 461 185.799804688 463.799804688 180.599609375 469.399414062 c 6 + 127.799804688 530 l 6 + 123.799804688 535.19921875 121.799804688 540.399414062 121.799804688 545.599609375 c 4 + 121.799804688 551.599609375 125 557.799804688 131.399414062 564.19921875 c 6 +EndSplineSet +Validated: 524289 +EndChar + +StartChar: semicolon +Encoding: 59 59 60 +Width: 585 +Flags: MW +HStem: -21 100<549 573> 416 21<479 479> 742 20<525 525> +VStem: 423 107 513 95<15 43> +LayerCount: 2 +Fore +SplineSet +525 762 m 1x70 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x70 +563 79 m 0x88 + 588 79 608 58 608 30 c 0 + 608 0 587 -21 559 -21 c 0 + 534 -21 513 0 513 28 c 0 + 513 58 535 79 563 79 c 0x88 +EndSplineSet +Validated: 1 +EndChar + +StartChar: less +Encoding: 60 60 61 +Width: 585 +Flags: W +LayerCount: 2 +Fore +SplineSet +139 92 m 1 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +172 450 m 1 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: equal +Encoding: 61 61 62 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 355 95<172 405 172 406 158 405> +LayerCount: 2 +Fore +SplineSet +139 92 m 1 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1 +172 450 m 1 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: greater +Encoding: 62 62 63 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: question +Encoding: 63 63 64 +Width: 585 +Flags: MW +HStem: 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<479 479> 685 95<155 423 155 168> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa0 +155 780 m 1x88 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x88 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +525 762 m 1x94 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x94 +EndSplineSet +Validated: 1 +EndChar + +StartChar: at +Encoding: 64 64 65 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<479 479> 685 95<155 423 155 168> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +77 394 m 1x28 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x28 +155 780 m 1x02 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x02 +172 450 m 1x10 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x10 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x05 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x05 +EndSplineSet +Validated: 1 +EndChar + +StartChar: A +Encoding: 65 65 66 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xd0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xd0 +82 717 m 1xca + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xca +155 780 m 1xc4 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1xc4 +172 450 m 1xe0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xe0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1xc9 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xc9 +EndSplineSet +Validated: 1 +EndChar + +StartChar: B +Encoding: 66 66 67 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x82 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x82 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x42 + 139 92 l 1x82 +77 394 m 1x2a + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x2a +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1x06 + 66 440 l 1 + 82 717 l 1 +172 450 m 1x12 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x12 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x42 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: C +Encoding: 67 67 68 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21<47 47> 374 20<77 77> 416 21<77 77> 685 95<155 423 155 168> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xb0 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1xb0 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x70 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1x34 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x34 +155 780 m 1x38 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x38 +EndSplineSet +Validated: 1 +EndChar + +StartChar: D +Encoding: 68 68 69 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<479 479> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x82 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x82 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x42 + 139 92 l 1x82 +77 394 m 1x2a + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x2a +172 450 m 1x12 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x12 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x42 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x06 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: E +Encoding: 69 69 70 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77> 685 95<155 423 155 168> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1x80 +77 394 m 1x50 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x50 +82 717 m 1x0a + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x0a +155 780 m 1x04 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x04 +172 450 m 1x20 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x20 +EndSplineSet +Validated: 1 +EndChar + +StartChar: F +Encoding: 70 70 71 +Width: 585 +Flags: MW +HStem: 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77> 685 95<155 423 155 168> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa0 +82 717 m 1x94 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x94 +155 780 m 1x88 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x88 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +EndSplineSet +Validated: 1 +Substitution2: "Single Substitution lookup 0 subtable" f +EndChar + +StartChar: G +Encoding: 71 71 72 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 374 20G<77 77> 416 21G<77 77> 685 95<155 423 155 168> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x98 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x98 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x58 + 139 92 l 1x98 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x38 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1x1a + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x1a +155 780 m 1x1c + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x1c +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x58 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: H +Encoding: 72 72 73 +Width: 585 +Flags: MW +HStem: 36 21<472 472> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77 479 479> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xd6 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xd6 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1xce + 66 440 l 1 + 82 717 l 1 +172 450 m 1xe6 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xe6 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1xce + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: I +Encoding: 73 73 74 +Width: 585 +Flags: MW +HStem: 36 21<472 472> 416 21<479 479> 742 20<525 525> +VStem: 406 124 +LayerCount: 2 +Fore +SplineSet +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: J +Encoding: 74 74 75 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 374 20<77 77> 416 21<479 479> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x9c + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x9c + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x5c + 139 92 l 1x9c +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x3c + 63 363 l 2 + 66 373 74 384 77 394 c 1 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x5c + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +Substitution2: "Single Substitution lookup 0 subtable" j +EndChar + +StartChar: K +Encoding: 75 75 76 +Width: 585 +Flags: MW +HStem: 36 21<472 472> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77> 685 95<155 423 155 168> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xd0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xd0 +82 717 m 1xca + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xca +155 780 m 1xc4 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1xc4 +172 450 m 1xe0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xe0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: L +Encoding: 76 76 77 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21<47 47> 374 20<77 77> 416 21<77 77> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xb8 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1xb8 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x78 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: M +Encoding: 77 77 78 +Width: 585 +Flags: W +LayerCount: 2 +Fore +SplineSet +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +172 450 m 1 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: N +Encoding: 78 78 79 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 59 21G<47 47> 374 20G<77 77> 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xf0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xf0 +82 717 m 1xf4 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xf4 +155 780 m 1xf8 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1xf8 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1xf2 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xf2 +EndSplineSet +Validated: 1 +EndChar + +StartChar: O +Encoding: 79 79 80 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 374 20<77 77> 416 21<77 77 479 479> 685 95<155 423 155 168> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x98 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x98 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x58 + 139 92 l 1x98 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x38 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1x1a + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x1a +155 780 m 1x1c + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x1c +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x58 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x19 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x19 +EndSplineSet +Validated: 1 +EndChar + +StartChar: P +Encoding: 80 80 81 +Width: 585 +Flags: MW +HStem: 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77 479 479> 685 95<155 423 155 168> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa0 +82 717 m 1x94 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x94 +155 780 m 1x88 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x88 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +525 762 m 1x92 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x92 +EndSplineSet +Validated: 1 +EndChar + +StartChar: Q +Encoding: 81 81 82 +Width: 585 +Flags: MW +HStem: 36 21<472 472> 355 95<172 405 172 406 158 405> 416 21<77 77 479 479> 685 95<155 423 155 168> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +82 717 m 1xa8 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xa8 +155 780 m 1x90 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x90 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1xa4 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xa4 +EndSplineSet +Validated: 1 +EndChar + +StartChar: R +Encoding: 82 82 83 +Width: 585 +Flags: MW +HStem: 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa0 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +EndSplineSet +Validated: 1 +EndChar + +StartChar: S +Encoding: 83 83 84 +Width: 585 +Flags: MW +HStem: -2 94<138 147 75 400 147 288 288 400 138 460> 36 21<472 472> 356 94<171 404 171 406 158 404> 416 21<77 77> 685 91<169 513> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +138 92 m 1x80 + 400 92 l 1 + 421 65 445 37 466 10 c 0 + 469 7 471 5 471 3 c 0 + 471 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 147 -2 l 1 + 75 -2 l 1 + 68 6 61 15 54 23 c 0 + 51 27 46 30 46 35 c 2 + 46 37 l 1 + 138 92 l 1x80 +82 717 m 1x14 + 168 662 l 1 + 157 463 l 1 + 77 416 l 1 + 67 441 l 1 + 82 717 l 1x14 +155 779 m 1 + 513 776 l 1 + 423 685 l 1 + 169 685 l 1x08 + 89 736 l 1 + 155 779 l 1 +171 450 m 1x20 + 404 450 l 1 + 470 399 l 1 + 406 356 l 1 + 158 356 l 1 + 136 374 114 389 92 406 c 1 + 171 450 l 1x20 +476 389 m 1 + 508 351 l 1 + 489 62 l 1 + 472 36 l 1x40 + 406 114 l 1 + 419 342 l 1 + 476 389 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: T +Encoding: 84 84 85 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x84 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1x84 +77 394 m 1x54 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x54 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1x0c + 66 440 l 1 + 82 717 l 1 +172 450 m 1x24 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x24 +EndSplineSet +Validated: 1 +EndChar + +StartChar: U +Encoding: 85 85 86 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 374 20<77 77> 416 21<77 77 479 479> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x9e + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x9e + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x5e + 139 92 l 1x9e +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x3e + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x5e + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: V +Encoding: 86 86 87 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 374 20<77 77> 416 21<77 77 479 479> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x9e + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x9e + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x5e + 139 92 l 1x9e +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x3e + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x5e + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: W +Encoding: 87 87 88 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77 479 479> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x83 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x83 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x43 + 139 92 l 1x83 +77 394 m 1x2b + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x2b +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1x07 + 66 440 l 1 + 82 717 l 1 +172 450 m 1x13 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x13 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x43 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x07 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: X +Encoding: 88 88 89 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 355 95<172 405 172 406 158 405> 685 95<155 423 155 168> +LayerCount: 2 +Fore +SplineSet +139 92 m 1 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1 +155 780 m 1 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1 +172 450 m 1 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: Y +Encoding: 89 89 90 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 355 95<172 405 172 406 158 405> 416 21<77 77 479 479> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x84 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x84 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x44 + 139 92 l 1x84 +82 717 m 1x1c + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x1c +172 450 m 1x24 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x24 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x44 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x14 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: Z +Encoding: 90 90 91 +Width: 585 +Flags: MW +HStem: 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<479 479> 685 95<155 423 155 168> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa0 +155 780 m 1x88 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x88 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +525 762 m 1x94 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x94 +EndSplineSet +Validated: 1 +EndChar + +StartChar: bracketleft +Encoding: 91 91 92 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21<47 47> 374 20<77 77> 416 21<77 77> 685 95<155 423 155 168> 697 20<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xb0 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1xb0 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x70 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1x34 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x34 +155 780 m 1x38 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x38 +EndSplineSet +Validated: 1 +EndChar + +StartChar: backslash +Encoding: 92 92 93 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 355 95<172 405 172 406 158 405> 416 21G<77 77> 697 20G<82 82> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +82 717 m 1xb0 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xb0 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: bracketright +Encoding: 93 93 94 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 416 21<479 479> 685 95<155 423 155 168> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xa0 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1xa0 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x60 + 139 92 l 1xa0 +155 780 m 1x30 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x30 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x60 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x28 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x28 +EndSplineSet +Validated: 1 +EndChar + +StartChar: asciicircum +Encoding: 94 94 95 +Width: 585 +Flags: MW +HStem: 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +82 717 m 1xa0 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xa0 +155 780 m 1xc0 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1xc0 +525 762 m 1x88 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x88 +EndSplineSet +Validated: 1 +EndChar + +StartChar: underscore +Encoding: 95 95 96 +Width: 585 +Flags: MW +HStem: 355 95<172 405 172 406 158 405> +LayerCount: 2 +Fore +SplineSet +172 450 m 1 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: grave +Encoding: 96 96 97 +Width: 585 +Flags: MW +HStem: 416 21<479 479> 742 20<525 525> +VStem: 423 107 +LayerCount: 2 +Fore +SplineSet +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: a +Encoding: 97 97 98 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<479 479> 685 95<155 423 155 168> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +77 394 m 1x28 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x28 +155 780 m 1x02 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x02 +172 450 m 1x10 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x10 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x05 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x05 +EndSplineSet +Validated: 1 +EndChar + +StartChar: b +Encoding: 98 98 99 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x82 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x82 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x42 + 139 92 l 1x82 +77 394 m 1x2a + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x2a +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1x06 + 66 440 l 1 + 82 717 l 1 +172 450 m 1x12 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x12 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x42 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: c +Encoding: 99 99 100 +Width: 585 +Flags: W +LayerCount: 2 +Fore +SplineSet +139 92 m 1 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +172 450 m 1 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: d +Encoding: 100 100 101 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<479 479> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x82 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x82 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x42 + 139 92 l 1x82 +77 394 m 1x2a + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x2a +172 450 m 1x12 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x12 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x42 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x06 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: e +Encoding: 101 101 102 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1x80 +77 394 m 1x50 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x50 +82 717 m 1x0a + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x0a +155 780 m 1x04 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x04 +172 450 m 1x20 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x20 +525 762 m 1x09 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x09 +EndSplineSet +Validated: 1 +EndChar + +StartChar: f +Encoding: 102 102 103 +Width: 585 +Flags: MW +HStem: 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77> 685 95<155 423 155 168> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa0 +82 717 m 1x94 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x94 +155 780 m 1x88 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x88 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +EndSplineSet +Validated: 1 +EndChar + +StartChar: g +Encoding: 103 103 104 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 355 95<172 405 172 406 158 405> 416 21<77 77 479 479> 685 95<155 423 155 168> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +82 717 m 1x14 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x14 +155 780 m 1x08 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x08 +172 450 m 1x20 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x20 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x12 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x12 +EndSplineSet +Validated: 1 +EndChar + +StartChar: h +Encoding: 104 104 105 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xd4 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xd4 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1xcc + 66 440 l 1 + 82 717 l 1 +172 450 m 1xe4 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xe4 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: i +Encoding: 105 105 106 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> +VStem: 406 103 +LayerCount: 2 +Fore +SplineSet +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: j +Encoding: 106 106 107 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 374 20G<77 77> 416 21G<479 479> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x9c + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x9c + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x5c + 139 92 l 1x9c +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x3c + 63 363 l 2 + 66 373 74 384 77 394 c 1 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x5c + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: k +Encoding: 107 107 108 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77> 685 95<155 423 155 168> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xd0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xd0 +82 717 m 1xca + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xca +155 780 m 1xc4 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1xc4 +172 450 m 1xe0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xe0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: l +Encoding: 108 108 109 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21G<47 47> 374 20G<77 77> 416 21G<77 77> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xb8 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1xb8 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x78 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: m +Encoding: 109 109 110 +Width: 585 +Flags: MW +HStem: 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77 479 479> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xac + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xac +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1x9c + 66 440 l 1 + 82 717 l 1 +172 450 m 1xcc + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xcc +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x9c + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: n +Encoding: 110 110 111 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xd0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xd0 +172 450 m 1xe0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xe0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: o +Encoding: 111 111 112 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +77 394 m 1x28 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x28 +172 450 m 1x10 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x10 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: p +Encoding: 112 112 113 +Width: 585 +Flags: MW +HStem: 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa0 +82 717 m 1x94 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x94 +155 780 m 1x88 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x88 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +525 762 m 1x92 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x92 +EndSplineSet +Validated: 1 +EndChar + +StartChar: q +Encoding: 113 113 114 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 355 95<172 405 172 406 158 405> 416 21G<77 77 479 479> 685 95<155 423 155 168> 697 20G<82 82> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +82 717 m 1xa8 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1xa8 +155 780 m 1x90 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x90 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1xa2 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1xa2 +EndSplineSet +Validated: 1 +EndChar + +StartChar: r +Encoding: 114 114 115 +Width: 585 +Flags: MW +HStem: 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa0 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa0 +172 450 m 1xc0 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc0 +EndSplineSet +Validated: 1 +EndChar + +StartChar: s +Encoding: 115 115 116 +Width: 585 +Flags: MW +HStem: -2 94<138 147 75 400 147 288 288 400 138 460> 36 21G<472 472> 356 94<171 404 171 406 158 404> 416 21G<77 77> 685 91<169 513> 697 20G<82 82> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +138 92 m 1x80 + 400 92 l 1 + 421 65 445 37 466 10 c 0 + 469 7 471 5 471 3 c 0 + 471 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 147 -2 l 1 + 75 -2 l 1 + 68 6 61 15 54 23 c 0 + 51 27 46 30 46 35 c 2 + 46 37 l 1 + 138 92 l 1x80 +82 717 m 1x14 + 168 662 l 1 + 157 463 l 1 + 77 416 l 1 + 67 441 l 1 + 82 717 l 1x14 +155 779 m 1 + 513 776 l 1 + 423 685 l 1 + 169 685 l 1x08 + 89 736 l 1 + 155 779 l 1 +171 450 m 1x20 + 404 450 l 1 + 470 399 l 1 + 406 356 l 1 + 158 356 l 1 + 136 374 114 389 92 406 c 1 + 171 450 l 1x20 +476 389 m 1 + 508 351 l 1 + 489 62 l 1 + 472 36 l 1x40 + 406 114 l 1 + 419 342 l 1 + 476 389 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: t +Encoding: 116 116 117 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77> 697 20G<82 82> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x84 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1x84 +77 394 m 1x54 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x54 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1x0c + 66 440 l 1 + 82 717 l 1 +172 450 m 1x24 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x24 +EndSplineSet +Validated: 1 +EndChar + +StartChar: u +Encoding: 117 117 118 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 374 20G<77 77> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x90 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x90 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x50 + 139 92 l 1x90 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x30 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x50 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: v +Encoding: 118 118 119 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 374 20G<77 77> 416 21G<77 77 479 479> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x9e + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x9e + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x5e + 139 92 l 1x9e +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x3e + 63 363 l 2 + 66 373 74 384 77 394 c 1 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x5e + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: w +Encoding: 119 119 120 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77 479 479> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x83 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x83 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x43 + 139 92 l 1x83 +77 394 m 1x2b + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x2b +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1x07 + 66 440 l 1 + 82 717 l 1 +172 450 m 1x13 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x13 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x43 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x07 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: x +Encoding: 120 120 121 +Width: 585 +Flags: MW +HStem: 36 21G<472 472> 59 21G<47 47> 355 95<172 405 172 406 158 405> 374 20G<77 77> 416 21G<77 77 479 479> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xd6 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xd6 +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1xce + 66 440 l 1 + 82 717 l 1 +172 450 m 1xe6 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xe6 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1xce + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: y +Encoding: 121 121 122 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21G<47 47 472 472> 355 95<172 405 172 406 158 405> 416 21G<77 77 479 479> 697 20G<82 82> 697 20G<82 82> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x82 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x82 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x42 + 139 92 l 1x82 +82 717 m 1x1a + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x1a +172 450 m 1x22 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x22 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x42 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x12 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: z +Encoding: 122 122 123 +Width: 585 +Flags: MW +HStem: 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<479 479> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xa8 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xa8 +172 450 m 1xc8 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xc8 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x98 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: braceleft +Encoding: 123 123 124 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: bar +Encoding: 124 124 125 +Width: 585 +Flags: MW +HStem: 36 21<472 472> 416 21<479 479> 742 20<525 525> +VStem: 406 124 +LayerCount: 2 +Fore +SplineSet +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: braceright +Encoding: 125 125 126 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: asciitilde +Encoding: 126 126 127 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21G<47 47> 374 20G<77 77> 416 21G<479 479> 685 95<155 423 155 168> 742 20G<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1xb0 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1xb0 +77 394 m 1 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1x70 + 63 363 l 2 + 66 373 74 384 77 394 c 1 +155 780 m 1x38 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x38 +525 762 m 1x34 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x34 +EndSplineSet +Validated: 1 +EndChar + +StartChar: uni007F +Encoding: 127 127 128 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0080 +Encoding: 128 128 129 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0081 +Encoding: 129 129 130 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0082 +Encoding: 130 130 131 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0083 +Encoding: 131 131 132 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0084 +Encoding: 132 132 133 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0085 +Encoding: 133 133 134 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0086 +Encoding: 134 134 135 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0087 +Encoding: 135 135 136 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0088 +Encoding: 136 136 137 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0089 +Encoding: 137 137 138 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni008A +Encoding: 138 138 139 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni008B +Encoding: 139 139 140 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni008C +Encoding: 140 140 141 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni008D +Encoding: 141 141 142 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni008E +Encoding: 142 142 143 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni008F +Encoding: 143 143 144 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0090 +Encoding: 144 144 145 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0091 +Encoding: 145 145 146 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0092 +Encoding: 146 146 147 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0093 +Encoding: 147 147 148 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0094 +Encoding: 148 148 149 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0095 +Encoding: 149 149 150 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0096 +Encoding: 150 150 151 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0097 +Encoding: 151 151 152 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0098 +Encoding: 152 152 153 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni0099 +Encoding: 153 153 154 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni009A +Encoding: 154 154 155 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni009B +Encoding: 155 155 156 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni009C +Encoding: 156 156 157 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni009D +Encoding: 157 157 158 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni009E +Encoding: 158 158 159 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni009F +Encoding: 159 159 160 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni00A0 +Encoding: 160 160 161 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: exclamdown +Encoding: 161 161 162 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: cent +Encoding: 162 162 163 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: sterling +Encoding: 163 163 164 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: currency +Encoding: 164 164 165 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: yen +Encoding: 165 165 166 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: brokenbar +Encoding: 166 166 167 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: section +Encoding: 167 167 168 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: dieresis +Encoding: 168 168 169 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: copyright +Encoding: 169 169 170 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ordfeminine +Encoding: 170 170 171 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: guillemotleft +Encoding: 171 171 172 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: logicalnot +Encoding: 172 172 173 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni00AD +Encoding: 173 173 174 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: registered +Encoding: 174 174 175 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: macron +Encoding: 175 175 176 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: degree +Encoding: 176 176 177 +Width: 585 +Flags: MW +HStem: 355 95<172 405 172 406 158 405> 416 21<77 77 479 479> 685 95<155 423 155 168> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +172 450 m 1x80 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x80 +82 717 m 1x50 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x50 +155 780 m 1x60 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x60 +525 762 m 1x48 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x48 +EndSplineSet +Validated: 1 +EndChar + +StartChar: plusminus +Encoding: 177 177 178 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni00B2 +Encoding: 178 178 179 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni00B3 +Encoding: 179 179 180 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: acute +Encoding: 180 180 181 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni00B5 +Encoding: 181 181 182 +Width: 585 +Flags: MW +HStem: 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77 479 479> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +77 394 m 1xac + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1xac +82 717 m 1 + 168 661 l 1 + 156 463 l 1 + 77 416 l 1x9c + 66 440 l 1 + 82 717 l 1 +172 450 m 1xcc + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1xcc +525 762 m 1 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1x9c + 423 458 l 1 + 435 672 l 1 + 525 762 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: paragraph +Encoding: 182 182 183 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: periodcentered +Encoding: 183 183 184 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: cedilla +Encoding: 184 184 185 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uni00B9 +Encoding: 185 185 186 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ordmasculine +Encoding: 186 186 187 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: guillemotright +Encoding: 187 187 188 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: onequarter +Encoding: 188 188 189 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: onehalf +Encoding: 189 189 190 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: threequarters +Encoding: 190 190 191 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: questiondown +Encoding: 191 191 192 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Agrave +Encoding: 192 192 193 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Aacute +Encoding: 193 193 194 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Acircumflex +Encoding: 194 194 195 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Atilde +Encoding: 195 195 196 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Adieresis +Encoding: 196 196 197 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Aring +Encoding: 197 197 198 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: AE +Encoding: 198 198 199 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Ccedilla +Encoding: 199 199 200 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Egrave +Encoding: 200 200 201 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Eacute +Encoding: 201 201 202 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Ecircumflex +Encoding: 202 202 203 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Edieresis +Encoding: 203 203 204 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Igrave +Encoding: 204 204 205 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Iacute +Encoding: 205 205 206 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Icircumflex +Encoding: 206 206 207 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Idieresis +Encoding: 207 207 208 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Eth +Encoding: 208 208 209 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Ntilde +Encoding: 209 209 210 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Ograve +Encoding: 210 210 211 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Oacute +Encoding: 211 211 212 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Ocircumflex +Encoding: 212 212 213 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Otilde +Encoding: 213 213 214 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Odieresis +Encoding: 214 214 215 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: multiply +Encoding: 215 215 216 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Oslash +Encoding: 216 216 217 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Ugrave +Encoding: 217 217 218 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Uacute +Encoding: 218 218 219 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Ucircumflex +Encoding: 219 219 220 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Udieresis +Encoding: 220 220 221 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Yacute +Encoding: 221 221 222 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: Thorn +Encoding: 222 222 223 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: germandbls +Encoding: 223 223 224 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: agrave +Encoding: 224 224 225 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<479 479> 685 95<155 423 155 168> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +77 394 m 1x28 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x28 +155 780 m 1x02 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x02 +172 450 m 1x10 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x10 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x05 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x05 +EndSplineSet +Validated: 1 +EndChar + +StartChar: aacute +Encoding: 225 225 226 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 36 21<47 47 472 472> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<479 479> 685 95<155 423 155 168> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1x80 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1x40 + 139 92 l 1x80 +77 394 m 1x28 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x28 +155 780 m 1x02 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x02 +172 450 m 1x10 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x10 +475 388 m 1 + 509 350 l 1 + 490 62 l 1 + 472 36 l 1x40 + 406 115 l 1 + 418 342 l 1 + 475 388 l 1 +525 762 m 1x05 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x05 +EndSplineSet +Validated: 1 +EndChar + +StartChar: acircumflex +Encoding: 226 226 227 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: atilde +Encoding: 227 227 228 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: adieresis +Encoding: 228 228 229 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: aring +Encoding: 229 229 230 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ae +Encoding: 230 230 231 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ccedilla +Encoding: 231 231 232 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: egrave +Encoding: 232 232 233 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: eacute +Encoding: 233 233 234 +Width: 585 +Flags: MW +HStem: -2 94<139 146 75 400 146 288 288 400 139 460> 59 21<47 47> 355 95<172 405 172 406 158 405> 374 20<77 77> 416 21<77 77 479 479> 685 95<155 423 155 168> 697 20<82 82> 742 20<525 525> +LayerCount: 2 +Fore +SplineSet +139 92 m 1x80 + 400 92 l 1 + 421 66 444 36 465 10 c 0 + 468 7 470 5 470 3 c 0 + 470 0 467 -2 460 -2 c 2 + 288 -2 l 1 + 146 -2 l 1 + 75 -2 l 1 + 68 7 61 15 54 24 c 0 + 51 27 47 30 47 35 c 2 + 47 36 l 1 + 139 92 l 1x80 +77 394 m 1x50 + 151 342 l 1 + 139 109 l 1 + 47 59 l 1 + 63 363 l 2 + 66 373 74 384 77 394 c 1x50 +82 717 m 1x0a + 168 661 l 1 + 156 463 l 1 + 77 416 l 1 + 66 440 l 1 + 82 717 l 1x0a +155 780 m 1x04 + 514 775 l 1 + 423 685 l 1 + 168 685 l 1 + 88 735 l 1 + 155 780 l 1x04 +172 450 m 1x20 + 405 450 l 1 + 470 399 l 1 + 406 355 l 1 + 158 355 l 1 + 137 374 113 389 92 406 c 1 + 172 450 l 1x20 +525 762 m 1x09 + 527 757 530 751 530 746 c 0 + 525 647 519 552 514 453 c 1 + 479 416 l 1 + 423 458 l 1 + 435 672 l 1 + 525 762 l 1x09 +EndSplineSet +Validated: 1 +EndChar + +StartChar: ecircumflex +Encoding: 234 234 235 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: edieresis +Encoding: 235 235 236 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: igrave +Encoding: 236 236 237 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: iacute +Encoding: 237 237 238 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: icircumflex +Encoding: 238 238 239 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: idieresis +Encoding: 239 239 240 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: eth +Encoding: 240 240 241 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ntilde +Encoding: 241 241 242 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ograve +Encoding: 242 242 243 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: oacute +Encoding: 243 243 244 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ocircumflex +Encoding: 244 244 245 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: otilde +Encoding: 245 245 246 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: odieresis +Encoding: 246 246 247 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: divide +Encoding: 247 247 248 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: oslash +Encoding: 248 248 249 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ugrave +Encoding: 249 249 250 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: uacute +Encoding: 250 250 251 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ucircumflex +Encoding: 251 251 252 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: udieresis +Encoding: 252 252 253 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: yacute +Encoding: 253 253 254 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: thorn +Encoding: 254 254 255 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar + +StartChar: ydieresis +Encoding: 255 255 256 +Width: 585 +Flags: W +LayerCount: 2 +Fore +Validated: 1 +EndChar +EndChars +EndSplineFont diff --git a/public/font/Segment7.woff b/public/font/Segment7.woff new file mode 100644 index 0000000000..53f1471dd9 Binary files /dev/null and b/public/font/Segment7.woff differ diff --git a/public/font/Segment7.woff2 b/public/font/Segment7.woff2 new file mode 100644 index 0000000000..55afda145a Binary files /dev/null and b/public/font/Segment7.woff2 differ diff --git a/public/font/alarmclock.woff2 b/public/font/alarmclock.woff2 new file mode 100644 index 0000000000..fcae9c38d8 Binary files /dev/null and b/public/font/alarmclock.woff2 differ diff --git a/public/font/lichess.woff b/public/font/lichess.woff index c896bc7536..1ac42db692 100644 Binary files a/public/font/lichess.woff and b/public/font/lichess.woff differ diff --git a/public/font/lichess.woff2 b/public/font/lichess.woff2 index e8eba7ad76..99ce8f9c2e 100644 Binary files a/public/font/lichess.woff2 and b/public/font/lichess.woff2 differ diff --git a/public/images/icons/tornado-white.svg b/public/images/icons/tornado-white.svg new file mode 100644 index 0000000000..51e880d145 --- /dev/null +++ b/public/images/icons/tornado-white.svg @@ -0,0 +1 @@ + diff --git a/public/images/icons/tornado.svg b/public/images/icons/tornado.svg new file mode 100644 index 0000000000..9b35fe9918 --- /dev/null +++ b/public/images/icons/tornado.svg @@ -0,0 +1 @@ + diff --git a/translation/dest/broadcast/bg-BG.xml b/translation/dest/broadcast/bg-BG.xml index 3ea04e700d..8842ca1be7 100644 --- a/translation/dest/broadcast/bg-BG.xml +++ b/translation/dest/broadcast/bg-BG.xml @@ -1,2 +1,21 @@ - + + Излъчване + Излъчвания на турнир на живо + Нови предавания на живо + Текущи + Предстоящи + Завършени + Име на събитието + Кратко описание на събитието + Пълно описание на събитието + Незадължително дълго описание на излъчването. %1$s е налично. Дължината трябва да по-малка от %2$s знака. + Уебадрес на източника + Уебадресът, който Lichess ще проверява, за да получи осъвременявания на PGN. Той трябва да е публично достъпен от интернет. + Номер на рунда + Дата на започване във вашата часова зона + По избор, ако знаете, кога започва събитието + Признателност на източника + Клониране на излъчването + Нулиране на излъчването + diff --git a/translation/dest/challenge/az-AZ.xml b/translation/dest/challenge/az-AZ.xml index d1c1ebf779..49bf0d8f69 100644 --- a/translation/dest/challenge/az-AZ.xml +++ b/translation/dest/challenge/az-AZ.xml @@ -8,8 +8,8 @@ Çağırış göndərmək üçün lütfən qeydiyyatdan keçin. %s istifadəçisinə çağırış edə bilməzsiz. %s çağırışları qəbul etmir. - Sizin %1$s reytinqiniz %2$s-in reytinqindən çox uzaqdır. - Müvəqqəti %s reytinqi səbəbilə çağırış edə bilməzsiz. + Sizin %1$s reytinqiniz %2$s-in reytinqindən çox uzaqdır. + Müvəqqəti %s reytinqi səbəbilə çağırış edə bilməzsiz. %s yalnız dostlarından çağırış qəbul edir. Hal-hazırda çağırışları qəbul etmirəm. Bu mənim üçün uyğun vaxt deyil, lütfən sonra yenidən soruşun. @@ -20,4 +20,6 @@ Zəhmət olmasa mənə reytinqsiz bir çağırış göndərin. Hal-hazırda qeyri-ənənəvi şahmat variantları çağırışlarını qəbul etmirəm. Hazırda bu variantı oynamaq istəmirəm. + Botlardan gələn çağırışları qəbul etmirəm. + Yalnız botlardan gələn çağırışları qəbul edirəm. diff --git a/translation/dest/challenge/bg-BG.xml b/translation/dest/challenge/bg-BG.xml index 3ea04e700d..faf712a943 100644 --- a/translation/dest/challenge/bg-BG.xml +++ b/translation/dest/challenge/bg-BG.xml @@ -1,2 +1,22 @@ - + + Предизвикателства + Предизвикайте на партия + Предизвикателството отказано + Предизвикателството прието! + Предизвикателството отменено. + Регистрирайте се, за да отправяте предизвикателства. + Не може да предизвикате %s. + %s не приема предизвикателства. + Вашият рейтинг %1$s е предалеч от %2$s. + %s приема предизвикателства само от приятели. + Не приемам предизвикателства в момента. + Това не е точният момент за мен, моля, опитайте пак по-късно. + Този път управлението е пребързо за мен, моля, предизвикайте ме пак с по-бавна игра. + Този път управлението е твърде бавно за мен, моля, предизвикайте ме пак с по-бърза игра. + Не приемам предизвикателства с такъв времеви формат. + Вместо това изпращайте ми рейтингови предизвикателства, моля. + Вместо това изпращайте ми лежерни предизвикателства, моля. + Не приемам вариант за партия шах в момента. + Не желая да играя този вариант в момента. + diff --git a/translation/dest/challenge/bs-BA.xml b/translation/dest/challenge/bs-BA.xml index 8246a02570..393ba666cc 100644 --- a/translation/dest/challenge/bs-BA.xml +++ b/translation/dest/challenge/bs-BA.xml @@ -8,9 +8,11 @@ Molimo, registrirajte se da biste mogli slati izazove. Ne možete izazvati %s. %s ne prihvata izazove. - Vaš %1$s rejting predaleko je od %2$s. - Nemoguće izazvati zbog privremenog %s rejtinga. + Vaš %1$s rejting predaleko je od %2$s. + Nemoguće izazvati zbog privremenog %s rejtinga. %s prihvata samo izazove od prijatelja. Trenutno ne prihvatam izazove. Ne odgovara mi ovaj trenutak; molim, izazovite me ponovo kasnije. + Ne prihvatam izazove od botova. + Prihvatam izazove samo od botova. diff --git a/translation/dest/challenge/ca-ES.xml b/translation/dest/challenge/ca-ES.xml index 64b3b149c8..5a80c4fdd5 100644 --- a/translation/dest/challenge/ca-ES.xml +++ b/translation/dest/challenge/ca-ES.xml @@ -1,6 +1,25 @@ + Desafiaments + Desafia a una partida + Desafiament rebutjat + Desafiament acceptat! + Desafiament cancel·lat. + Si us plau, registra\'t per enviar desafiaments. + No pots desafiar a %s. + %s no accepta desafiaments. + La teva qualificació de %1$s és massa distant de la de %2$s. + No es pot desafiar a causa de la qualificació provisional de %s. + %s només accepta desafiaments dels amics. + No accepto desafiaments en aquest moment. + Ara mateix no puc, si us plau prova-ho més tard. Aquest control de temps és massa ràpid per a mi. Si us plau, desafia\'m un altra vegada amb un ritme més lent. Aquest control de temps és massa lent per a mi. Si us plau, desafia\'m una altra vegada amb un ritme més ràpid. No accepto desafiaments amb aquest control de temps. + Si us plau, envia\'m un desafiament puntuat. + Si us plau, envia\'m un desafiament casual. + No accepto desafiaments per variants en aquest moment. + No vull jugar aquesta variant en aquest moment. + No accepto desafiaments de bots. + Només accepto desafiaments de bots. diff --git a/translation/dest/challenge/da-DK.xml b/translation/dest/challenge/da-DK.xml index 6badecc4e2..52507421cd 100644 --- a/translation/dest/challenge/da-DK.xml +++ b/translation/dest/challenge/da-DK.xml @@ -8,8 +8,8 @@ Opret en konto for at sende udfordringer. Du kan ikke udfordre %s. %s accepterer ikke udfordringer. - Din %1$s rating er for langt fra %2$s. - Kan ikke udfordre på grund af provisorisk %s rating. + Din %1$s rating er for langt fra %2$s. + Kan ikke udfordre på grund af provisorisk %s rating. %s accepterer kun udfordringer fra venner. Jeg accepterer ikke udfordringer i øjeblikket. Det er ikke et godt tidspunkt for mig, spørg venligst igen senere. @@ -20,4 +20,6 @@ Send mig gerne en ikke-ratet udfordring i stedet. Jeg accepterer ikke variantudfordringer lige nu. Jeg er ikke villig til at spille denne variant lige nu. + Jeg accepterer ikke udfordringer fra bots. + Jeg accepterer kun udfordringer fra bots. diff --git a/translation/dest/challenge/de-DE.xml b/translation/dest/challenge/de-DE.xml index c13bdad52c..50102c5e9a 100644 --- a/translation/dest/challenge/de-DE.xml +++ b/translation/dest/challenge/de-DE.xml @@ -8,16 +8,18 @@ Bitte registriere dich, um Herausforderungen zu senden. Du kannst %s nicht herausfordern. %s nimmt keine Herausforderungen an. - Deine %1$s Wertung ist zu weit von %2$s entfernt. - Herausforderung wegen provisorischer %s Wertung nicht möglich. + Deine %1$s Wertung ist zu weit von %2$s entfernt. + Herausforderung wegen provisorischer %s Wertung nicht möglich. %s nimmt Herausforderungen nur von Freunden an. Ich nehme derzeit keine Herausforderungen an. Ich nehme momentan keine Herausforderungen an, bitte frage später noch einmal. - Diese Bedenkzeit ist zu gering für mich, ich bitte daher um erneutes Herausfordern mit mehr Bedenkzeit. - Diese Bedenkzeit ist zu viel für mich, ich bitte daher um erneutes Herausfordern mit weniger Bedenkzeit. - Ich nehme keine Herausforderungen mit Bedenkzeit an. + Diese Bedenkzeit ist zu gering für mich, bitte fordere mich erneut mit einer höheren Bedenkzeit heraus. + Diese Bedenkzeit ist zu lang für mich, bitte fordere mich mit weniger Bedenkzeit heraus. + Ich nehme keine Herausforderungen mit dieser Bedenkzeit an. Bitte fordere mich stattdessen zu einer gewerteten Partie heraus. Bitte fordere mich stattdessen zu einer ungewerteten Partie heraus. Ich nehme derzeit keine Herausforderungen für andere Spielvarianten an. - Ich bin nicht bereit, diese Variante zu spielen. + Ich bin derzeit nicht bereit, diese Variante zu spielen. + Ich nehme keine Herausforderungen von Bots an. + Ich nehme nur Herausforderungen von Bots an. diff --git a/translation/dest/challenge/el-GR.xml b/translation/dest/challenge/el-GR.xml index 3ea04e700d..9147066bdc 100644 --- a/translation/dest/challenge/el-GR.xml +++ b/translation/dest/challenge/el-GR.xml @@ -1,2 +1,5 @@ - + + Δεν δέχομαι προκλήσεις από bots. + Δέχομαι μόνο προκλήσεις από bots. + diff --git a/translation/dest/challenge/en-US.xml b/translation/dest/challenge/en-US.xml index 3d8775fee0..9f3288513b 100644 --- a/translation/dest/challenge/en-US.xml +++ b/translation/dest/challenge/en-US.xml @@ -8,8 +8,8 @@ Please register to send challenges. You cannot challenge %s. %s does not accept challenges. - Your %1$s rating is too far from %2$s. - Cannot challenge due to provisional %s rating. + Your %1$s rating is too far from %2$s. + Cannot challenge due to provisional %s rating. %s only accepts challenges from friends. I\'m not accepting challenges at the moment. This is not the right time for me, please ask again later. @@ -20,4 +20,6 @@ Please send me a casual challenge instead. I\'m not accepting variant challenges right now. I\'m not willing to play this variant right now. + I\'m not accepting challenges from bots. + I\'m only accepting challenges from bots. diff --git a/translation/dest/challenge/es-ES.xml b/translation/dest/challenge/es-ES.xml index 5371017dab..a9140eadae 100644 --- a/translation/dest/challenge/es-ES.xml +++ b/translation/dest/challenge/es-ES.xml @@ -8,8 +8,8 @@ Por favor regístrate para desafiar a otros jugadores. No puedes desafiar a %s. %s no acepta desafíos. - Tu puntuación de %1$s está demasiado lejos de la de %2$s. - No puedes desafiar a otros jugadores debido a que tu puntuación de %s es provisional. + Tu puntuación de %1$s está demasiado lejos de la de %2$s. + No puedes desafiar a otros jugadores debido a que tu puntuación de %s es provisional. %s sólo acepta desafíos de sus amigos. No estoy aceptando desafíos por el momento. No estoy aceptando desafíos ahora mismo, por favor pregunta de nuevo más tarde. @@ -17,7 +17,9 @@ Este control de tiempo es demasiado lento para mí, por favor desafíame de nuevo con una partida más rápida. No estoy aceptando desafíos con este control de tiempo. En su lugar, desafíame a una partida por puntos. - En su lugar, desafíame a una partida casual. + En su lugar, desafíame a una partida amistosa. No estoy aceptando desafíos de variantes en este momento. No estoy dispuesto a jugar esta variante en este momento. + No estoy aceptando desafíos de bots. + Solo estoy aceptando desafíos de bots. diff --git a/translation/dest/challenge/eu-ES.xml b/translation/dest/challenge/eu-ES.xml index 3ea04e700d..b5f10de9f9 100644 --- a/translation/dest/challenge/eu-ES.xml +++ b/translation/dest/challenge/eu-ES.xml @@ -1,2 +1,25 @@ - + + Erronkak + Partida baterako erronka egin + Erronka baztertuta + Erronka onartuta! + Erronka bertan behera utzita. + Eman izena erronkak bidaltzeko. + Ezin diozu %s erabiltzaileri erronka egin. + %s erabiltzaileak ez du erronkarik onartzen. + Zure %1$s puntuazioa urrunegi dago %2$s-tik. + Ezin duzu erronkarik egin behin-behineko %s puntuazioa duzulako. + %s erabiltzaileak bere lagunen erronkak onartzen ditu bakarrik. + Orain ez dut erronkarik onartzen. + Hori ez da momenturik onena, eskatu beranduago. + Erritmo hori azkarregia da, proposatu partida geldoago bat. + Erritmo hori geldoegia da, proposatu partida azkarrago bat. + Ez dut erritmo horretako erronkarik onartzen. + Mesedez bidali puntuaziorako balio duen erronka bat. + Mesedez bidali lagunarteko erronka bat, puntuaziorako balio ez duena. + Ez dut aldaeren erronkarik onartzen. + Ez dut aldaera horretan jokatu nahi. + Ez dut erroboten erronkarik onartzen. + Erroboten erronkak bakarrik onartzen ditut. + diff --git a/translation/dest/challenge/fi-FI.xml b/translation/dest/challenge/fi-FI.xml index fcb98394b1..faf46840e6 100644 --- a/translation/dest/challenge/fi-FI.xml +++ b/translation/dest/challenge/fi-FI.xml @@ -8,9 +8,11 @@ Rekisteröidy niin voit lähettää haasteita. Et voi haastaa pelaajaa %s. %s ei ota haasteita vastaan. - %1$s-vahvuuslukusi on liian kaukana pelaajan %2$s vahvuusluvusta. - Et voi haastaa, koska %s-vahvuuslukusi on tilapäinen. + %1$s-vahvuuslukusi on liian kaukana pelaajan %2$s vahvuusluvusta. + Et voi haastaa, koska %s-vahvuuslukusi on tilapäinen. %s ottaa vastaan haasteita vain kavereiltaan. En ota tällä hetkellä haasteita vastaan. Ajankohta ei sovi minulle juuri nyt, pyydä myöhemmin uudelleen. + En ota vastaan haasteita boteilta. + Otan vastaan haasteita vain boteilta. diff --git a/translation/dest/challenge/fo-FO.xml b/translation/dest/challenge/fo-FO.xml index a6e2fc800d..6e08580300 100644 --- a/translation/dest/challenge/fo-FO.xml +++ b/translation/dest/challenge/fo-FO.xml @@ -13,4 +13,6 @@ %s tekur bert við avbjóðingum frá vinum. Eg taki ikki móti avbjóðingum í løtuni. Eg taki ikki ímóti avbjóðingum í løtuni. Spyr vinaliga aftur seinni. + Eg taki ikki móti avbjóðingum frá teldum. + Eg taki bert móti avbjóðingum frá teldum. diff --git a/translation/dest/challenge/fr-FR.xml b/translation/dest/challenge/fr-FR.xml index 31cccbfef6..65e4cc1858 100644 --- a/translation/dest/challenge/fr-FR.xml +++ b/translation/dest/challenge/fr-FR.xml @@ -8,8 +8,8 @@ Veuillez vous inscrire pour envoyer des défis. Vous ne pouvez pas défier %s. %s n’accepte pas les défis. - Votre classement de %1$s est trop différent de celui de %2$s. - Défi refusé à cause de la cote %s provisoire + Votre classement de %1$s est trop différent de celui de %2$s. + Défi refusé à cause de la cote %s provisoire %s n’accepte que les défis de ses ami(e)s. Je n\'accepte pas de défis pour le moment. Ce n\'est pas un bon moment pour moi, réessayez plus tard s\'il vous plaît. @@ -20,4 +20,6 @@ Envoyez-moi plutôt un défi amical. Je n\'accepte pas de défis en variantes pour le moment. Je ne veux pas jouer cette variante pour le moment. + Je n\'accepte pas les défis des robots. + J\'accepte uniquement les défis des robots. diff --git a/translation/dest/challenge/hr-HR.xml b/translation/dest/challenge/hr-HR.xml index 6f692d9147..03e02cb4b2 100644 --- a/translation/dest/challenge/hr-HR.xml +++ b/translation/dest/challenge/hr-HR.xml @@ -5,19 +5,21 @@ Izazov odbijen Izazov prihvaćen! Izazov otkazan. - Za slanje izazova morate se registrirati. - Ne možete izazvati %s. + Registriraj se za slanje izazova. + Ne možeš izazvati %s. %s ne prihvaća izazove. - Prevelika je razlika između tvog i %2$s %1$s rejtinga. - Nemoguće izazvati zbog prevelike razlike u %s rejtingu. - %s prihvaća samo izazove od prijatelja. + Prevelika je razlika između tvog i %2$s %1$s rejtinga. + Nemoguće izazvati zbog prevelike razlike u %s rejtingu. + %s prihvaća izazove isključivo od prijatelja. Trenutačno ne prihvaćam izazove. - Trenutačno nije najbolje vrijeme, molimo Vas pokušajte kasnije. - Ovaj vremenski format je prebrz za mene, molim Vas da me izazovete na sporiji format. - Ovaj vremenski format je prespor za mene, molim Vas da me izazovete na brži format. + Trenutačno ne mogu prihvatiti izazov, molim te da pokušaš kasnije. + Ovaj vremenski format je prebrz za mene, izazovi me na sporiji format. + Ovaj vremenski format je prespor za mene, izazovi me na brži format. Ne prihvaćam izazove u ovom vremenskom formatu. - Molim Vas da me radije izazovete na rangiranu partiju. - Molim Vas da me radije izazovete na ležernu partiju. + Radije me izazovi na bodovanu partiju. + Radije me izazovi na ležernu partiju. Ne prihvaćam izazove u ovoj varijanti. Trenutačno ne želim igrati ovu varijantu. + Ne prihvaćam izazove od botova. + Prihvaćam izazove isključivo od botova. diff --git a/translation/dest/challenge/ja-JP.xml b/translation/dest/challenge/ja-JP.xml index 7bb3a856bb..c6c01d0afd 100644 --- a/translation/dest/challenge/ja-JP.xml +++ b/translation/dest/challenge/ja-JP.xml @@ -8,8 +8,8 @@ 挑戦を送るには登録が必要です。 %s には挑戦できません。 %s は挑戦を受け付けていません。 - あなたの %1$s レーティングは %2$s と離れすぎています。 - %s レーティングが暫定のため挑戦できません。 + あなたの %1$s レーティングは %2$s と離れすぎています。 + %s レーティングが暫定のため挑戦できません。 %s は友達からの挑戦しか受け付けません。 現在、挑戦を受け付けていません。 今は都合が悪いので、後でもう一度尋ねてください。 @@ -20,4 +20,6 @@ 代わりに非レート戦での挑戦を送ってください。 現在、バリアントでの挑戦は受け付けていません。 今はこのバリアントで対戦するつもりはありません。 + ボットからの挑戦は受け付けていません。 + 私はボットからの挑戦しか受け付けません。 diff --git a/translation/dest/challenge/lt-LT.xml b/translation/dest/challenge/lt-LT.xml index 57acf713e2..c30bfd5653 100644 --- a/translation/dest/challenge/lt-LT.xml +++ b/translation/dest/challenge/lt-LT.xml @@ -20,4 +20,6 @@ Vietoje šio iššūkio atsiųskite nevertinamą iššūkį. Šiuo metu nepriimu variantų iššūkių. Šiuo metu nenoriu žaisti šio varianto. + Nepriimu iššūkių iš programų. + Priimu iššūkius tik iš programų. diff --git a/translation/dest/challenge/lv-LV.xml b/translation/dest/challenge/lv-LV.xml index f7791e6c7c..ebb16775c8 100644 --- a/translation/dest/challenge/lv-LV.xml +++ b/translation/dest/challenge/lv-LV.xml @@ -8,8 +8,8 @@ Lūdzu reģistrējieties, lai sūtītu izaicinājumus. Nevarat izaicināt %s. %s nepieņem izaicinājumus. - Jūsu %1$s reitings ir par tālu no %2$s. - Nevar izaicināt pagaidu %s reitinga dēļ. + Jūsu %1$s reitings ir par tālu no %2$s. + Nevar izaicināt pagaidu %s reitinga dēļ. %s pieņem izaicinājumus tikai no draugiem. Pašlaik nepieņemu izaicinājumus. Šis laiks man neder, lūdzu piedāvājiet vēlāk. @@ -20,4 +20,6 @@ Labāk lūdzu atsūtiet nevērtētu izaicinājumu. Šobrīd nepieņemu variantu izaicinājumus. Šobrīd nevēlos spēlēt šo variantu. + Pašlaik nepieņemu izaicinājumus no botiem. + Pieņemu izaicinājumus tikai no botiem. diff --git a/translation/dest/challenge/nb-NO.xml b/translation/dest/challenge/nb-NO.xml index 373a979ffc..6c1b55f0ad 100644 --- a/translation/dest/challenge/nb-NO.xml +++ b/translation/dest/challenge/nb-NO.xml @@ -20,4 +20,6 @@ Send meg en utfordring til et uformelt parti i stedet. Jeg godtar ikke utfordringer til varianter for øyeblikket. Jeg ønsker ikke å spille denne varianten for øyeblikket. + Jeg godtar ikke utfordringer fra boter. + Jeg godtar bare utfordringer fra boter. diff --git a/translation/dest/challenge/nl-NL.xml b/translation/dest/challenge/nl-NL.xml index d1950f9fc0..e33ebce478 100644 --- a/translation/dest/challenge/nl-NL.xml +++ b/translation/dest/challenge/nl-NL.xml @@ -8,8 +8,8 @@ Gelieve te registreren om uitdagingen te versturen. Je kunt %s niet uitdagen. %s neemt geen uitdagingen aan. - Je rating van %1$s wijkt te veel af van %2$s. - Uitdagen niet mogelijk vanwege voorlopige %s-rating. + Je rating van %1$s wijkt te veel af van %2$s. + Uitdagen niet mogelijk vanwege voorlopige %s-rating. %s neemt alleen uitdagingen aan van vrienden. Momenteel neem ik geen uitdagingen aan. Op dit moment neem ik geen uitdagingen aan, probeer het later nog eens. @@ -20,4 +20,6 @@ Stuur me a.u.b. een uitdaging zonder rating. Momenteel neem ik geen uitdagingen aan voor varianten. Momenteel voel ik er niet voor om deze variant te spelen. + Ik neem geen uitdagingen van bots aan. + Ik neem alleen uitdagingen van bots aan. diff --git a/translation/dest/challenge/nn-NO.xml b/translation/dest/challenge/nn-NO.xml index 7ad66fd00d..4add459f4c 100644 --- a/translation/dest/challenge/nn-NO.xml +++ b/translation/dest/challenge/nn-NO.xml @@ -8,8 +8,8 @@ Du må registrera deg om du vil oppretta utfordringar. Du kan ikkje utfordra %s. %s tek ikkje i mot utfordringar. - Ratinga di i %1$s er for langt unna %2$s. - Kan ikkje utfordre grunna mellombels %s rating. + Ratinga di i %1$s er for langt unna %2$s. + Kan ikkje utfordre grunna mellombels %s rating. %s tek berre mot utfordringar frå vener. Eg tek for tida ikkje mot utfordringar. Det passar ikkje nett no, men spør meg gjerne seinare. @@ -20,4 +20,6 @@ Send meg heller ei utfordring til eit uformelt parti. Eg tek ikkje utfordringar til variantar nett no. Eg ønskjer ikkje å spela denne varianten nett no. + Eg tek ikkje utfordringar frå bottar. + Eg tek berre utfordringar frå bottar. diff --git a/translation/dest/challenge/pl-PL.xml b/translation/dest/challenge/pl-PL.xml index d4bec6de09..f3d416d20d 100644 --- a/translation/dest/challenge/pl-PL.xml +++ b/translation/dest/challenge/pl-PL.xml @@ -8,8 +8,8 @@ Zarejestruj się, aby zapraszać do gry. Nie możesz wyzwać %s. %s nie przyjmuje wyzwań. - Twój ranking (%1$s) jest zbyt odległy od %2$s. - Nie możesz zapraszać ze względu na swój tymczasowy ranking (%s). + Twój ranking (%1$s) jest zbyt odległy od %2$s. + Nie możesz zapraszać ze względu na swój tymczasowy ranking (%s). %s akceptuje tylko wyzwania od znajomych. Obecnie nie akceptuję wyzwań. Nie mam teraz czasu, spróbuj proszę później. @@ -20,4 +20,6 @@ Zaproś mnie proszę do partii nierankingowej. Nie akceptuję teraz zaproszeń do gry w warianty. Nie chcę grać teraz tego wariantu. + Nie przyjmuję wyzwań od botów. + Przyjmuję tylko wyzwania od botów. diff --git a/translation/dest/challenge/pt-BR.xml b/translation/dest/challenge/pt-BR.xml index 785b9e66a2..c000e9d2c5 100644 --- a/translation/dest/challenge/pt-BR.xml +++ b/translation/dest/challenge/pt-BR.xml @@ -20,4 +20,6 @@ Por favor, envie-me um desafio amigável. Eu não estou aceitando desafios de variantes no momento. Não estou disposto a jogar esta variante no momento. + Não estou aceitando desafios de robôs. + Estou aceitando apenas desafios de robôs. diff --git a/translation/dest/challenge/pt-PT.xml b/translation/dest/challenge/pt-PT.xml index acd8f0b24d..c24edb979b 100644 --- a/translation/dest/challenge/pt-PT.xml +++ b/translation/dest/challenge/pt-PT.xml @@ -8,8 +8,8 @@ Por favor regista-te para enviar desafios. Não podes desafiar %s. %s não aceita desafios. - A tua classificação %1$s é muito diferente de %2$s. - Não podes desafiar por causa do tua pontuação provisória de %s. + A tua classificação %1$s é muito diferente de %2$s. + Não podes desafiar por causa do tua pontuação provisória de %s. %s só aceita desafios de amigos. Não estou a aceitar desafios com este controlo de tempo. Este não é o momento certo para mim, por favor pergunte novamente mais tarde. diff --git a/translation/dest/challenge/ro-RO.xml b/translation/dest/challenge/ro-RO.xml index 3ea04e700d..ccb1d3152d 100644 --- a/translation/dest/challenge/ro-RO.xml +++ b/translation/dest/challenge/ro-RO.xml @@ -1,2 +1,5 @@ - + + Nu accept provocările roboților. + Accept doar provocările roboților. + diff --git a/translation/dest/challenge/ru-RU.xml b/translation/dest/challenge/ru-RU.xml index e09f2f2220..3ffa01dfd4 100644 --- a/translation/dest/challenge/ru-RU.xml +++ b/translation/dest/challenge/ru-RU.xml @@ -20,4 +20,6 @@ Вызовите меня на товарищескую игру, пожалуйста. Я не принимаю вызовы на неклассические шахматы прямо сейчас. Я не хочу играть в этот вариант шахмат прямо сейчас. + Я не принимаю вызовы от ботов. + Я принимаю вызовы только от ботов. diff --git a/translation/dest/challenge/sl-SI.xml b/translation/dest/challenge/sl-SI.xml index 397ef65fa9..2ff51f97e6 100644 --- a/translation/dest/challenge/sl-SI.xml +++ b/translation/dest/challenge/sl-SI.xml @@ -1,5 +1,18 @@ + Izzivi + Izzovi na partijo + Izziv zavrnjen + Izziv je sprejet! + Izziv je preklican. + Če želite poslati izziv, se prosim registrirajte. + Ne morete izzvati %s. + %s ne sprejema izzivov. + Vaš %1$s rating je predaleč od ratinga igralca %2$s. + Izzivanje ni mogoče, zaradi začasnega %s ratinga. + %s sprejema izzive samo od prijateljev. + Sedaj ne sprejemam izzivov. + Zdaj ni pravi čas, posimo vprašajte kasneje. Tokratna kontrola je zame prehitra, prosim, ponovno izzivajte s počasnejšo igro. Tokratna kontrola je zame prepočasna, prosim, znova izzivajte s hitrejšo igro. S tem časovnim nadzorom ne sprejemam izzivov. @@ -7,4 +20,6 @@ Prosim, pošljite mi nerangirani izziv. Trenutno ne sprejemam variantnih izzivov. Trenutno nisem pripravljen igrati te različice. + Izzivov od robotov ne sprejemam. + Sprejemam le izzive od robotov. diff --git a/translation/dest/challenge/sv-SE.xml b/translation/dest/challenge/sv-SE.xml index 39c5534344..6e2efc3e35 100644 --- a/translation/dest/challenge/sv-SE.xml +++ b/translation/dest/challenge/sv-SE.xml @@ -8,16 +8,18 @@ Vänligen registrera ett konto för att skicka utmaningar. Du kan inte utmana %s. %s accepterar inte utmaningar. - Din %1$srating är för långt ifrån %2$s. - Kan inte utmana på grund av provisorisk %srating. + Din %1$srating är för långt ifrån %2$s. + Kan inte utmana på grund av provisorisk %srating. %s accepterar endast utmaningar från vänner. Jag accepterar inte utmaningar för tillfället. Detta är inte rätt tid för mig, vänligen fråga igen senare. Denna tidskontroll är för snabb för mig, vänligen utmana igen med ett långsammare parti. Denna tidskontroll är för långsam för mig, vänligen utmana igen med ett snabbare parti. - Jag accepterar inte utmaningar med denna tidskontroll. + Jag antar inte utmaningar med denna tidskontroll. Vänligen skicka en rankad utmaning istället. Vänligen skicka en orankad utmaning istället. - Jag accepterar inte utmaningar med varianter för tillfället. + Jag antar inte utmaningar med varianter för tillfället. Jag vill inte spela denna variant för tillfället. + Jag antar inte utmaningar från bottar. + Jag antar endast utmaningar från bottar. diff --git a/translation/dest/challenge/tr-TR.xml b/translation/dest/challenge/tr-TR.xml index 2dd92574d7..4502b4291c 100644 --- a/translation/dest/challenge/tr-TR.xml +++ b/translation/dest/challenge/tr-TR.xml @@ -8,8 +8,8 @@ Oyun daveti göndermek için üye olun. %s adlı oyuncuya oyun daveti gönderemezsiniz. %s oyun davetlerini kabul etmiyor. - %1$s puanınız %2$s ile kıyaslandığında büyük fark var. - %s puanınız geçici olduğu için başka oyunculara meydan okuyamazsınız. + %1$s puanınız %2$s ile kıyaslandığında büyük fark var. + %s puanınız geçici olduğu için başka oyunculara meydan okuyamazsınız. %s sadece arkadaşlarından gelen oyun davetlerini kabul ediyor. Şimdilik oyun tekliflerini kabul etmiyorum. Şu anda müsait değilim, lütfen daha sonra yeniden teklif ediniz. @@ -20,4 +20,6 @@ Bunun yerine puansız oyun teklifi yapınız lütfen. Şimdilik standart dışı varyantlarda oyun tekliflerini kabul etmiyorum. Şimdilik bu varyantı oynamak istemiyorum. + Botlardan gelen oyun tekliflerini kabul etmiyorum. + Yalnızca botlardan gelen oyun tekliflerini kabul ediyorum. diff --git a/translation/dest/challenge/uk-UA.xml b/translation/dest/challenge/uk-UA.xml index 3ea04e700d..682569b4aa 100644 --- a/translation/dest/challenge/uk-UA.xml +++ b/translation/dest/challenge/uk-UA.xml @@ -1,2 +1,5 @@ - + + Я не приймаю виклики від ботів. + Я приймаю виклики лише від ботів. + diff --git a/translation/dest/challenge/uz-UZ.xml b/translation/dest/challenge/uz-UZ.xml index 749420a707..0fdb47a756 100644 --- a/translation/dest/challenge/uz-UZ.xml +++ b/translation/dest/challenge/uz-UZ.xml @@ -4,4 +4,22 @@ O\'yinga chorlov Chorlovni rad etildi Chorlov qabul qilindi! + Chorlov bekor qilindi. + Iltimos o\'yinga chorlash uchun ro\'yhatdan o\'ting. + Siz %s ni chorlay olmaysiz. + %s chorlovni qabul qilmadi. + Sizning %1$s reytingingiz %2$s dan ancha uzoq. + %s taxminiy belgilangan reyting bilan bellashib bo\'lmaydi. + %s faqat doʻstlardan chorlovni qabul qiladi. + Ayni damda chorlovni qabul qila olmayman. + Ayni dam men uchun qulay emas, iltimos keyinroq soʻrang. + Usbu vaqt boshqaruvi men uchun tezlik qiladi, iltimos sekinroq oʻynash uchun uzoqroq vaqt bilan chorlang. + Ushbu vaqt boshqaruvi men uchun sekin hisoblanadi, iltimos tezroq oʻyin uchun qisqaroq vaqt bilan chorlang. + Men ushbu vaqt boshqaruvidagi chorlovni qabul qila olmayman. + Iltimos menga reytingli chorlovni yuboring. + Iltimos menga reytingsiz bellashuv chorlovini joʻnating. + Xozir men bellashuvlar variantlarini qabul qila olmayman. + Ayni damda ushbu variantda oʻynashga men tayyor emasman. + Ayni damda men botlardan chorlovlarni qabul qila olmayman. + Men faqat botlardan chorlovlarni qabul qila olaman. diff --git a/translation/dest/challenge/vi-VN.xml b/translation/dest/challenge/vi-VN.xml index 3ea04e700d..388a9a49a7 100644 --- a/translation/dest/challenge/vi-VN.xml +++ b/translation/dest/challenge/vi-VN.xml @@ -1,2 +1,14 @@ - + + Thách đấu + Yêu cầu chơi + Thử thách đấu bị từ chối + Lời thách đấu được chấp nhận! + Lời thách đấu bị hủy bỏ. + Xin vui lòng đăng ký để gửi những lời thách đấu. + Bạn không thể thách đấu %s. + %s không chấp nhận những lời thách đấu. + Chỉ số %1$s của bạn quá xa so với %2$s. + Không thể thách đấu do xếp hạng %s tạm thời. + %s chỉ chấp nhận những thách thức từ bạn bè. + diff --git a/translation/dest/class/es-ES.xml b/translation/dest/class/es-ES.xml index 5f5781da46..7056d4d9ed 100644 --- a/translation/dest/class/es-ES.xml +++ b/translation/dest/class/es-ES.xml @@ -5,7 +5,7 @@ Características Generar rápidamente nombres de usuario y contraseñas seguras para estudiantes Seguir el progreso del estudiante en partidas y ejercicios de táctica - Notificar a todos los estudiantes sobre el nuevo material de clase + Enviar un mensaje a todos los estudiantes sobre el nuevo material de clase 100% libre y gratuito para todos, para siempre, sin publicidad ni rastreadores Solicitar ser profesor de Lichess No hay clases todavía. @@ -90,7 +90,7 @@ Aquí está el enlace para acceder a la clase. Editar las novedades Notificar a todos los estudiantes Aún no hay nada aquí. - Todas las noticias de clase en un solo lugar. + Todas las noticias de la clase en un solo campo. Añade las novedades más recientes en la parte superior. No elimines las novedades anteriores. Separa las novedades con --- Mostrará una línea separadora horizontal. diff --git a/translation/dest/coach/et-EE.xml b/translation/dest/coach/et-EE.xml index 3ea04e700d..d54f04b145 100644 --- a/translation/dest/coach/et-EE.xml +++ b/translation/dest/coach/et-EE.xml @@ -1,2 +1,5 @@ - + + Lichess treenerid + Lichess treener + diff --git a/translation/dest/coach/uz-UZ.xml b/translation/dest/coach/uz-UZ.xml index 3ea04e700d..8a945eb49a 100644 --- a/translation/dest/coach/uz-UZ.xml +++ b/translation/dest/coach/uz-UZ.xml @@ -1,2 +1,12 @@ - + + Lichess murabbiylari + Lichess murabbiyi + Siz %s da ajoyib shaxmat murabbiyimisiz? + NM yoki FIDE + Oʻz reytingingizni kiriting va biz sizni ariznagizni koʻrib chiqamiz. + Tillar + Reyting + Soatli reyting + Mavjudligi + diff --git a/translation/dest/contact/bg-BG.xml b/translation/dest/contact/bg-BG.xml index 0f32d452de..62db89dabe 100644 --- a/translation/dest/contact/bg-BG.xml +++ b/translation/dest/contact/bg-BG.xml @@ -10,4 +10,11 @@ Забравих потребителското си име Можете да влезе с email адреса, с който сте регистрирани Нямам достъп до 2-стъпковите кодове за аутентикация + Искам да променя потребителското ми име + Искам да изчистя моята история или рейтинг + Не е възможно да почистите в играта своите история, шахматни задачи или рейтинги. + Искам да докладвам играч + Страница за грешката + Добре сте дошли да използвате Lichess за своята дейност, дори и търговска такава. + Никое от горните diff --git a/translation/dest/contact/es-ES.xml b/translation/dest/contact/es-ES.xml index bb6137a3ce..8d2c546096 100644 --- a/translation/dest/contact/es-ES.xml +++ b/translation/dest/contact/es-ES.xml @@ -34,8 +34,8 @@ No envíes mensajes directos a los moderadores. La única forma eficaz de denunciar jugadores es mediante el formulario de denuncia. Quiero informar de un error - En el Foro de Comentarios de Lichess - Como un problema del sitio web de Lichess en GitHub + En el foro de comentarios de Lichess + Como un problema de la página de Lichess en GitHub Como un problema de la aplicación móvil de Lichess en GitHub En el servidor de Discord de Lichess Por favor, describe cómo se ve el error, qué esperabas que sucediera, y los pasos para reproducir el error. diff --git a/translation/dest/contact/hr-HR.xml b/translation/dest/contact/hr-HR.xml index 374cb4a818..cc038b7ea4 100644 --- a/translation/dest/contact/hr-HR.xml +++ b/translation/dest/contact/hr-HR.xml @@ -27,6 +27,7 @@ Želim izbrisati svoju povijest ili ocjenu Nije moguće izbrisati svoju povijest igara, povijest zagonetka ili ocjenu. Želim prijaviti igrača + Kako biste prijavili igrača, koristite obrazac za prijavu Do te stranice možete doći i klikom na %s gumb za izvještaj na stranici profila. Nemojte prijavljivati igrače na forumu. Ne šaljite nam e-poštu s izvješćima. diff --git a/translation/dest/contact/sr-SP.xml b/translation/dest/contact/sr-SP.xml index 8cbb1653b0..adb4659aba 100644 --- a/translation/dest/contact/sr-SP.xml +++ b/translation/dest/contact/sr-SP.xml @@ -48,6 +48,7 @@ По FIDE Laws of Chess §6.9, ако је мат могућ са било којим редоследом легалних потеза, партија није реми Могуће је матирати уз помоћ само коња или ловца, ако противник има фигура сем краља. Рејтинг поени нису додељени + Страница са грешком Можеш послати жалбу %s. Грешке се могу дешавати понекад, и нама је жао због тога. Ако је твоја жалба легитимна, уклонићемо забрану што пре. diff --git a/translation/dest/emails/si-LK.xml b/translation/dest/emails/si-LK.xml index df166c5ba3..3b15a032c7 100644 --- a/translation/dest/emails/si-LK.xml +++ b/translation/dest/emails/si-LK.xml @@ -15,6 +15,7 @@ මෙන්න ඔබේ පැතිකඩ පිටුව: %1$s. ඔබට එය %2$s මත පුද්ගලීකරණය කළ හැකිය. විනෝද වන්න, ඔබේ කොටස් සෑම විටම ඔබේ ප්‍රතිවාදියාගේ රජු වෙතට යා හැකි වේවා! + Lichess.org වෙත සාදරයෙන් පිළිගනිමු, %s (ක්ලික් කිරීම ක්‍රියා නොකරයි ද? එය ඔබගේ බ්‍රව්සරයට ඇතුල් කර උත්සාහ කරන්න!) මෙය ඔබගේ %s භාවිතය හා සම්බන්ධ සේවා විද්‍යුත් තැපෑලකි. අප හා සම්බන්ධ වීමට, කරුණාකර %s භාවිතා කරන්න. diff --git a/translation/dest/faq/de-DE.xml b/translation/dest/faq/de-DE.xml index 5aa1d0295b..5c42a4d5eb 100644 --- a/translation/dest/faq/de-DE.xml +++ b/translation/dest/faq/de-DE.xml @@ -19,7 +19,7 @@ Fair Play Warum wurde ich für künstliche Wertungsmanipulation (Tiefstapelei und Hochtreiben) oder Computerunterstützung markiert? Lichess arbeitet mit starken Erkennungsmethoden und sehr gründlichen Verfahren, um alle Hinweise zu überprüfen und eine Entscheidung zu treffen. Der Prozess umfasst oft viele Moderatoren und kann eine lange Zeit dauern. Außer der Markierung selbst werden wir für einzelne Fälle nicht auf Einzelheiten über Hinweise oder das Entscheidungsverfahren eingehen. Dies würde es in Zukunft einfacher machen, eine Erkennung zu vermeiden und wäre eine Einladung zu unproduktiven Debatten. Diese Zeit und Mühe wenden wir lieber für andere wichtige Fälle auf. Benutzer können Widerspruch einlegen, indem sie eine E-Mail an %1$s schicken, jedoch werden Entscheidungen selten rückgängig gemacht. - Wann bin ich berechtigt, die automatische Wertungs-Rückerstattung von Betrügern zu erhalten? + Wann qualifiziere ich mich für die automatische Wertungs-Rückerstattung von Betrügern? Eine Minute, nachdem ein Spieler markiert wurde, werden seine 40 neuesten Partien in den letzten 3 Tagen betrachtet. Wenn du in diesen Partien unter den Gegnern warst, sich damit deine Wertung (wegen einer Niederlage oder eines Remis\') verschlechtert hat und deine Wertung nicht vorläufig war, erhältst du eine Wertungsrückerstattung. Die Rückerstattung wird begrenzt durch deine Spitzenwertung und deine Wertungsfortschritte nach der Partie. (Wenn deine Wertung nach diesen Partien stark gestiegen ist, erhältst du möglicherweise keine Rückerstattung oder nur eine Teilrückerstattung.) Eine Rückerstattung beträgt nie mehr als 150 Punkte. Was geschieht mit Spielern, die Partien verlassen ohne aufzugeben? @@ -28,7 +28,7 @@ Es ist nicht möglich, sich als Moderator zu bewerben. Wenn wir jemanden sehen, von dem wir glauben, dass er als Moderator gut wäre, werden wir ihn direkt kontaktieren. Unterscheidet sich Fernschach von normalem Schach? Bei Lichess besteht der Hauptunterschied bei den Regeln für Fernschach darin, dass hier zwar ein Eröffnungsbuch erlaubt ist. Die Verwendung von Schachcomputern ist jedoch immer noch verboten und führt zu einer Markierung des Kontos wegen unerlaubter Unterstützung durch Schachcomputer. Obwohl die ICCF die Verwendung von Schachcomputern in Fernschachpartien erlaubt, ist dies auf Lichess nicht gestattet. - Das Spiel selbst betreffend + Spielerlebnis Wie wird entschieden, was Bullet, Blitz und andere Zeitkontrollen sind? Lichess Zeitkontrollen basieren auf der erwarteten Spieldauer = %1$s Zum Beispiel berechnet sich die erwartete Spieldauer einer 5+3 Partie zu 5 × 60 + 40 × 3 = 420 Sekunden. diff --git a/translation/dest/faq/es-ES.xml b/translation/dest/faq/es-ES.xml index 829a875832..fea0a80472 100644 --- a/translation/dest/faq/es-ES.xml +++ b/translation/dest/faq/es-ES.xml @@ -99,7 +99,7 @@ No solicites el título de LM. Ese trofeo es único en la historia de Lichess, nadie más que %1$s lo tendrá jamás. Para obtenerlo, hiimgosu se desafió a sí mismo a berserk y ganó 100%% partidas de %s. un torneo Bullet por hora - ZugAddict estaba transmitiendo y durante las dos últimas horas había estado tratando de derrotar a la I.A. nivel 8 en una partida 1+0, sin éxito. Thibault le dijo que si lo hacía con éxito durante la transmisión, obtendría un trofeo único. Una hora después, venció a Stockfish y se cumplió la promesa. + ZugAddict estaba transmitiendo y durante las dos últimas horas había estado tratando de derrotar a la I.A. nivel 8 en una partida 1+0, sin éxito. Thibault le dijo que si lo lograba durante la transmisión, obtendría un trofeo único. Una hora después, venció a Stockfish y se cumplió la promesa. Puntuaciones de Lichess ¿Qué sistema de puntuación utiliza Lichess? Las puntuaciones se calculan utilizando el método de clasificación Glicko-2 desarrollado por Mark Glickman. Es un método de puntuación muy popular y que utilizan muchas organizaciones de ajedrez (la FIDE es un contraejemplo notable, ya que todavía utilizan el sistema de puntuación Elo). diff --git a/translation/dest/faq/et-EE.xml b/translation/dest/faq/et-EE.xml index 3ea04e700d..f96c66627d 100644 --- a/translation/dest/faq/et-EE.xml +++ b/translation/dest/faq/et-EE.xml @@ -1,2 +1,5 @@ - + + KKK + Korduma kippuvad küsimused + diff --git a/translation/dest/faq/hr-HR.xml b/translation/dest/faq/hr-HR.xml index 524727c3d7..76c69fbb9b 100644 --- a/translation/dest/faq/hr-HR.xml +++ b/translation/dest/faq/hr-HR.xml @@ -4,7 +4,7 @@ Često postavljena pitanja Zašto se Lichess tako zove? Lichess je šah opisan sa izrazima uživo/lako/beslatno. Izgovara se kao %1$s. - lee-chess + li čes Čujte to izgovara stručnjak. Uživo, jer se igre igraju i gledaju u stvarnom vremenu 24/7; lagan i besplatan zbog činjenice da je Lichess otvorenog koda i da nije opterećen vlasničkim smećem koji muči druge web stranice. Slično tome, izvorni kod Lichess-a, %1$s, stoji za li[chess in sca]la, s obzirom da je najveći dio Lichess-a napisan u %2$s, intuitivnom programskom jeziku. @@ -38,12 +38,21 @@ Na primjer, procijenjeno trajanje 5+3 računa se kao 5 × 60 + 40 × 3 i iznosi Koje varijente šaha mogu da igram na Lichess-u? Lichess podržava standardni šah i %1$s. Osmerostruka varijanta šaha + Što je prosječan gubitak centi-pješaka (ACPL)? + Centipawn je mjerna jedinica koja se koristi u šahu kao prikaz prednosti. Centipawn je jednak 1/100 pijuna. Prema tome 100 centipawn-a = 1 pijun. Te vrijednosti ne igraju formalnu ulogu u igri, ali su korisne igračima i ključne su u računalnom šahu za procjenu pozicija. + +Gornji potez računala izgubit će nula centipawn-a, ali manji potezi rezultirat će pogoršanjem položaja, mjereno u centipawn-ima. + +Ova se vrijednost može koristiti kao pokazatelj kvalitete igre. Što manje centipauna jedan izgubi po potezu, to je jača igra. + +Računalnu analizu na Lichessu pokreće Stockfish. Gubljenje igre zbog isteka vremena, remi i nedostatni šahovski materijal U slučaju da jednom igraču ponestane vremena, taj igrač će obično izgubiti igru. Međutim, igra je remi ako je položaj figura takav da protivnik ne može matirati protivničkog kralja nijednim mogućim nizom legalnih poteza (%1$s). U rijetkim slučajevima to se može teško odlučiti automatski (prisilne linije, tvrđave). Prema zadanim postavkama uvijek smo uz igrača kojem nije ponestalo vremena. Imajte na umu da je moguće izvesti mat sa jednim skakačem ili lovcem ako protivnik ima figuru koja bi mogla blokirati njegovog kralja. + FIDE priručnik %s Zašto može pijun uzeti protivničkog pijuna kojeg je već prošao? (en passant) Ovaj potez važi u šahu i poznat je kao \"en passant\". Članak na Wikipediji daje %1$s poteza \"en passant\". @@ -84,6 +93,8 @@ Nemojte tražiti LM titulu. Koje korisničko ime mogu koristiti? Općenito, korisničko ime ne bi trebala biti: uvredljivo, lažno predstavljanje nekog drugog ili oglašavanje. Više o %1$s korisničkog imena. smjernicama + Mogu li promijeniti svoje korisničko ime? + Ne, korisnička imena se ne mogu mijenjati iz tehničkih i praktičnih razloga. Korisnička imena materijalizirana su na previše mjesta: u bazama podataka, izvozima, zapisnicima i umovima ljudi. Kapitalizaciju možete prilagoditi jednom. Jedinstveni trofeji Taj trofej jedinstven je u povijesti Lichess-a. Nitko drugi osim %1$s ga nikad neće imati. Da bi ga dobio, hiimgosu je izazvao sebe na berserk i pobijedio u 100%% igara %s. @@ -91,4 +102,42 @@ Nemojte tražiti LM titulu. ZugAddict je emitirao i posljednjih 2 sata je pokušavao poraziti A.I. razine 8 u igri 1+0, ali bez uspjeha. Thibault mu je rekao da će dobiti jedinstveni trofej ako to uspješno učini u emitiranju. Sat vremena kasnije razbio je Stockfish, a obećanje je bilo ispunjeno. Lichess rajgovi Kakav sistem rangiranja koristi Lichess? + Ocjene se izračunavaju pomoću metode ocjenjivanja Glicko-2, koju je razvio Mark Glickman. Ovo je vrlo popularna metoda ocjenjivanja, a koristi je značajan broj šahovskih organizacija (FIDE je značajan kontra-primjer, jer još uvijek koriste datirani sustav ocjenjivanja Elo). + +U osnovi, ocjene Glicko koriste \"intervale pouzdanosti\" prilikom izračunavanja i predstavljanja vaše ocjene. Kada prvi put započnete koristiti web mjesto, vaša ocjena započinje s 1500 ± 700. 1500 predstavlja vašu ocjenu, a 700 predstavlja interval pouzdanosti. + +U osnovi, sustav je 90% siguran da je vaša ocjena negdje između 800 i 2200. Nevjerojatno je neizvjestan. Zbog toga će se, kad igrač tek započinje, njegova ocjena vrlo dramatično promijeniti, potencijalno nekoliko stotina bodova odjednom. Ali nakon nekih igara protiv etabliranih igrača interval povjerenja će se suziti, a količina osvojenih / izgubljenih bodova nakon svake igre smanjit će se. + +Još jedna stvar koju treba napomenuti jest da će se s vremenom interval pouzdanosti povećavati. To vam omogućuje brže osvajanje / gubljenje bodova kako biste se podudarali s bilo kakvim promjenama u razini vještina tijekom tog vremena. + Zašto se znak upitnik (?) nalazi pokraj mog rejtinga? + Upitnik znači da je vaš rejting privremen. Razlozi uključuju: + Igrač još nije završio dovoljno ocijenjene igre protiv %1$s u ocijenjenim partijama. + podjednaki protivnici + Igrač nije dugo igrao. Ovisno o broju igara koje ste igrali, možda će trebati oko godinu dana neaktivnosti da bi vaša ocjena ponovno postala privremena. + Konkretno, to znači da je odstupanje Glicko-2 veće od 110. Odstupanje je razina povjerenja koji sustav ima u ocjenu. Što je niže odstupanje, to je ocjena stabilnija. + Kako funkcioniraju titule i ljestvice poretka? + Da biste došli na %1$s, moraš: + ljestvica poretka + odigrati najmanje 30 ocijenjenih partija u određenom rejtingu + odigrati ocijenjenu igru ne stariju od tjedan dana, + imaju ocjenu odstupanja nižu od %1$s, u standardnom šahu, i nižu od %2$s u varijantama, + biti u top 10 u određenom rejtingu. + Drugi je uvjet da igrači koji više ne koriste svoje račune prestanu popunjavati ploče s rezultatima. + Zašto su rejtinzi veći u usporedbi s drugim web mjestima i organizacijama poput FIDE, USCF i ICC? + Najbolje je ne smatrati ocjene apsolutnim brojevima ili ih uspoređivati ​​s drugim organizacijama. Različite organizacije imaju različite razine igrača, različite sustave ocjenjivanja (Elo, Glicko, Glicko-2 ili izmijenjena verzija prethodno spomenutog). Ovi čimbenici mogu drastično utjecati na apsolutne brojke (ocjene). + +Najbolje je da o ocjenama razmišljate kao o \"relativnim\" brojkama (za razliku od \"apsolutnih\"): U grupi igrača, njihove relativne razlike u ocjenama pomoći će vam da procijenite tko će i koliko često pobjeđivati ​​/ izvlačiti / gubiti. Reći \"imam ocjenu X\" ne znači ništa, osim ako postoje drugi igrači s kojima se ta ocjena može usporediti. + Kako sakriti rejtinge dok traju partije? + Omogućite Zen-način u %1$s ili pritiskom na %2$s tijekom igre. + prikaži postavke + Izgubio sam igru ​​zbog prekida ili slabe veze. Mogu li dobiti svoje bodove nazad? + Nažalost, ne možemo vratiti bodove za partije izgubljene zbog kašnjenja ili prekida veze, bez obzira je li problem bio na vašem ili na našem kraju. Ovo drugo je vrlo rijetko. Također imajte na umu da kada se Lichess ponovno pokrene i izgubite na vrijeme zbog toga, prekidamo igru ​​kako bismo spriječili nepravedan gubitak. + Kako... + Uključiti ili isključiti notifikacije? + Pogledajte skočni prozor s informacijama o web mjestu + Lichess može po želji slati skočne obavijesti, na primjer kada ste na redu vi ili ste primili privatnu poruku. + +Kliknite ikonu lokota pored adrese lichess.org na URL traci vašeg preglednika. + +Zatim odaberite želite li dopustiti ili blokirati obavijesti od strane Lichess-a. diff --git a/translation/dest/faq/nn-NO.xml b/translation/dest/faq/nn-NO.xml index 294be17df3..2690789cfb 100644 --- a/translation/dest/faq/nn-NO.xml +++ b/translation/dest/faq/nn-NO.xml @@ -113,13 +113,13 @@ Sjå meir om dette trekket i %3$s for å få litt øving med det. Spørjeteiknet tyder at ratinga er mellombels. Grunnar til dette kan vere: Spelaren har så langt ikkje fullførd tilstrekkeleg mange rata parti mot %1$s i ratingkategorien. motspelarar av tilsvarande spelestyrke - Spelaren har ikkje spela tilstrekkeleg mange nylege parti. Avhengig av talet på parti du har spelt kan du etter omlag eit års inaktivitet få mellombels rating igjen. + Spelaren har ikkje spelt tilstrekkeleg mange nylege parti. Avhengig av talet på parti du har spela kan du etter omlag eit års inaktivitet få mellombels rating igjen. Det inneber at Glicko-2-avviket er større enn 110. Avviket er eit mål på den tiltrua systemet har til ratingtalet. Desto lågare avvik, desto meir stabil er ei rating. Korleis fungerer rangeringar og leiartavler? For å bli ført opp på %1$s må du: leiartavler for rating: - har spelt minst 30 rata parti under ei gjeven rating, - har spelt eit rata parti sist veke for denne ratinga, + har spelt minst 30 rata parti i ein gjeven ratingkategori, + har spelt eit rata parti i denne ratingkategorien sist veke, ha eit ratingsavvik lågare enn %1$s, i standardsjakk og lågare enn %2$s i variantar, vere på topp ti i denne ratingskategorien. Det andre kravet er utforma slik at spelarar som ikkje lengre brukar kontoen fell ut av leiartavlene. diff --git a/translation/dest/patron/es-ES.xml b/translation/dest/patron/es-ES.xml index e9e2a1e29e..dc5795ea73 100644 --- a/translation/dest/patron/es-ES.xml +++ b/translation/dest/patron/es-ES.xml @@ -15,11 +15,11 @@ Somos una organización sin ánimo de lucro porque creemos que todos deberíamos tener acceso a una plataforma de ajedrez de primera clase y gratuita. Lo hacemos posible gracias al apoyo de gente como tú. Si te gusta Lichess, por favor ¡considera apoyarnos donando y convirtiéndote en patrón! De por vida - Paga %s una vez. ¡Sé un Patrón de la Lichess para siempre! + Paga %s una vez. ¡Sé un patrón de Lichess para siempre! Patrón de Lichess de por vida ¿Hacer una donación adicional? Mensual - Facturación recurrente, renovando sus alas de Patrón cada mes. + Facturación recurrente, renovando tus alas de patrón cada mes. Una vez Una sola donación que te otorga las alas de patrón durante un mes. Otro @@ -49,7 +49,7 @@ Sin embargo, los patrones obtienen derecho a presumir de su nuevo icono de perfi Patrón de Lichess por un mes Patrón de Lichess por %s meses - Soportas lichess.org con %s al mes. + Apoyas a lichess.org con %s al mes. ¡Muchas gracias por tu apoyo! ¡Eres genial! Estado actual Próximo pago @@ -57,17 +57,17 @@ Sin embargo, los patrones obtienen derecho a presumir de su nuevo icono de perfi Haz una donación adicional ahora Actualizar Cambiar la cantidad mensual (%s) - cancela tu soporte + cancela tu apoyo %1$s o %2$s Decide cuanto vale Lichess para ti: Retira tu tarjeta de crédito y detén los pagos: - Ya no soporta Lichess + Ya no apoyas a Lichess Historial de pagos Pagado Ver otros Patrones de Lichess Fecha Cantidad - La transacción ha sido completada, y un recibo de tu donación ha sido enviado por correo electrónico. + La transacción ha sido completada y el recibo de la donación se te ha enviado por correo electrónico. Ahora tienes una cuenta de Patrón permanente. ¡Échale un vistazo a tu página de perfil! ¡Ahora eres un Patrón de Lichess de por vida! diff --git a/translation/dest/patron/nl-NL.xml b/translation/dest/patron/nl-NL.xml index 48705ccd45..97791d491e 100644 --- a/translation/dest/patron/nl-NL.xml +++ b/translation/dest/patron/nl-NL.xml @@ -9,9 +9,9 @@ Gratis schaken voor iedereen, voor altijd! Geen advertenties, geen abonnementen; maar open-source en passie. Hartelijk dank voor je donatie! - Je hebt een levenslang Patroon-account. Dat is super geweldig! + Je hebt een levenslang Patroon-account. Dat is geweldig! Je hebt een Patroon-account tot %s. - Indien niet vernieuwd, wordt je naar het standaard account teruggezet. + Indien niet vernieuwd, word je naar het standaard account teruggezet. Wij zijn een organisatie zonder winstoogmerk omdat wij van mening zijn dat iedereen toegang moet hebben tot een gratis schaakplatform van wereldklasse. We rekenen op de steun van mensen zoals u om dit mogelijk te maken. Als het gebruik van Lichess u bevalt, overweeg dan alstublieft om ons te steunen door te doneren en een Patroon te worden! Levenslang @@ -19,9 +19,9 @@ Levenslange Lichess Patroon Een extra donatie maken? Maandelijks - Terugkerende betaling, verlengt je beschermvleugels elke maand. + Terugkerende betaling, verlengt je Patroonvleugels elke maand. Eenmalig - Een enkele donatie die u de Beschermvleugels geeft voor één maand. + Een enkele donatie die u de Patroonvleugels geeft voor één maand. Overige Vul een USD bedrag in Creditcard @@ -32,16 +32,16 @@ Allereerst, krachtige servers. Daarnaast betalen we een voltijds ontwikkelaar: %s, de oprichter van Lichess. Zie de gedetailleerde kostenverdeling - Is Lichess echt een organisatie zonder winstoogmerk? - Ja, hier is de akte van oprichting (in Franse taal) + Is Lichess aantoonbaar een organisatie zonder winstoogmerk? + Ja, hier is de akte van oprichting (in het Frans) Kan ik mijn maandelijkse ondersteuning wijzigen of annuleren? Ja, op elk gewenst moment vanaf deze pagina. Of u kunt %s. - lichess ondersteuning contacten + contact opnemen met de Lichess helpdesk Andere vormen van donatie? We accepteren ook bankoverschrijvingen - En hier is ons bitcoin adres: %s - Zijn sommige functies gereserveerd voor Patronen? + En hier is ons bitcoinadres: %s + Zijn sommige functies enkel beschikbaar voor Patronen? Nee, omdat Lichess altijd gratis is, en voor iedereen. Dat is een belofte. Het enige verschil? Patronen krijgen een cool nieuw profielpictogram als waardering. Zie de gedetailleerde functievergelijking @@ -62,7 +62,7 @@ Het enige verschil? Patronen krijgen een cool nieuw profielpictogram als waarder Beslis wat Lichess voor jou waard is: Trek je creditcard terug en stop de betalingen: Lichess wordt niet langer gesteund - Betaalhistorie + Betaalgeschiedenis Betaald Andere Lichess Patronen bekijken Datum diff --git a/translation/dest/patron/sr-SP.xml b/translation/dest/patron/sr-SP.xml index 0e3f736dd1..0221f582f1 100644 --- a/translation/dest/patron/sr-SP.xml +++ b/translation/dest/patron/sr-SP.xml @@ -53,6 +53,7 @@ Следећа уплата Направи додатну донацију сада Промени месечну вредност (%s) + откажи твоју пордшку %1$s или %2$s Одлучи колико Личес теби вреди: Повуци своју кредитну картицу и обустави наплате: diff --git a/translation/dest/perfStat/nn-NO.xml b/translation/dest/perfStat/nn-NO.xml index ecf5799d13..2c469fd567 100644 --- a/translation/dest/perfStat/nn-NO.xml +++ b/translation/dest/perfStat/nn-NO.xml @@ -16,7 +16,7 @@ Sigrar Tap Fråkoplingar - For få spelte parti + For få spela parti Høgaste rating: %s Lågaste rating: %s frå %1$s til %2$s @@ -26,7 +26,7 @@ Noverande rekke: %s Beste sigrar Verste tap - Parti spelt på rad + Parti spela på rad Mindre enn ein time mellom partia Lengste speletid no diff --git a/translation/dest/preferences/az-AZ.xml b/translation/dest/preferences/az-AZ.xml index 209080a389..eafe2a9304 100644 --- a/translation/dest/preferences/az-AZ.xml +++ b/translation/dest/preferences/az-AZ.xml @@ -6,7 +6,7 @@ Material fərqi Lövhə xəbərdarlıqları (son gediş və şah vermə) Fiqurun gedə biləcəyi xanalar (qanuni gediş və öngedişlər) - Taxta kordinatları + Lövhə koordinantları (A-H, 1-8) Oyun zamanı notasiyanı göstər Şahmat notasiyası Şahmat fiqur simvolu @@ -15,10 +15,10 @@ Lövhə ölçüləndirmə tutacağını göstər Yalnız başlanğıc pozisiyada Gözübağlı şahmat (görünməz fiqurlar) - Şahmat saat - Son 10 saniyə - Qalan zaman < 10 saniyə - Yaşıl üfüqi tərəqqi bar + Şahmat saatı + Saniyənin onda biri + 10 saniyədən az vaxt qalanda + Üfüqi yaşıl inkişaf sətri Zaman azaldığında səslə xəbərdarlıq Vaxt ver Oyun seçimləri @@ -27,12 +27,12 @@ Fiquru sürüşdürərək Hər ikisi Öngedişlər (oyun növbəsi rəqibdə olarkən oyna) - Geri Alma (rəqib razılığı ilə) + Geri qaytarma (rəqib razılığı ilə) Yalnız reytinqsiz oyunlarda Avtomatik Vəzirə çıx - Ön hücum edərkən + Ön gediş edərkən Üç dəfə təkrarlanan oyunda avtomatik heç-heçə təklif et - Qalan zaman < 30 saniyə + Qalan vaxt 30 saniyədən az olanda Gediş təsdiqi Yazışmalı oyunlar Yazışmalı və vaxtsız @@ -43,5 +43,5 @@ Gedişləri klaviatura ilə daxil et Etibarlı gedişlər üçün oxları göstər Məğlub olduqda və ya heç-heçə etdikdə \"Yaxşı oyun idi, yaxşı oynadın\" deyin - Seçimləriniz qeyd edildi. + Tərcihləriniz saxlanıldı. diff --git a/translation/dest/preferences/es-ES.xml b/translation/dest/preferences/es-ES.xml index 63b5764caa..606572f9a8 100644 --- a/translation/dest/preferences/es-ES.xml +++ b/translation/dest/preferences/es-ES.xml @@ -11,13 +11,13 @@ Notación de los movimientos Símbolo de la pieza Inicial (en inglés) de la pieza (K, Q, R, B, N) - Modo Zen + Modo Zen Mostrar el control de tamaño del tablero Sólo en posición inicial Ajedrez a ciegas (piezas invisibles) Reloj de ajedrez Décimas de segundo - Cuando queden menos de 10 segundos + Cuando queden menos de 10 segundos Barras de progreso horizontales verdes Alerta cuando reste poco tiempo Dar más tiempo diff --git a/translation/dest/preferences/hr-HR.xml b/translation/dest/preferences/hr-HR.xml index 72b0006c4b..7c71203056 100644 --- a/translation/dest/preferences/hr-HR.xml +++ b/translation/dest/preferences/hr-HR.xml @@ -11,17 +11,17 @@ Oznaka poteza Simbol šahovske figure Slovo (K, Q, R, B, N) - Zen način + Zen način Prikaži ručicu za promjenu veličine ploče Samo na početku partije Šah na slijepo (nevidljive figure) Sat Desetinke sekundi - Kad je ostalo manje od 10 sekundi + Kad je ostalo manje od 10 sekundi Vodoravna zelena linija napretka Zvuk kada je vrijeme kritično Daj više vremena - Način igre + Način igre Kako želiš pomicati figure? Klikom na dva polja Povlačenjem figure @@ -41,5 +41,7 @@ Pomakni kralja dvije kocke Pomakni kralja na kulu Omogući unošenje poteza tipkovnicom + Crtaj strelice za planiranje budućih poteza + Reci \"Dobra partija, odlićno odigrano\" kad izgubiš ili odigraš remi Tvoje promjene su spremljene. diff --git a/translation/dest/preferences/id-ID.xml b/translation/dest/preferences/id-ID.xml index 06a9a0e1d3..acf5ea43cc 100644 --- a/translation/dest/preferences/id-ID.xml +++ b/translation/dest/preferences/id-ID.xml @@ -11,17 +11,17 @@ Catatan langkah Simbol bidak catur Huruf (K, Q, R, B, N) - Moda Zen + Moda Zen Tampilkan pengubah ukuran papan catur Hanya di posisi awal Catur buta (buah catur disembunyikan) Jam catur Sepersepuluh detik - Ketika waktu tersisa < 10 detik + Ketika waktu tersisa < 10 detik Indikator horisontal perkembangan warna hijau Bersuara ketika waktu hampir habis Berikan waktu lebih - Lingkungan permainan + Lingkungan permainan Bagaimana Anda melangkahkan bidak? Klik dua kotak Seret sebuah bidak @@ -41,5 +41,6 @@ Memindahkan raja dua kotak Memindahkan raja ke benteng Melangkah dengan menggunakan keyboard + Ucapkan \"Good game, well played\" apabila kalah atau seri Preferensi telah disimpan. diff --git a/translation/dest/preferences/lv-LV.xml b/translation/dest/preferences/lv-LV.xml index 2fb62e0c42..42f16bdce4 100644 --- a/translation/dest/preferences/lv-LV.xml +++ b/translation/dest/preferences/lv-LV.xml @@ -11,31 +11,31 @@ Gājienu notācija Šaha figūras simbols Burts (K, D, T, L, Z) - Zen režīms + Zen režīms Rādīt galdiņa izmēra maiņas rīku Tikai sākotnējajā pozīcijā Aklais šahs (ar neredzamām figūrām) Šaha pulkstenis Sekunžu desmitdaļas - Ja atlicis < 10 sekundēm + Ja atlicis < 10 sekundēm Zaļā horizontālā izpildes josla Signalizēt, kad laika pavisam maz Dot vairāk laika - Spēles uzvedība - Kā pārvietosi figūras? - Klikšķini uz diviem lauciņiem - Velc figūru + Spēles uzvedība + Kā pārvietot figūras? + Klikšķinot uz diviem lauciņiem + Velkot figūru Jebkurā veidā - Priekšgājieni (izdarīt gājienu kamēr pretinieks domā) + Priekšgājieni (izdarīti pretinieka gājienā) Gājienu atsaukšana (ar pretinieka piekrišanu) Tikai nevērtētajās spēlēs Automātiski pārvērst par Dāmu - Ja priekšgājiens + Tikai priekšgājienos Automātiski pieprasīt trīskāršās atkārtošanās neizšķirtu Ja atlicis < 30 sekundēm Gājiena apstiprināšana Korespondencšaha spēlēs - Korespondencšahs un bezgalīgs + Korespondencšaha un bezgalīgajās spēlēs Apstiprināt padošanos un neizšķirta piedāvājumus Rokādes metode Pārvietot karali par diviem lauciņiem diff --git a/translation/dest/preferences/tr-TR.xml b/translation/dest/preferences/tr-TR.xml index 449c6be44e..1cdbb787c6 100644 --- a/translation/dest/preferences/tr-TR.xml +++ b/translation/dest/preferences/tr-TR.xml @@ -3,10 +3,10 @@ Seçenekler Oyun görünümü Hamle animasyonu - Malzeme farkı + Taş farkı Tahta uyarıları (son hamle ve şah çekme) Taşın gidebileceği kareler (geçerli hamleler ve ön hamleler) - Tahta kordinatları (A-H, 1-8) + Tahta koordinatları (A-H, 1-8) Oyun sırasında notasyonu göster Notasyon tut Satranç taşı sembolü @@ -14,34 +14,34 @@ Sade görünüm Tahta büyüklüğünü ayarlama kolunu göster Sadece oyunun başında - Körleme satranç (taşlar gözükmez) + Körleme satranç (taşlar görünmez) Satranç saati Saniyenin Onda Biri - Kalan zaman 10 saniye ise + Kalan zaman 10 saniyeden az ise Yeşil yatay ilerleme çubuğu Zaman azaldığında sesle uyarı - Daha fazla süre ver - Oyun Tercihleri - Taşları nasıl hareket ettireceksin? + Fazladan süre ver + Oyun tercihleri + Taşları nasıl hareket ettirirsin? İki kareye tıklayarak - Taşı sürükle - İkiside + Taşı sürükleyerek + İkisi de Ön hamleler (hamle sırası rakipteyken oynama) Geri Alma (rakibin onayıyla) Sadece puansız oyunlarda Geçer piyonu otomatik olarak Vezir\'e terfi et Ön hamlelerde Üçlü tekrarda otomatik olarak beraberlik teklif et - Kalan zaman 30 saniye ise + Kalan zaman 30 saniyeden az ise Hamleyi onayla - Yazışmalı oyunlarda + Yazışmalı oyunlar Yazışmalı ve sınırsız Oyundan çekilme ve beraberlik tekliflerini onayla - Rok atma tarzı + Rok atma yöntemi Şahı iki kare sürerek - Şahı kalenin üstüne oynama + Şahı kalenin üstüne getirerek Hamleleri klavye ile gir - Okları geçerli hamlelere kaydır + Geçerli hamlelere ok çiz Beraberlik veya yenilgiyle biten maçların sonunda \"İyi oyundu, güzel oynadın\" mesajı gönder Tercihleriniz kaydedildi. diff --git a/translation/dest/preferences/uz-UZ.xml b/translation/dest/preferences/uz-UZ.xml index 4fe639a984..302066edcd 100644 --- a/translation/dest/preferences/uz-UZ.xml +++ b/translation/dest/preferences/uz-UZ.xml @@ -11,17 +11,17 @@ Yurishlarni qayd qilib borish Sipoh belgisi Harflar (K, Q, R, B, N) - Zen holati (faqat doska va soat) + Zen holati (faqat doska va soat) Doskani o\'lchamini o\'gartiruvchi uskunani namoyishi Faqat boshlang\'ich holatda Ko\'zlar berklitilgan shahmat (sipohlar ko\'rinmas holda) Shaxmat Soati 10 lab sekundlar - Qachonki vaqt tugashiga < 10 sekundlar bo\'lsa + Qachonki vaqt tugashiga < 10 sekundlar bo\'lsa Gorizantal yashil rangdagi jarayon indikatori Vaqt kritik holatga kelganda ovoz ovoz berish Takroran berish - O\'yindagi boshqaruv + O\'yin hatti harakatlari Sipohlarni qanday yurasiz? Ikkita kvadratni bosing Sipohni suring @@ -41,5 +41,7 @@ Qirolni ikki katakka yuring Qirolni to\'ra tomonga yuring Yurish klaviatura orqali amalga oshiriladi + Ishonchli yurishlarga oʻqlarni torting + Magʻlubiyatga uchraganingizda \"Yaxshi oʻyin, yaxshi oʻnaldi\" deb ayting Sizning sozlashlaringiz saqlandi. diff --git a/translation/dest/puzzle/es-ES.xml b/translation/dest/puzzle/es-ES.xml index 61f4c4d18d..9fc6679316 100644 --- a/translation/dest/puzzle/es-ES.xml +++ b/translation/dest/puzzle/es-ES.xml @@ -1,27 +1,27 @@ - Ejercicios + Rompecabezas Temas de rompecabezas Recomendado Fases - Temas + Motivos Avanzado Duraciones Mates Objetivos Origen Movimientos especiales - ¿Te gusto este rompecabezas? + ¿Te ha gustado este rompecabezas? ¡Vota para cargar el siguiente! Tu puntuación en los rompecabezas: %s Encuentra el mejor movimiento para las blancas. Encuentra el mejor movimiento para las negras. Para conseguir rompecabezas personalizados: - Rompecabezas %s - ejercicio diario + Puzzle%s + Rompecabezas del día Clic para resolver Buen movimiento - ¡Encontraste el mejor movimiento! + ¡El mejor movimiento! Continúa… ¡Éxito! ¡Rompecabezas terminado! @@ -44,8 +44,8 @@ Ejemplo Añadir otro tema Ir al siguiente rompecabezas inmediatamente - Panel de rompecabezas - Áreas de mejoramiento + Panel de puzzles + Áreas de mejora Fortalezas Historial de rompecabezas resuelto diff --git a/translation/dest/puzzle/hr-HR.xml b/translation/dest/puzzle/hr-HR.xml index 92795f0047..36856ddf06 100644 --- a/translation/dest/puzzle/hr-HR.xml +++ b/translation/dest/puzzle/hr-HR.xml @@ -1,5 +1,54 @@ - Zagonetke + Zadaci + Kategorije zadataka Preporučeno + Faze + Motivi + Napredno + Duljine + Matevi + Ciljevi + Podrijetlo + Specifični potezi + Sviđa li ti se ovaj zadatak? + Ocijeni i prijeđi na sljedeći zadatak! + Tvoj rejting zadataka %s + Pronađi najbolji potez za bijelog. + Pronađi najbolji potez za crnog. + Za personalizirane zadatke: + Zadatak %s + Zadatak dana + Klikni za rješenje + Dobar potez + Najbolji potez! + Nastavi… + Uspješno obavljeno! + Zadatak riješen! + Netočan odgovor! + Pokušaj nešto drugo. + Rejting: %s + skriven + + Odigrano %s puta + Odigrano %s puta + Odigrano %s puta + + Iz partije %s + Nastavi sa zadacima + Težina zadataka + Srednje + Lakše + Najlakše + Teže + Najteže + Primjer + Dodaj novu kategoriju + Automatski učitaj nove zadatke + Sučelje zadataka + Nedostaci + Prednosti + Povijest zadataka + riješeno + neuspješno diff --git a/translation/dest/puzzle/nl-NL.xml b/translation/dest/puzzle/nl-NL.xml index 461100f6be..49ac2755f4 100644 --- a/translation/dest/puzzle/nl-NL.xml +++ b/translation/dest/puzzle/nl-NL.xml @@ -45,6 +45,8 @@ Voeg nog een thema toe Direct door naar volgende puzzel Puzzel-dashboard + Verbeterpunten + Sterke punten Puzzelscore opgelost niet opgelost diff --git a/translation/dest/puzzle/nn-NO.xml b/translation/dest/puzzle/nn-NO.xml index 7b61801459..809d37174f 100644 --- a/translation/dest/puzzle/nn-NO.xml +++ b/translation/dest/puzzle/nn-NO.xml @@ -9,6 +9,7 @@ Lengder Mattar Mål + Opphav Spesialtrekk Likte du denne oppgåva? Stem for å laste den neste! @@ -29,8 +30,8 @@ Rating: %s løynd - Spelt %s gong - Spelt %s gonger + Spela %s gong + Spela %s gonger Frå parti %s Hald fram å øva @@ -48,5 +49,5 @@ Styrkeområde Oppgåvehistorikk løyst - feila + uløyst diff --git a/translation/dest/puzzle/ru-RU.xml b/translation/dest/puzzle/ru-RU.xml index 2e7c625312..7b8c642e92 100644 --- a/translation/dest/puzzle/ru-RU.xml +++ b/translation/dest/puzzle/ru-RU.xml @@ -46,8 +46,8 @@ Пример Добавить другой мотив Сразу перейти к следующей задаче - Страница задач - Области улучшения + Панель задач + Слабые стороны Сильные стороны История задач решённые diff --git a/translation/dest/puzzle/uz-UZ.xml b/translation/dest/puzzle/uz-UZ.xml index 14f0a251d6..d4090f3915 100644 --- a/translation/dest/puzzle/uz-UZ.xml +++ b/translation/dest/puzzle/uz-UZ.xml @@ -1,4 +1,53 @@ + Boshqotirmalar + Boshqotirma mavzulari + Tavsiya etilgan + Bosqichlar + Sabablar + Yuqori mavqeili + Uzunliklar + Motlar + Maqsadlar + Kelib chiqish + Maxsus yurishlar + Ushbu boshqotirma yoqdimi? + Navbatdagi bittasini oʻqish uchun baholang! + Sizning boshqotirmalardagi reytingingiz: %s + Oqlar uchun eng yaxshi yurishni toping. + Qoralar uchun eng yaxshi yurishni toping. + Shaxsiy jumboqlarni yaratish uchun: + %s boshqotirma + Kun boshqotirmasi + Yechish uchun bosing + Yaxshi yurish + Zo\'r yurish! + Harakatni davom eting… + Muvaffaqiyat! + Boshqotirma tugallandi! + Bu yurish emas! + Yana urinib koʻring. + Reyting: %s + berkitilgan + + %s vaqt o\'ynaldi + %s marta o\'ynaldi + + %s o\'yinidan + Shug\'ullanishni davom eting + Qiyin daraja + Odatiy + Onsonroq + Eng Oson + Qiyinroq + Eng Qiyin + Masalan + Boshqa mavzu kiriting + Keyingi boshqotirmaga birdan oʻtish + Boshqotirma uskunalar doskasi + Rivojlanish maydonlari Kuchli tomonlari + Boshqotirma tarixi + yechildi + xatolik diff --git a/translation/dest/puzzle/zh-CN.xml b/translation/dest/puzzle/zh-CN.xml index a1a83ee126..36cea9f04b 100644 --- a/translation/dest/puzzle/zh-CN.xml +++ b/translation/dest/puzzle/zh-CN.xml @@ -1,12 +1,34 @@ 训练题 + 训练主题 我们推荐: 阶段 主题 高等 - 你喜欢了这个训练题吗? - 继续…… + 长度 + 杀王 + 目标 + 你喜欢这道训练题吗? + 投票以加载下一题 + 你的解题积分:%s + 找出白方的最佳着法 + 找出黑方的最佳着法 + 获取个性化训练题 + %s号题 + 每日一题 + 点击解题 + 好棋 + 最佳着法! + 请继续…… + 解题成功! + 解题完成 + 不是最佳着法 + 积分:%s + 隐藏 + + 已被尝试%s次 + 来自 %s 号赛 继续训练 难度 @@ -16,5 +38,10 @@ 更难 最难 例子 + 添加新的主题 一解决训练题就马上转到下一个 + 强度 + 解题历史 + 已解决 + 失败 diff --git a/translation/dest/puzzleTheme/ca-ES.xml b/translation/dest/puzzleTheme/ca-ES.xml index eef2ea2d4e..d426f9c41f 100644 --- a/translation/dest/puzzleTheme/ca-ES.xml +++ b/translation/dest/puzzleTheme/ca-ES.xml @@ -4,6 +4,10 @@ Un peó a punt de coronar o amenaçant la coronació és la tàctica clau. Avantatge Aprofita l\'oportunitat per agafar avantatge definitiva. (200cp ≤ eval ≤ 600cp) + Mat d\'Anastasia + Un cavall i una torre o una dama es coordinen per atrapar el rei de l\'oponent entre una cantonada del tauler i una peça aliada. + Mat àrab + Un cavall i una torre es coordinen per atrapar el rei de l\'oponent en una cantonada del tauler. Atacant f2 o f7 Un atac centrat en el peó de f2 o f7, com a l\'obertura de l\'atac Fegatello. Atracció @@ -12,40 +16,85 @@ Fes escac i mat al rei a la primera fila, quan està atrapat per les seves pròpies peces. Final d’alfils Un final d\'alfils i peons. + Mat de Boden + Dos alfils atacant en diagonals que es creuen fan mat a un rei que queda atrapat entre peces amigues. Enrocant Assegura el rei, i prepara la torre per l\'atac. Captura el defensor Menjar una peça que és vital per defensar una altra, fent que es pugui menjar la peça que ara ja no està defensada. Destrucció Veure l\'error de l\'adversari per a obtenir un gran avantatge (aval ≥ 600cp) + Mat dels dos alfils + Dos alfils atacant en diagonals adjacents fan mat a un rei que queda obstruït per peces amigues. + Mat de Cozio + Una reina fa mat a un rei adjacent que té les dues caselles adjacents obstruïdes per peces amigues. Igualtat + Remunta des d\'una posició perduda i assegura un empat o una posició balancejada. (eval ≤ 200cp) Atac pel flan de rei + Un atac al rei de l\'oponent, després de que hagi enrocat en curt. + Alliberament + Una jugada, sovint amb tempo, que allibera una casella, fila o diagonal seguit d\'una idea tàctica. + Jugada defensiva + Una jugada precisa o seqüència de jugades necessàries per evitar perdre material o un altre avantatge. + Desviació + Un moviment que distrau una peça de l\'oponent per realitzar una altra tasca, com protegir una casella. A vegades també anomenat \"sobrecàrrega\". Atac a la descoberta + Moure una peça que prèviament bloquejava un atac a llarg distància d\'una altra peça, com per exemple un cavall que surt de davant d\'una torre. + Doble escac + Posar en escac amb dues peces a la vegada, com a resultat d\'un atac descobert on tant la peça que s\'ha mogut com la peça descoberta ataquen el rei de l\'oponent. Final + Una tàctica durant la última fase del joc. + Una tàctica que involucra la regla de captura de pas, on un peó pot capturar el peó d\'un oponent que l\'ha passat utilitzant el seu moviment inicial de dues caselles. + Rei exposat + Una tàctica que involucra un rei amb alguns defensors al seu voltant, sovint acabant amb escac i mat. Forquilla + Un moviment on la peça moguda ataca dos peces de l\'oponent a la vegada. Peça penjant + Una tàctica que involucra una peça de l\'oponent que no està suficientment defensada i que es pot capturar. + Mat de la cantonada + Escac i mat amb una torre, un cavall i un peó junt amb un peó enemic que limita l\'escapada del rei enemic. + Interferència + Moure una peça entre dues peces de l\'oponent que deixa una o dues peces enemigues indefenses, com un cavall en una casella defensada entre dues torres. Intermèdia + En lloc de jugar la jugada esperada, interposar un moviment previ que genera un perill imminent al que l\'oponent ha de respondre. També és conegut com \"Zwischenzug\" o \"Jugada intermèdia\". Final de cavalls + Un final amb només cavalls i peons. Problema llarg + Tres jugades per guanyar. + Partides de Mestre + Problemes de partides jugades per jugadors amb títol. + Partides Mestre vs Mestre + Problemes de partides entre dos jugadors amb títol. Mat + Guanya la partida amb estil. Mat en 1 Fer escac i mat en una jugada. Mat en 2 + Fer escac i mat en dues jugades. Mat en 3 + Fer escac i mat en tres jugades. Mat en 4 + Fer escac i mat en quatre jugades. Mat en 5 o més + Troba una seqüència llarga de mat. Mig joc Una maniobra tàctica a la segona fase de la partida. Problema d\'una sola jugada + Un problema que és només d\'un moviment. Obertura + Una tàctica durant la primera fase del joc. Final de peons Final amb només peons. Clavada + Una tàctica que involucra clavades, on una peça no es pot moure sense revelar un atac a una altra peça amb més valor. Promoció + Un peó que promociona o que amenaça a promocionar és clau de la tàctica. Final de dames + Un final només amb reines i peons. Dama i Torre Un final amb només dames, torres i peons. Atac pel flanc de dama + Un atac al rei de l\'oponent, després de que hagi enrocat en llarg. Sacrifici Problema curt Guanyar en dues jugades. diff --git a/translation/dest/puzzleTheme/es-ES.xml b/translation/dest/puzzleTheme/es-ES.xml index 2f7dab2599..92ae28d0e7 100644 --- a/translation/dest/puzzleTheme/es-ES.xml +++ b/translation/dest/puzzleTheme/es-ES.xml @@ -88,7 +88,7 @@ Clavada Una táctica donde una pieza no puede moverse sin revelar un ataque a una pieza de mayor valor. Promoción - Un peón que promueve o amenaza con promover es clave para la táctica. + Un peón que se promociona o amenaza con promocionarse es clave para la táctica. Final de damas Un final solo con damas y peones. Final de dama y torre diff --git a/translation/dest/puzzleTheme/hr-HR.xml b/translation/dest/puzzleTheme/hr-HR.xml index 3ea04e700d..79db074400 100644 --- a/translation/dest/puzzleTheme/hr-HR.xml +++ b/translation/dest/puzzleTheme/hr-HR.xml @@ -1,2 +1,124 @@ - + + Pješak napreduje + Pješak u postupku ili prijetnji promaknućem je ključan za taktiku. + Prednost + Iskoristi priliku i pridobij odlučujuču prednost. (200cp ≤ eval ≤ 600cp) + Anastazijin mat + Skakač i top ili dama udružuju se kako bi uhvatili protivničkog kralja u zamku između ruba ploče s jedne i njegove figure s druge strane. + Arapski mat + Skakač i top udružuju snage kako bi zarobili suparničkog kralja u uglu igraće ploče. + Napad na f2 ili f7 polje + Napad na f2 ili f7 pješaka kao što je napad lovcem popularno nazvan \"fried liver opening\". + Privlačenje + Razmjena ili žrtva koja potiče ili forsira protivničke figure u poziciju koja omogućuje taktičke poteze koji donose prednost. + Mat na zadnjem redu + Top ili dama matiraju kralja koji se nalazi na njegovom prvom redu (odnosno osmom iz perspektive protivnika) te je zagrađen svojim figurama. + Lovčeva završnica + Završnica u kojoj sudjeluju samo lovci i pješaci. + Bodenov mat + Dva lovca napadaju po unakrsnim dijagonalama i matiraju kralja okruženog njegovim figurama. + Rokada + Dovedi svog kralja na sigurno i postavi svog topa za napad. + Eliminiraj obranu + Eliminacijom figure koja brani ili je neizravno uključena u obranu druge figure omogućujete uzimanje figure koja ostaje bez obrane. + Uništavanje + Uoči protivničku grešku te pridobij golemu prednost. (eval ≥ 600cp) + Mat lovačkim parom + Lovački par zadaje mat na susjednim dijagonalama kralju zarobljenom iza prijateljske figure. + Lastin mat + Kraljica zadaje mat dodirujuči protivničkog kralja po dijagonali. Kraljeva jedina polja za bijeg zauzeta su njegovim figurama. + Izjednačenje + Pronađi potez koji te dovodi iz gubitničke u podjednaku poziciju. (eval ≤ 200cp) + Napad na kraljevoj strani + Napad na protivničkog kralja nakon što je protivnik odigrao malu rokadu. + Čiščenje + Potez (najčešće s tempom) koji oslobađa polje, red ili dijagonalu za nadolazeću taktičku ideju. + Obrambeni potez + Određeni potez ili slijed poteza koje je potrebno odigrati za zadržavanje materijala ili pozicije. + Odvraćanje + Potez koji odvraća protivničku figuru od dužnosti koju obavlja (kao što je kontroliranje značajnog polja). Ova taktika se također zove i \"preopterećenje\". + Otkriveni napad + Napad izvršen kad se figura koja blokira drugu figuru (kraljicu, lovca ili topa) skloni sa određene dijagonale, reda ili stupca. + Dvostruki šah + Šah kojeg daju dvije figure istovremeno kao rezultat otkrivenog šaha. + Završnica + Taktički potezi u završnici. + Taktika koja uključuje pravilo \"en passant\" po kojem pješak uzima protivničkog pješaka koji ga preskače koristeći inicijalno otvaranje pješaka za dva polja. + Golišavi kralj + Taktika koja uključuje kralja okruženim nekolicinom obrambenih figura što često rezultira matom. + Rašlje + Situacija u šahovskoj partiji kad jedna figura napadne dvije ili više protivničkih. + Viseća figura + Taktika koja uključuje neobranjenu ili nedovoljno obranjenu protivničku figuru besplatnu za uzimanje. + Kuka-mat + U kuka-matu sudjeluju top, skakač i pješak te jedan protivnički pješak koji onemogućuje bijeg svom kralju. + Podmetanje + Pomicanje figure između dvije protivničke figure pritom ih napadajući. Kao rezultat protivnik nije u mogućnosti obraniti obe figure. + Međupotez + Potez koji se igra prije očekivanog poteza koji predstavlja direktnu prijetnju na koju protivnik mora odgovoriti. + Skakačeva završnica + Završnica u kojoj sudjeluju samo skakači i pješaci. + Dugi zadatak + Tri poteza za pobjedu. + Majstorske partije + Zadaci iz partija odigranih od strane igrača s titulom. + Majstor protiv majstora + Zadaci iz partija odigranih između igrača s titulama. + Mat + Pobijedi sa stilom. + Mat u 1 + Matiraj protivnika u jednom potezu. + Mat u 2 + Matiraj protivnika u dva poteza. + Mat u 3 + Matiraj protivnika u tri poteza. + Mat u 4 + Matiraj protivnika u četiri poteza. + Mat u 5 ili više + Pronađi slijed koji uključuje više od četiri poteza i dovodi do mata. + Središnjica + Taktički potezi u središnjici. + Jednopotezni zadatak + Zadatak koji se sastoji od samo jednog poteza. + Otvaranje + Taktički potezi u otvaranju. + Pješačka završnica + Završnica koja uključuje samo pješake. + Svezivanje + Taktika koja uključuje protivničku figuru koja je vezana za kralja ili drugu figuru veče vrijednosti. + Unapređenje + Pješak u postupku ili prijetnji promaknućem je ključan za taktiku. + Kraljičina završnica + Završnica u kojoj sudjeluju samo kraljica i pješaci. + Kraljica i top + Završnica u kojoj sudjeluju isključivo kraljica, top i pješaci. + Napad na kraljičinu stranu + Napad na protivničkog kralja nakon što je protivnik odigrao veliku rokadu. + Tihi potez + Potez koji ne uzima protivničku figuru ni ne stavlja protivničkog kralja u šah ali zato priprema neizbježnu prijetnju za nadolazeće poteze. + Topovska završnica + Završnica u kojoj sudjeluju samo topovi i pješaci. + Žrtva + Taktika koja uključuje žrtvu koja rezultira stjecanjem prednosti neposredno nakon forsiranog slijeda poteza. + Kratki zadatak + Dva poteza za pobjedu. + Ražanj + Napadom figura sa linijskim djelovanjem (dama, top ili lovac) na jednu figuru (npr. kralja), napadnuta se figura prisiljava na povlačenje što vodi gubitku figure, koja se nalazi na istoj liniji kao i napadnuta figura. + Ugušeni mat + Mat kojeg skakač vrši nad kraljem kojemu njegove figure onemogućuju bijeg. + Super-velemajstorske igre + Zadaci iz partija najboljih svjetskih velemajstora. + Zarobljena figura + Figura koja ne može pobjeći uzimanju. + Potpromaknuće + Promaknuće u skakača, lovca ili topa. + Iznimno duga puzla + Slijed od četiri ili više poteza nužan za pobjedu. + Rendgenski napad + Figura napada ili brani polje kroz protivničku figuru. + Iznuđeni potez (Zugzwang) + Protivnik je prisiljen odigrati potez koji mu pogoršava poziciju. + Pomalo svega + Kao i u pravim partijama - budi spreman i očekuj bilo što! Kombinacija svih navedenih vrsta zadataka. + diff --git a/translation/dest/puzzleTheme/nn-NO.xml b/translation/dest/puzzleTheme/nn-NO.xml index ffd7f0ac52..4c78341f3b 100644 --- a/translation/dest/puzzleTheme/nn-NO.xml +++ b/translation/dest/puzzleTheme/nn-NO.xml @@ -61,6 +61,10 @@ Sluttspel med berre springarar og bønder. Lang taktikkoppgåve Vinst i tre trekk. + Meisterparti + Sjakknøtter frå parti med spelarar som har sjakktittel. + Meister mot meister-parti + Sjakknøtter frå parti mellom to spelarar som har sjakktittel. Matt Vinn partiet med stil. Matt i eitt trekk diff --git a/translation/dest/puzzleTheme/ru-RU.xml b/translation/dest/puzzleTheme/ru-RU.xml index 5f6773141a..af51943251 100644 --- a/translation/dest/puzzleTheme/ru-RU.xml +++ b/translation/dest/puzzleTheme/ru-RU.xml @@ -24,6 +24,10 @@ Избавьтесь от фигуры, защищающей другую фигуру, с последующим взятием фигуры, оставшейся без защиты. Разгром Используйте зевок противника для получения сокрушительного преимущества. (600 и более сантипешек) + Мат двумя слонами + Два слона атакующей стороны на ставят мат на пересекающихся диагоналях, в то время как король противника стеснён его же фигурой. + Мат «ласточкин хвост» + Мат ферзём стоящему рядом королю противника, единственные два поля отхода которого занимают его же фигуры. Уравнение Отыграйтесь из проигранной позиции: сведите партию вничью или получите позиционное равенство. (менее 200 сантипешек) Атака на королевском фланге diff --git a/translation/dest/puzzleTheme/sl-SI.xml b/translation/dest/puzzleTheme/sl-SI.xml index 19717b7a0a..424564678c 100644 --- a/translation/dest/puzzleTheme/sl-SI.xml +++ b/translation/dest/puzzleTheme/sl-SI.xml @@ -1,5 +1,12 @@ + Napredovani kmet + Kmet pred promocijo ali s pretnjo po promociji je ključna v taktiki. + Prednost + Izkoristite priložnost in si pridobite odločilno prednost (ocena pozicije med 200 in 600 stotinov kmeta) + Anastasijin mat + Skakač in trnjava ali dama sodelujejo, da ujamejo nasprotnega kralja ob rob šahovnice in prijateljsko figuro v past. + Arabski mat Igre mojstrov Igre, ki so jih odigrali igralci z nazivom. Igre mojster proti mojstru diff --git a/translation/dest/puzzleTheme/uz-UZ.xml b/translation/dest/puzzleTheme/uz-UZ.xml index 3ea04e700d..9af37473f3 100644 --- a/translation/dest/puzzleTheme/uz-UZ.xml +++ b/translation/dest/puzzleTheme/uz-UZ.xml @@ -1,2 +1,6 @@ - + + Arabcha mot + f2 yoki f7 hujum + Jozibasi + diff --git a/translation/dest/puzzleTheme/zh-CN.xml b/translation/dest/puzzleTheme/zh-CN.xml index 3ea04e700d..f865dd5340 100644 --- a/translation/dest/puzzleTheme/zh-CN.xml +++ b/translation/dest/puzzleTheme/zh-CN.xml @@ -1,2 +1,87 @@ - + + 高兵 + 兵升变或威胁升变是战术的关键 + 优势 + 抓住你获得决定性优势的机会。(200cp ≤ 估值 ≤ 600cp) + 阿纳斯塔西亚杀法(车马杀王) + 马与车或者后配合将对方的王将死在被对方棋子卡住的角落 + 阿拉伯杀法(车马杀王) + 马与车配合将杀角落位置对方的王 + 进攻f2或f7 + 进攻的焦点集中在f2或f7兵,像在双马防御煎肝进攻中一样 + 引入 + 以兑子或弃子吸引或迫使对方的棋子移动到后续可实施战术的格子 + 底线杀王 + 在底线将杀被对方棋子困住的王 + 象残局 + 象兵残局 + 波登杀法 + 双象在交错的斜线上将杀被对方子力阻挡的王 + 王车易位 + 将王转移到安全的地方,将车投入进攻 + 双象杀王 + 双象在交错的斜线上将杀被对方子力阻挡的王 + 燕尾杀法 + 后贴面杀,王唯一能逃跑的两个格子被自己的棋子阻挡 + 均势 + 从要输棋的局面回到和棋或者均势(eval ≤ 200cp) + 王翼进攻 + 在对方短易位后进攻对方的王 + 将对方的棋子从另一个它负责的任务中转移出来的一步棋,例如防守一个关键格。有时候也叫“过载”。 + 闪击 + 双将 + 两个棋子同时将军,作为一种闪击,走动的棋子与后面揭露出来的棋子同时攻击对方的王 + 残局 + 暴露的王 + 王的周围只有很少的防守棋子时的战术,往往导致杀棋 + 走一步棋使走动的棋子同时攻击对方的两个棋子 + 得子 + 车杀棋 + 用车、马、兵杀棋,对方的兵限制王逃跑 + 马残局 + 长谜题 + 三步胜 + 大师对局 + 大师与大师对局 + 杀王 + 一步杀 + 一步之内实现杀棋 + 两步杀 + 两步之内实现杀棋 + 三步杀 + 三步之内实现杀棋 + 四步杀 + 四步之内实现杀棋 + 五步或更多步杀 + 指出一长套杀棋着法 + 中局 + 对局第二阶段的战术 + 一步棋谜题 + 只有一步棋的谜题 + 开局 + 对局第一阶段的战术 + 王兵残局 + 只有兵的残局 + 牵制 + 升变 + 兵升变或威胁升变是战术的关键 + 后残局 + 只有后和兵的残局 + 后和车 + 只有后、车、兵的残局 + 后翼进攻 + 在对方长易位后进攻对方的王 + 一步棋没有将军或捉子,但确实为后续准备了一个不可避免的威胁。 + 车兵残局 + 只有车和兵的残局 + 弃子 + 短谜题 + 两步胜 + 闷杀 + 低升变 + 升变为马、象或车 + 超级长谜题 + 四步或更多步胜 + 楚茨文克(无等着) + diff --git a/translation/dest/settings/hr-HR.xml b/translation/dest/settings/hr-HR.xml index 59ccb3edcb..9ff5beda83 100644 --- a/translation/dest/settings/hr-HR.xml +++ b/translation/dest/settings/hr-HR.xml @@ -2,8 +2,8 @@ Postavke Zatvori račun - Zatvaranje je konačno. Nema povratka. Jeste li sigurni? - Neće Vam biti dopušteno otvaranje novog računa s istim imenom, čak i ako je kapitalizacija slova drugačija. + Zatvaranje je konačno. Nema povratka. Jesi li siguran? + Neće ti biti dopušteno otvaranje novog računa s istim imenom, čak i ako kapitalizacija slova bude drugačija. Predomislio/la sam se, ne zatvaraj moj račun Jeste li sigurni da želite zatvoriti račun? Zatvaranje računa je trajna odluka. Više se NIKADA nećete moći prijaviti. Račun je zatvoren. diff --git a/translation/dest/site/el-GR.xml b/translation/dest/site/el-GR.xml index 67f8ee8126..a35ed2d2be 100644 --- a/translation/dest/site/el-GR.xml +++ b/translation/dest/site/el-GR.xml @@ -283,7 +283,7 @@ Ανάκληση κίνησης Προσφέρετε ανάκληση της προηγούμενης κίνησης Προσφορά ανάκλησης κίνησης εστάλη - Αρνήθηκε η προσφορά ανάκλησης κίνησης + Απορρίφθηκε η προσφορά ανάκλησης κίνησης Προσφορά ακύρωσης κίνησης αποδεκτή Προσφορά ακύρωσης κίνησης ακυρώθηκε Ο αντίπαλός σας πρότεινε ακύρωση της τελευταίας κίνησης diff --git a/translation/dest/site/es-ES.xml b/translation/dest/site/es-ES.xml index 2098e43a5b..7b8c62bbd9 100644 --- a/translation/dest/site/es-ES.xml +++ b/translation/dest/site/es-ES.xml @@ -9,7 +9,7 @@ Tu turno %1$s nivel %2$s Nivel - Fuerza + Nivel Mostrar/Ocultar chat Activar/Desactivar sonido Chat diff --git a/translation/dest/site/ga-IE.xml b/translation/dest/site/ga-IE.xml index c58b9b1e79..19827cebcf 100644 --- a/translation/dest/site/ga-IE.xml +++ b/translation/dest/site/ga-IE.xml @@ -279,6 +279,8 @@ Tá do rátáil %1$s (%2$s) ró-ard Tá an rátáil seachtainiúil %1$s is fearr agat (%2$s) ró-ard Tá do rátáil %1$s (%2$s) ró-íseal + Rátáil ≥ %1$s i %2$s + Rátáil ≤ %1$s i %2$s Caithfidh tú a bheith i bhfoireann %s Níl tú sa bhfoireann %s Ar ais don chluiche @@ -300,6 +302,7 @@ Staidéar Déan cluiche a iompórtáil Seo CAPCHTA fichille. + Cliceáil ar an mbord le bogadh a dhéanamh, agus cruthaigh gur duine thú. Réitigh an captcha fichille, le do thoil. Ní marbhsháinn é sin Marbhsháinn ag bán le beart amháin @@ -390,13 +393,18 @@ Meanghrádú na gcéilí imeartha Baill amháin Eagarthóir boird + Socraigh an bhord Oscailtí a bhfuil tóir orthu Suíomh tosaithe + Glan an bhord Sábhail suíomh Lódáil suíomh Príobháideach + Tuairiscigh %s do na modhnóirí + Comhlánú próifíle: %s rátáil %s Mura bhfuil ann do, fág an bosca folamh + Ráta críochnúcháin cluiche: %s Próifíl Cuir próifíl in eagar Céadainm @@ -404,6 +412,7 @@ Féinaisnéis Tír Go raibh maith agat! + Nascanna le meáin sóisialta Nodaireacht inlíne Féach ar Lichess TV Níos luaithe ar Lichess TV @@ -412,6 +421,8 @@ Imreoirí gníomhach Aire duit, tá an cluiche seo rátáilte ach níl clog ann! D\'éirigh leat + Téigh ar aghaidh chuig an chéad cluiche eile go huathoibríoch i ndiaidh bogadh + Athrú uathoibríoch Fadbhbanna Nuashonraithe is déanaí Buaiteoirí comórtais @@ -442,20 +453,24 @@ Cur nasc le ar a laghad cluiche amháin ina ndéantar caimiléireacht le do thoil. le %s Tá an topaic seo dúnta anois. + Téamú Blag Ceisteanna & Freagraí Nótaí Clóscríobh nótaí príobhaideach anseo Ainm úsáideora nó pasfhocal mícheart Pasfhocal mícheart + Cód fíordheimhniú neamhbhailí Seol nasc chugam trí r-phost Pasfhocal reatha Pasfhocal nua Pasfhocal nua (arís) + Tá difríocht idir an dhá pasfhocail nua Neart pasfhocail Am tosaithe ar an gclog Am le cur leis an gclog Príobháideachas + Polasaí príobháideacht Lig d\'imreoirí eile thú a leanacht Lig d\'imreoirí eile dúshlán a sheoladh chugat Lig d\'imreoirí eile cuireadh staidéir a sheoladh chugat @@ -472,6 +487,7 @@ Éasca Gnáth Deacair + Glacann %1$s páirt i %2$s D\'iarr %1$s %2$s D\'fhreagair %1$s %2$s Dúirt %1$s %2$s @@ -479,9 +495,19 @@ Cailleadh %1$s i gcoinne %2$s i %3$s %1$s i gcoinne %2$s i %3$s + %1$s i gcoinne %2$s i %3$s Amlíne Ag tosú: + Tá an t-eolas ar fad roghnach agus beidh sé infheicthe do chách. Do chathair, réigiún nó cúige. + Labhair fút féin, faoi do shuimeanna, faoi fichelle, na oscailtí is fearr leat, imreoirí,... + + %s carachtar ar a mhéad. + %s carachtairí ar a mhéad. + %s carachtairí ar a mhéad. + %s carachtairí ar a mhéad. + %s carachtairí ar a mhéad. + Duine Ríomhaire Taobh diff --git a/translation/dest/site/gu-IN.xml b/translation/dest/site/gu-IN.xml index 127752c261..573fe3eb80 100644 --- a/translation/dest/site/gu-IN.xml +++ b/translation/dest/site/gu-IN.xml @@ -100,6 +100,17 @@ ફરીથી રમો વાસ્તવિક સમય માં CPL નિયમ દ્વારા + મોટી ભૂલ + મોટી ભૂલો + ભૂલ + ભૂલો + ચૂક + બોર્ડ ફેરવો + ખેલાડીઓ + મિત્રો + આજે + ગઇકાલે + એક દિવસ શરૂઆત %s ચાલો diff --git a/translation/dest/site/hr-HR.xml b/translation/dest/site/hr-HR.xml index 5099b61881..64b1a54ed2 100644 --- a/translation/dest/site/hr-HR.xml +++ b/translation/dest/site/hr-HR.xml @@ -211,8 +211,8 @@ %s odigranih partija s tobom Odustani - Bijelome isteklo vrijeme - Crnome isteklo vrijeme + Bijelom je isteklo vrijeme + Crnom je isteklo vrijeme Ponuda remija poslana Ponuda remija odbijena Ponuda remija prihvaćena @@ -535,7 +535,7 @@ računalnu analizu, chat partije i URL za dijeljenje. Trenutna lozinka Nova lozinka Ponovi novu lozinku - Nova zaporke se ne podudaru + Zaporke se ne podudaraju Snaga zaporke Početno vrijeme Vremenski dodatak @@ -690,7 +690,7 @@ računalnu analizu, chat partije i URL za dijeljenje. Ako ne vidiš email, pogledaj na drugim mjestima (otpad/smeće, neželjena pošta, društvene mreže ili druge mape). Poslali smo email na %s. Klikni link u emailu da resetiraš lozinku. Registracijom prihvaćaš %s - Pročitajte naše %s. + Pročitajte naša %s. Mrežno kašnjenje između tebe i lichess-a Vrijeme obrade poteza na lichess serveru Preuzmi s bilješkama @@ -861,15 +861,15 @@ računalnu analizu, chat partije i URL za dijeljenje. Trener šahovskih taktika Važno Na tvoje pitanje možda već postoji odgovor %1$s - u F.A.Q. + u najčešće postavljenim pitanjima. Za prijavu korisnika zbog varanja ili lošeg ponašanja, %1$s - koristite obrazac za prijavu + koristi obrazac za prijavu Za potraživanje pomoći, %1$s - kontaktirajte nas + kontaktiraj nas Ova tema je arhivirana i na nju više nije moguće odgovoriti. Pridruži se %1$s za objavljivanje na ovom forumu %1$s tim - Još ne možeš objavljivati na forumima. Odigrajte nekoliko partija! + Još ne možeš objavljivati na forumima. Odigraj nekoliko partija! Pretplati se Otkaži pretplatu diff --git a/translation/dest/site/nn-NO.xml b/translation/dest/site/nn-NO.xml index 1f73ffe1ab..d2790511ff 100644 --- a/translation/dest/site/nn-NO.xml +++ b/translation/dest/site/nn-NO.xml @@ -130,7 +130,7 @@ %s spelar %s spelarar - Pågåande parti + Parti som blir spela no %s parti %s parti @@ -616,9 +616,9 @@ i %3$s Denne simultanframsyninga finst ikkje. Returner til simultanheimesida Simultanframsyning inneber at ein spelar møter fleire motspelarar samstundes. - Mot 50 motspelarar, vann Fischer 47 parti, spelte to remis og tapte eitt. + Mot 50 motspelarar, fekk Fischer 47 sigrar, to remisar og eit tap. Konseptet liknar på verkelege simultansjakkframsyningar, der verten for arrangementet går frå bord til bord og spelar mot fleire motstandarar samstundes. - Når simultanframsyninga startar, byrjar alle deltakarane eit parti mot verten som får spela med dei kvite brikkene. Simultanoppvisninga endar når alle partia er ferdigspelte. + Når simultanframsyninga byrjar, startar alle deltakarane eit parti mot den som er vert. Verten får spela med dei kvite brikkene. Simultanoppvisinga endar når alle partia er ferdigspelte. Simultanframsyningar er alltid urangerte. Omstart, attendetrekk og \"meirtid\" er slått av. Opprett Når du arrangerer ei simultanframsyning spelar du mot fleire motstandarar samstundes. diff --git a/translation/dest/site/uz-UZ.xml b/translation/dest/site/uz-UZ.xml index 3bb430b434..17cec5990b 100644 --- a/translation/dest/site/uz-UZ.xml +++ b/translation/dest/site/uz-UZ.xml @@ -9,6 +9,7 @@ Sizni yurishingiz %1$s daraja %2$s Daraja + Kuchli tomonlari Suhbatni yopish/ochish Ovozni yoqish/o\'chirish Suhbat @@ -199,6 +200,8 @@ siz o\'ynagan o\'yinlar - %s Bekor + Oqlar vaqti tugadi + Qoralar vaqti tugadi Durrang uchun taklif yuborildi Durrang taklifi inkor qilindi Durrang taklifi qabul qilindi @@ -502,9 +505,12 @@ Joriy parol Yangi parol Yangi parol (yana) + Yangi parollar mos kelmayabdi + Parol mustahkamligi Boshlang\'ich vaqt Vaqtni oshishi Shaxsiylik + Maxfiylik siyosati Boshqa o\'yinchilarga sizni kuzatishiga imkon bering Boshqa o\'yinchilarga siz bilan bellashuviga imkon bering Boshqa o\'yinchilarga sizni ta\'limga chorlashiga imkon bering @@ -650,6 +656,7 @@ Agar siz emailni ko\'rmasangiz, boshqa kataloglaringizni qarab ko\'ring, masalan, spam, ijtimoiy va boshqa shularga o\'xshashlarni. Biz %s ga hat yubordik. Parolni qayta tiklash uchun emaildagi linkni bosing. Ro\'yhatdan o\'tib bizning %s shartlarimizga roziligingizni bildirasiz. + Biz haqimizda oʻqing: %s. Lichess va sizning o\'rtangizdagi tarmoq kechikishi Lichess serverida yurishni amalga oshirish uchun vaqt Annotatsiya holatda yuklash diff --git a/translation/dest/storm/aa-ER.xml b/translation/dest/storm/aa-ER.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/aa-ER.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/af-ZA.xml b/translation/dest/storm/af-ZA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/af-ZA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ak-GH.xml b/translation/dest/storm/ak-GH.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ak-GH.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/am-ET.xml b/translation/dest/storm/am-ET.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/am-ET.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/an-ES.xml b/translation/dest/storm/an-ES.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/an-ES.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ar-SA.xml b/translation/dest/storm/ar-SA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ar-SA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/as-IN.xml b/translation/dest/storm/as-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/as-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ast-ES.xml b/translation/dest/storm/ast-ES.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ast-ES.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/az-AZ.xml b/translation/dest/storm/az-AZ.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/az-AZ.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ba-RU.xml b/translation/dest/storm/ba-RU.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ba-RU.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/be-BY.xml b/translation/dest/storm/be-BY.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/be-BY.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/bg-BG.xml b/translation/dest/storm/bg-BG.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/bg-BG.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/bn-BD.xml b/translation/dest/storm/bn-BD.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/bn-BD.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/br-FR.xml b/translation/dest/storm/br-FR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/br-FR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/bs-BA.xml b/translation/dest/storm/bs-BA.xml new file mode 100644 index 0000000000..5dce02a151 --- /dev/null +++ b/translation/dest/storm/bs-BA.xml @@ -0,0 +1,22 @@ + + + Povucite potez da biste počeli + riješeni problemi + Novi najbolji dnevni rezultat! + Novi sedmični najbolji rezultat! + Novi mjesečni najbolji rezultat! + Novi najbolji rezultat sveukupno! + Prethodni najbolji rezultat bio je %s + Igrajte ponovo + + Jedna runda + %s rundi + %s rundi + + + Odigrao jednu rundu od %2$s + Odigrao %1$s rundi od %2$s + Odigrao %1$s rundi %2$s + + Najbolji rezultat: %s + diff --git a/translation/dest/storm/ca-ES.xml b/translation/dest/storm/ca-ES.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ca-ES.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ce-CE.xml b/translation/dest/storm/ce-CE.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ce-CE.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ceb-PH.xml b/translation/dest/storm/ceb-PH.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ceb-PH.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ckb-IR.xml b/translation/dest/storm/ckb-IR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ckb-IR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/co-FR.xml b/translation/dest/storm/co-FR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/co-FR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/cs-CZ.xml b/translation/dest/storm/cs-CZ.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/cs-CZ.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/cv-CU.xml b/translation/dest/storm/cv-CU.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/cv-CU.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/cy-GB.xml b/translation/dest/storm/cy-GB.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/cy-GB.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/da-DK.xml b/translation/dest/storm/da-DK.xml new file mode 100644 index 0000000000..254ba0347f --- /dev/null +++ b/translation/dest/storm/da-DK.xml @@ -0,0 +1,11 @@ + + + Ryk for at starte + opgaver løst + Ny daglig topscore! + Ny ugentlig topscore! + Ny månedlig topscore! + Tidligere topscore var %s + Spil igen + Højeste score: %s + diff --git a/translation/dest/storm/de-DE.xml b/translation/dest/storm/de-DE.xml new file mode 100644 index 0000000000..c7ae6169cf --- /dev/null +++ b/translation/dest/storm/de-DE.xml @@ -0,0 +1,20 @@ + + + Ziehe, um zu beginnen + Aufgaben gelöst + Neuer Tagesrekord! + Neuer Wochenrekord! + Neuer Monatsrekord! + Neuer Allzeit-Rekord! + Vorheriger Rekord war %s + Nochmal spielen + + 1 Durchlauf + %s Durchläufe + + + Einen Durchlauf von %2$s gespielt + %1$s Durchläufe von %2$s gespielt + + Rekord: %s + diff --git a/translation/dest/storm/el-GR.xml b/translation/dest/storm/el-GR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/el-GR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/en-US.xml b/translation/dest/storm/en-US.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/en-US.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/eo-UY.xml b/translation/dest/storm/eo-UY.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/eo-UY.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/es-ES.xml b/translation/dest/storm/es-ES.xml new file mode 100644 index 0000000000..ef63f09b3b --- /dev/null +++ b/translation/dest/storm/es-ES.xml @@ -0,0 +1,20 @@ + + + Mueve para empezar + rompecabezas resueltos + ¡Nueva puntuación más alta diaria! + ¡Nueva puntuación más alta semanal! + ¡Nueva puntuación más alta mensual! + ¡Nueva puntuación más alta de todo tiempo! + La puntuación más alta anterior era %s + Jugar de nuevo + + %s ronda + %s rondas + + + Jugó una ronda de %2$s + Jugó %1$s rondas de %2$s + + Puntuación más alta: %s + diff --git a/translation/dest/storm/et-EE.xml b/translation/dest/storm/et-EE.xml new file mode 100644 index 0000000000..03b1492b86 --- /dev/null +++ b/translation/dest/storm/et-EE.xml @@ -0,0 +1,4 @@ + + + Mängi uuesti + diff --git a/translation/dest/storm/eu-ES.xml b/translation/dest/storm/eu-ES.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/eu-ES.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/fa-IR.xml b/translation/dest/storm/fa-IR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/fa-IR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/fi-FI.xml b/translation/dest/storm/fi-FI.xml new file mode 100644 index 0000000000..9163bfc1a6 --- /dev/null +++ b/translation/dest/storm/fi-FI.xml @@ -0,0 +1,12 @@ + + + Aloita tekemällä siirto + tehtävää ratkaistu + Päivän uusi ennätys! + Viikon uusi ennätys! + Kuukauden uusi ennätys! + Uusi kaikkien aikojen ennätys! + Edellinen ennätys oli %s + Pelaa uudelleen + Ennätys: %s + diff --git a/translation/dest/storm/fo-FO.xml b/translation/dest/storm/fo-FO.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/fo-FO.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/fr-FR.xml b/translation/dest/storm/fr-FR.xml new file mode 100644 index 0000000000..811fc2b27a --- /dev/null +++ b/translation/dest/storm/fr-FR.xml @@ -0,0 +1,20 @@ + + + Faites un coup pour commencer + problèmes résolus + Nouveau record du jour! + Nouveau record de la semaine! + Nouveau record du mois! + Nouveau record de tous les temps! + Le record précédent était %s + Rejouer + + 1 essai + %s essais + + + A fait un essai de %2$s + A fait %1$s essais de %2$s + + Meilleur score : %s + diff --git a/translation/dest/storm/frp-IT.xml b/translation/dest/storm/frp-IT.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/frp-IT.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/fy-NL.xml b/translation/dest/storm/fy-NL.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/fy-NL.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ga-IE.xml b/translation/dest/storm/ga-IE.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ga-IE.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/gd-GB.xml b/translation/dest/storm/gd-GB.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/gd-GB.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/gl-ES.xml b/translation/dest/storm/gl-ES.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/gl-ES.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/gn-PY.xml b/translation/dest/storm/gn-PY.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/gn-PY.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/gu-IN.xml b/translation/dest/storm/gu-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/gu-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ha-HG.xml b/translation/dest/storm/ha-HG.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ha-HG.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/he-IL.xml b/translation/dest/storm/he-IL.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/he-IL.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/hi-IN.xml b/translation/dest/storm/hi-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/hi-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/hr-HR.xml b/translation/dest/storm/hr-HR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/hr-HR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/hu-HU.xml b/translation/dest/storm/hu-HU.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/hu-HU.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/hy-AM.xml b/translation/dest/storm/hy-AM.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/hy-AM.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ia-IA.xml b/translation/dest/storm/ia-IA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ia-IA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/id-ID.xml b/translation/dest/storm/id-ID.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/id-ID.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ig-NG.xml b/translation/dest/storm/ig-NG.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ig-NG.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/io-EN.xml b/translation/dest/storm/io-EN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/io-EN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/is-IS.xml b/translation/dest/storm/is-IS.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/is-IS.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/it-IT.xml b/translation/dest/storm/it-IT.xml new file mode 100644 index 0000000000..b056e70ee3 --- /dev/null +++ b/translation/dest/storm/it-IT.xml @@ -0,0 +1,9 @@ + + + Muovi un pedone per iniziare + Nuovo punteggio giornaliero! + Nuovo punteggio settimanale! + Nuovo punteggio massimo di tutti i tempi! + Il punteggio massimo precedente era %s + Gioca di nuovo + diff --git a/translation/dest/storm/ja-JP.xml b/translation/dest/storm/ja-JP.xml new file mode 100644 index 0000000000..c33cb14ca9 --- /dev/null +++ b/translation/dest/storm/ja-JP.xml @@ -0,0 +1,18 @@ + + + 一手指すとスタート + 解いた問題 + 今日のハイスコア更新! + 今週のハイスコア更新! + 今月のハイスコア更新! + 歴代のハイスコア更新! + 以前のハイスコアは %s + もう一度プレイ + + %s 回 + + + %2$s を %1$s 回プレイ + + ハイスコア:%s + diff --git a/translation/dest/storm/jbo-EN.xml b/translation/dest/storm/jbo-EN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/jbo-EN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/jv-ID.xml b/translation/dest/storm/jv-ID.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/jv-ID.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ka-GE.xml b/translation/dest/storm/ka-GE.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ka-GE.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/kab-DZ.xml b/translation/dest/storm/kab-DZ.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/kab-DZ.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/kk-KZ.xml b/translation/dest/storm/kk-KZ.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/kk-KZ.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/km-KH.xml b/translation/dest/storm/km-KH.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/km-KH.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/kmr-TR.xml b/translation/dest/storm/kmr-TR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/kmr-TR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/kn-IN.xml b/translation/dest/storm/kn-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/kn-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ko-KR.xml b/translation/dest/storm/ko-KR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ko-KR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ky-KG.xml b/translation/dest/storm/ky-KG.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ky-KG.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/la-LA.xml b/translation/dest/storm/la-LA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/la-LA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/lb-LU.xml b/translation/dest/storm/lb-LU.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/lb-LU.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/lg-UG.xml b/translation/dest/storm/lg-UG.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/lg-UG.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/lo-LA.xml b/translation/dest/storm/lo-LA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/lo-LA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/lt-LT.xml b/translation/dest/storm/lt-LT.xml new file mode 100644 index 0000000000..b147de2831 --- /dev/null +++ b/translation/dest/storm/lt-LT.xml @@ -0,0 +1,24 @@ + + + Norėdami pradėti padarykite ėjimą + išspręsta užduočių + Naujas kasdieninis rekordas! + Naujas savaitinis rekordas! + Naujas mėnesinis rekordas! + Naujas visų laikų rekordas! + Praėjęs rekordas buvo %s + Žaisti dar + + 1 eilė + %s eilės + %s eilės + %s eilių + + + Žaista viena %2$s eilė + Žaistos %1$s %2$s eilės + Žaista %1$s %2$s eilės + Žaista %1$s %2$s eilių + + Rekordas: %s + diff --git a/translation/dest/storm/lv-LV.xml b/translation/dest/storm/lv-LV.xml new file mode 100644 index 0000000000..7fe2d777d7 --- /dev/null +++ b/translation/dest/storm/lv-LV.xml @@ -0,0 +1,22 @@ + + + Izdariet gājienu, lai sāktu + atrisinātās puzles + Jauns dienas labākais rezultāts! + Jauns nedēļas labākais rezultāts! + Jauns mēneša labākais rezultāts! + Jauns visu laiku labākais rezultāts! + Iepriekšējais sasniegums bija %s + Spēlēt vēlreiz + + %s izspēlēšanas + %s izspēlēšana + %s izspēlēšanas + + + Izspēlēja %2$s %1$s reizes + Izspēlēja %2$s %1$s reizi + Izspēlēja %2$s %1$s reizes + + Labākais rezultāts: %s + diff --git a/translation/dest/storm/mai-IN.xml b/translation/dest/storm/mai-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/mai-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/mg-MG.xml b/translation/dest/storm/mg-MG.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/mg-MG.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/mi-NZ.xml b/translation/dest/storm/mi-NZ.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/mi-NZ.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/mk-MK.xml b/translation/dest/storm/mk-MK.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/mk-MK.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ml-IN.xml b/translation/dest/storm/ml-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ml-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/mn-MN.xml b/translation/dest/storm/mn-MN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/mn-MN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/mr-IN.xml b/translation/dest/storm/mr-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/mr-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ms-MY.xml b/translation/dest/storm/ms-MY.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ms-MY.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/mt-MT.xml b/translation/dest/storm/mt-MT.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/mt-MT.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/my-MM.xml b/translation/dest/storm/my-MM.xml new file mode 100644 index 0000000000..18edc7e7b7 --- /dev/null +++ b/translation/dest/storm/my-MM.xml @@ -0,0 +1,14 @@ + + + စတင်ရန် အရုပ် တစ်ရုပ်ကို ရွှေ့ပါ + ဖြေပြီးသည့် ဉာဏ်စမ်းများ + နေ့အလိုက် အမြင့်ဆုံး ရမှတ် အသစ် + လအလိုက် အမြင့်ဆုံး ရမှတ် အသစ် + အမြင့်ဆုံး ရမှတ် အသစ် + ယခင် အမြင့်ဆုံး ရမှတ်မှ %s ဖြစ်ပါသည် + ဆက်ကစားမည် + + တစ်ကြိမ် + + အမြင့်ဆုံး ရမှတ် %s + diff --git a/translation/dest/storm/nb-NO.xml b/translation/dest/storm/nb-NO.xml new file mode 100644 index 0000000000..b3b16e0bf6 --- /dev/null +++ b/translation/dest/storm/nb-NO.xml @@ -0,0 +1,20 @@ + + + Trekk for å begynne + sjakknøtter løst + Ny rekord for dagen! + Ny rekord for uken! + Ny rekord for måneden! + Ny rekord for alle tider! + Forrige rekord var %s + Spill igjen + + 1 runde + %s runder + + + Har spilt én runde med %2$s + Har spilt %1$s runder med %2$s + + Rekord: %s + diff --git a/translation/dest/storm/ne-NP.xml b/translation/dest/storm/ne-NP.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ne-NP.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/nl-NL.xml b/translation/dest/storm/nl-NL.xml new file mode 100644 index 0000000000..89b148d139 --- /dev/null +++ b/translation/dest/storm/nl-NL.xml @@ -0,0 +1,20 @@ + + + Doe een zet om te beginnen + puzzels opgelost + Nieuw dagrecord! + Nieuw weekrecord! + Nieuw maandrecord! + Nieuw record aller tijden! + Vorige record was %s + Opnieuw spelen + + 1 sessie + %s sessies + + + Eén sessie van %2$s gespeeld + %1$s sessies van %2$s gespeeld + + Record: %s + diff --git a/translation/dest/storm/nn-NO.xml b/translation/dest/storm/nn-NO.xml new file mode 100644 index 0000000000..1323406d98 --- /dev/null +++ b/translation/dest/storm/nn-NO.xml @@ -0,0 +1,20 @@ + + + Start ved å gjera eit trekk + sjakkoppgåvene løyst + Ny dagsrekord! + Ny vekesrekord! + Ny månadsrekord! + Ny personleg rekord! + Førre rekord var %s + Spel igjen + + 1 runde + %s rundar + + + Har spela ein runde med %2$s + Har spela %1$s rundar med %2$s + + Rekord: %s + diff --git a/translation/dest/storm/ns-ZA.xml b/translation/dest/storm/ns-ZA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ns-ZA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ny-MW.xml b/translation/dest/storm/ny-MW.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ny-MW.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/om-ET.xml b/translation/dest/storm/om-ET.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/om-ET.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/or-IN.xml b/translation/dest/storm/or-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/or-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/os-SE.xml b/translation/dest/storm/os-SE.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/os-SE.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/pa-IN.xml b/translation/dest/storm/pa-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/pa-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/pa-PK.xml b/translation/dest/storm/pa-PK.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/pa-PK.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/pi-IN.xml b/translation/dest/storm/pi-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/pi-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/pl-PL.xml b/translation/dest/storm/pl-PL.xml new file mode 100644 index 0000000000..7098a2da19 --- /dev/null +++ b/translation/dest/storm/pl-PL.xml @@ -0,0 +1,12 @@ + + + Wykonaj ruch, aby zacząć + zadania rozwiązane + Nowy dzień rekord! + Nowy tygodniowy rekord! + Nowy miesięczny rekord! + Nowy rekord! + Poprzedni rekord wynosił %s + Zagraj ponownie + Rekord: %s + diff --git a/translation/dest/storm/ps-AF.xml b/translation/dest/storm/ps-AF.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ps-AF.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/pt-BR.xml b/translation/dest/storm/pt-BR.xml new file mode 100644 index 0000000000..15ca95169f --- /dev/null +++ b/translation/dest/storm/pt-BR.xml @@ -0,0 +1,20 @@ + + + Mova para começar + quebra-cabeças resolvidos + Novo recorde diário! + Novo recorde semanal! + Novo recorde mensal! + Novo recorde de todos os tempos! + Recorde anterior era %s + Jogar novamente + + 1 tentativa + %s tentativas + + + Jogou uma tentativa de %2$s + Jogou %1$s tentativas de %2$s + + Recorde: %s + diff --git a/translation/dest/storm/pt-PT.xml b/translation/dest/storm/pt-PT.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/pt-PT.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/qu-PE.xml b/translation/dest/storm/qu-PE.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/qu-PE.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/rn-BI.xml b/translation/dest/storm/rn-BI.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/rn-BI.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ro-RO.xml b/translation/dest/storm/ro-RO.xml new file mode 100644 index 0000000000..c79b71ffa2 --- /dev/null +++ b/translation/dest/storm/ro-RO.xml @@ -0,0 +1,5 @@ + + + puzzle-uri rezolvate + Jucați din nou + diff --git a/translation/dest/storm/ru-RU.xml b/translation/dest/storm/ru-RU.xml new file mode 100644 index 0000000000..f8b221f473 --- /dev/null +++ b/translation/dest/storm/ru-RU.xml @@ -0,0 +1,11 @@ + + + Вернуться к началу + задача решена + Лучший результат за день! + Лучший результат за неделю! + Лучший результат за месяц! + Новый рекорд за все время! + Прошлый рекорд был %s + Играть снова + diff --git a/translation/dest/storm/rw-RW.xml b/translation/dest/storm/rw-RW.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/rw-RW.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sa-IN.xml b/translation/dest/storm/sa-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sa-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sc-IT.xml b/translation/dest/storm/sc-IT.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sc-IT.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sd-PK.xml b/translation/dest/storm/sd-PK.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sd-PK.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/se-NO.xml b/translation/dest/storm/se-NO.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/se-NO.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/si-LK.xml b/translation/dest/storm/si-LK.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/si-LK.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sk-SK.xml b/translation/dest/storm/sk-SK.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sk-SK.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sl-SI.xml b/translation/dest/storm/sl-SI.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sl-SI.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sn-ZW.xml b/translation/dest/storm/sn-ZW.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sn-ZW.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/so-SO.xml b/translation/dest/storm/so-SO.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/so-SO.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sq-AL.xml b/translation/dest/storm/sq-AL.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sq-AL.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sr-SP.xml b/translation/dest/storm/sr-SP.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sr-SP.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/st-ZA.xml b/translation/dest/storm/st-ZA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/st-ZA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sv-SE.xml b/translation/dest/storm/sv-SE.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sv-SE.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/sw-KE.xml b/translation/dest/storm/sw-KE.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/sw-KE.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ta-IN.xml b/translation/dest/storm/ta-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ta-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/te-IN.xml b/translation/dest/storm/te-IN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/te-IN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/tg-TJ.xml b/translation/dest/storm/tg-TJ.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/tg-TJ.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/th-TH.xml b/translation/dest/storm/th-TH.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/th-TH.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ti-ER.xml b/translation/dest/storm/ti-ER.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ti-ER.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/tk-TM.xml b/translation/dest/storm/tk-TM.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/tk-TM.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/tl-PH.xml b/translation/dest/storm/tl-PH.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/tl-PH.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/tlh-AA.xml b/translation/dest/storm/tlh-AA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/tlh-AA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/tn-ZA.xml b/translation/dest/storm/tn-ZA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/tn-ZA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/tp-TP.xml b/translation/dest/storm/tp-TP.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/tp-TP.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/tr-TR.xml b/translation/dest/storm/tr-TR.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/tr-TR.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/tt-RU.xml b/translation/dest/storm/tt-RU.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/tt-RU.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ug-CN.xml b/translation/dest/storm/ug-CN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ug-CN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/uk-UA.xml b/translation/dest/storm/uk-UA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/uk-UA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/ur-PK.xml b/translation/dest/storm/ur-PK.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/ur-PK.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/uz-UZ.xml b/translation/dest/storm/uz-UZ.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/uz-UZ.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/vi-VN.xml b/translation/dest/storm/vi-VN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/vi-VN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/wo-SN.xml b/translation/dest/storm/wo-SN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/wo-SN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/xh-ZA.xml b/translation/dest/storm/xh-ZA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/xh-ZA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/yo-NG.xml b/translation/dest/storm/yo-NG.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/yo-NG.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/zh-CN.xml b/translation/dest/storm/zh-CN.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/zh-CN.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/zh-TW.xml b/translation/dest/storm/zh-TW.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/zh-TW.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/storm/zu-ZA.xml b/translation/dest/storm/zu-ZA.xml new file mode 100644 index 0000000000..3ea04e700d --- /dev/null +++ b/translation/dest/storm/zu-ZA.xml @@ -0,0 +1,2 @@ + + diff --git a/translation/dest/streamer/bg-BG.xml b/translation/dest/streamer/bg-BG.xml index 9e27acc5cd..cef040620d 100644 --- a/translation/dest/streamer/bg-BG.xml +++ b/translation/dest/streamer/bg-BG.xml @@ -4,4 +4,16 @@ Lichess стример НА ЖИВО! ИЗВЪН ЛИНИЯ + Идем! + Известие до последователите ви в Lichess. + Дълго описание + Промяна/изтриване на снимката ви + Качване на снимка + Изтриване на снимка + Максимална големина: %s + Инсталирайте блокировач на зловреден софтуер! + Обезопасете се от реклами и тракери, +преливащи в Twitch и YouTube. +Lichess препоръчва uBlock Origin, +което е безплатно и с отворен код. diff --git a/translation/dest/streamer/de-DE.xml b/translation/dest/streamer/de-DE.xml index 152b2e7a63..f62151f1d9 100644 --- a/translation/dest/streamer/de-DE.xml +++ b/translation/dest/streamer/de-DE.xml @@ -4,7 +4,7 @@ Lichess Streamer LIVE! OFFLINE - Aktuelle Streams: %s + Streamt gerade: %s Letzter Stream %s Werde ein Lichess Streamer Hast du einen Twitch oder YouTube-Kanal? @@ -33,7 +33,7 @@ Das kannst du auf Twitch oder YouTube einstellen, nicht in den Lichess-Streamere Falls dein Stream in Englisch ist, bruchst du keine Sprachmarkierung einfügen. Dein Twitch-Benutzername oder die URL Optional. Leer lassen falls nicht verfügbar - Deine YouTube-Kanal-ID oder die URL + Deine YouTube-Kanal-ID oder URL Dein Streamername auf Lichess Kurz fassen: Maximal %s Zeichen diff --git a/translation/dest/streamer/es-ES.xml b/translation/dest/streamer/es-ES.xml index d08c1158d0..8e5cefee1a 100644 --- a/translation/dest/streamer/es-ES.xml +++ b/translation/dest/streamer/es-ES.xml @@ -16,7 +16,7 @@ %s está transmitiendo Reglas de transmisión Incluye la palabra clave \"lichess.org\" en el título de tu transmisión cuando transmitas en Lichess. - Elimina la palabra clave cuando transmitas cosas que no son relativas a Lichess. + Elimina la palabra clave cuando transmitas contenido que no esté relacionado a Lichess. Lichess detectará tu transmisión automáticamente y habilitará los siguientes incentivos: Beneficios de transmitir con la palabra clave Obtén un icono de presentador en tu perfil de Lichess. diff --git a/translation/dest/streamer/nl-NL.xml b/translation/dest/streamer/nl-NL.xml index a358b2c693..f013611056 100644 --- a/translation/dest/streamer/nl-NL.xml +++ b/translation/dest/streamer/nl-NL.xml @@ -7,7 +7,7 @@ Nu aan het streamen: %s Laatste stream: %s Word een Lichess streamer - Heeft u een Twitch- of YouTube-kanaal? + Heb je een Twitch- of YouTube-kanaal? Daar gaan we! Alle streamers Wijzig streamer pagina @@ -26,8 +26,8 @@ Je stream is goedgekeurd. Je stream wordt beoordeeld door de toezichthouders. Vul je streamer informatie in en upload een foto. - Wanneer u klaar bent om als Lichess stream vermeld te worden, %s - verzoek een beoordeling van een toezichthouder + Wanneer u klaar bent om als Lichess stream vermeld te worden, %s + verzoek een beoordeling van een toezichthouder Als je stream in een andere taal is dan het Engels, voeg de juiste taaltag toe (%s), ingesloten in vierkante haken, aan het begin van uw stream titel. Als voorbeelden plaatst u \"[NL]\" voor Nederlands, \"[DE]\" voor Duits, \"[FR]\" voor Frans, enz. Zet het in de stream titel op de Twitch of YouTube pagina, niet in de Lichess stream-instellingen. diff --git a/translation/dest/streamer/sr-SP.xml b/translation/dest/streamer/sr-SP.xml index ee1f543841..676bea1530 100644 --- a/translation/dest/streamer/sr-SP.xml +++ b/translation/dest/streamer/sr-SP.xml @@ -20,9 +20,10 @@ Твој стрим је одобрен. Твој стрим проверавају модератори. Молимо попуните стримерске информације и поставите слику. - Када будете спремни да постанете Личес стример, %s - затражите проверу од стране модератора + Када будете спремни да постанете Личес стример, %s + затражите проверу од стране модератора Твоје Твич корисничко име или УРЛ + Није обавезно. Оставити празно ако нема Твој Јутјуб канал ИД или УРЛ Наслов Реци нам нешто о свом стриму у једној реченици @@ -31,4 +32,5 @@ Постави слику Избриши слику Максимална величина: %s + Инсталирај блокер малвера! diff --git a/translation/dest/streamer/uz-UZ.xml b/translation/dest/streamer/uz-UZ.xml index 3ea04e700d..8299810e9f 100644 --- a/translation/dest/streamer/uz-UZ.xml +++ b/translation/dest/streamer/uz-UZ.xml @@ -1,2 +1,5 @@ - + + JONLI! + OFFLINE + diff --git a/translation/dest/team/az-AZ.xml b/translation/dest/team/az-AZ.xml index 330a48ec15..cdd6dfa91a 100644 --- a/translation/dest/team/az-AZ.xml +++ b/translation/dest/team/az-AZ.xml @@ -11,7 +11,7 @@ Komandalarım Komanda tapılmadı Komandaya qoşul - komandadan ayrıl + Komandanı tərk et Qəbul istəklərini əl ilə nəzərdən keçirin İşarəlidirsə, oyunçuların komandaya qoşulmaq üçün bir tələb yazması lazımdır, bu təklifi rədd edə və ya qəbul edə bilərsiniz. diff --git a/translation/dest/team/de-DE.xml b/translation/dest/team/de-DE.xml index be4b6b6f35..8909356333 100644 --- a/translation/dest/team/de-DE.xml +++ b/translation/dest/team/de-DE.xml @@ -12,7 +12,7 @@ Kein Team gefunden Tritt dem Team bei Team verlassen - Beitrittsanfragen manuell prüfen + Beitrittsanfragen manuell überprüfen Wenn diese Option aktiviert ist, müssen Spieler eine Anfrage schreiben, um dem Team beizutreten, welche du ablehnen oder akzeptieren kannst. Teamleiter @@ -34,7 +34,7 @@ Ein Arenaturnier, dem nur Mitglieder deines Teams beitreten können Benachrichtige alle Mitglieder Sende eine private Nachricht an alle Mitglieder des Teams - Sende eine private Nachricht an alle Mitglieder dieses Teams. Du kannst die Funktion benutzen, um Spieler zu einem Turnier oder einem Team-Kampf aufzurufen. Spieler, die diese Art von Nachrichten nicht empfangen wollen, könnten dein Team verlassen. + Sende eine private Nachricht an ALLE Mitglieder dieses Teams. Du kannst die Funktion benutzen, um Spieler zu einem Turnier oder einem Team-Kampf aufzurufen. Spieler, die diese Art von Nachrichten nicht empfangen wollen, könnten dein Team verlassen. Teams, die ich leite Möchtest du eines der kommenden Turniere verlinken? Benutzer, die dieses Team verwalten können diff --git a/translation/dest/team/es-ES.xml b/translation/dest/team/es-ES.xml index ff7892d85b..b1409858e5 100644 --- a/translation/dest/team/es-ES.xml +++ b/translation/dest/team/es-ES.xml @@ -12,8 +12,8 @@ Ningún equipo encontrado Unirse al equipo Abandonar el equipo - Revisar manualmente las solicitudes de admisión - Si está marcado, los jugadores tendrán que escribir una solicitud para unirse al equipo, que usted puede rechazar o aceptar. + Revisar manualmente las solicitudes de admisión + Si está marcado, los jugadores tendrán que escribir una solicitud para unirse al equipo, que tú puedes rechazar o aceptar. Líder del equipo Líderes del equipo diff --git a/translation/dest/team/hr-HR.xml b/translation/dest/team/hr-HR.xml index 34585e37a8..0e461ab844 100644 --- a/translation/dest/team/hr-HR.xml +++ b/translation/dest/team/hr-HR.xml @@ -13,6 +13,8 @@ Nijedan tim nije pronađen Priključi se timu Napusti tim + Ručno provjeri zahtjeve za pridruživanjem + Kada označeni, igrači moraju napisati zahtjev za pridruživanje timu, kojeg možeš prihvatiti ili odbiti. Vođa tima Vođe tima @@ -44,4 +46,8 @@ Igrači koji ne vole primiti vaše poruke bi mogli napustiti tim. Chat voditelja Raspusti tim Trajno raspusti tim. + Timska lozinka + (Neobvezno) Lozinka koju novi članovi moraju znati kako bi pristupili ovom timu. + Netočna timska lozinka. + Ovaj tim već postoji. diff --git a/translation/dest/team/uz-UZ.xml b/translation/dest/team/uz-UZ.xml index 054704b642..87798a92c2 100644 --- a/translation/dest/team/uz-UZ.xml +++ b/translation/dest/team/uz-UZ.xml @@ -12,6 +12,8 @@ Jamoa topilmadi Jamoaga qo\'shilish Jamoani tark etish + Qabul qilish soʻrovlarini koʻrib chiqish + Agar belgilangan boʻlsa, oʻyinchilar jamoaga qoʻshilish uchun soʻrov yozishlari kerak. Siz ularni inkor yoki qabul qilishingiz mumkin. Jamoa sardori Jamoa sardorlari @@ -39,4 +41,10 @@ Xabarlaringizni qabul qilishni yoqtirmaydigan oʻyinchilar jamoani tark etishlar Bo\'lajak musobaqalardan birini ulashni xohlaysizmi? Ushbu jamoani boshqaradigan foydalanuvchilar Sardorlar suhbati + Jamoani yopish + Jamoani butunlay yopish. + Jamoa kaliti + (Ixtiyoriy) Ushbu jamoaga yangi aʻzolarni qoʻshilishida bilishi kerak boʻlgan jamoa kaliti. + Jamoa kaliti mos kelmadi. + Ushbu jamoa mavjud. diff --git a/translation/dest/tfa/hr-HR.xml b/translation/dest/tfa/hr-HR.xml index 8d8f8b843b..61197d4246 100644 --- a/translation/dest/tfa/hr-HR.xml +++ b/translation/dest/tfa/hr-HR.xml @@ -5,11 +5,12 @@ Nabavite aplikaciju za dvofaktorsku provjeru autentičnosti, na primjer Google Authenticator za %1$s ili %2$s. Skenirajte QR kôd pomoću aplikacije. Unesite lozinku i kôd za provjeru autentičnosti koji je generirala aplikacija da biste dovršili postavljanje. Trebat će vam kôd za provjeru autentičnosti svaki put kada se prijavite. - Ako ne možete skenirati kod, ukucajte tajni %s u Vašoj aplikaciji. + Ako ne možete skenirati kod, ukucajte tajni %s u Vašoj aplikaciji. Kôd za provjeru autentičnosti Napomena: Ako izgubite pristup dvofaktorskim kodovima za provjeru autentičnosti, možete izvršiti resetiranje lozinke putem e-pošte. Uključite dvofaktorsku provjeru autentičnosti Isključite dvofaktorsku provjeru autentičnosti Dvofaktorska provjera autentičnosti je uključena Da biste onemogućili dvofaktorsku provjeru autentičnosti, potrebna vam je lozinka i kôd za provjeru autentičnosti iz aplikacije za potvrđivanje. Ako ste izgubili pristup kodovima za provjeru autentičnosti, možete izvršiti resetiranje lozinke putem e-pošte. + Otvori aplikaciju dvofaktorske autentifikacije na svom uređaju da bi mogli vidjeti svoj autentifikacijski kod i potvrditi svoj identitet. diff --git a/translation/dest/tfa/uz-UZ.xml b/translation/dest/tfa/uz-UZ.xml index a635c89e7a..0dfb020a01 100644 --- a/translation/dest/tfa/uz-UZ.xml +++ b/translation/dest/tfa/uz-UZ.xml @@ -1,4 +1,16 @@ Ikki Faktorli Autentifikatsiya + Ikki faktorli autentifikatsiya sizning akkountingizga ximoyalanishning yana bir qatlamini qoʻshadi. + Ikki faktorli autentifikatsiya uchun app ni oling, masalan Google Authenticator %1$s yoki %2$s lar uchun. + QR kodni app yordamida skanerdan oʻtkazing. + Sozlashlarni yakunlash uchun app tomonidan generatsiya qilingan autentifikatsiya kodi va parolni kiriting. Siz har safar (login) kirishni amalga oshirganingizda autentifikatsiya kodini kiritishingiz kerak boʻladi. + Agar siz kodni skanerdan oʻtkazmasangiz, sirli %s ni appga kiriting. + Autentifikatsiya kodi + Izoh: Agar siz ikki faktorli autentifikatsiyangizga huquqni yoʻqotsangiz, siz parolingizni email orqali tiklashingiz mumkin. + Ikki faktorli autentifikatsiyani yoqish + Ikki faktorli autentifikatsiyani oʻchirish + Ikki faktorli autentifikatsiya yoqilgan + Ikki faktorli autentifikatsiyani oʻchirish uchun siz autentifikator appdan autentifikatsiya kodi va parolni olishingiz kerak. Agar siz autentifikatsiya kodiga huquqni yoʻqotgan boʻlsangiz, siz parolni email orqali tiklashingiz mumkin. + Identifikatsiyalashdan oʻtish va autentifikatsiya kodini koʻrish uchun ikki faktorli autentifikatsiya appini qurilmangizda oching. diff --git a/translation/dest/tourname/de-DE.xml b/translation/dest/tourname/de-DE.xml index f71eede888..809814b2bf 100644 --- a/translation/dest/tourname/de-DE.xml +++ b/translation/dest/tourname/de-DE.xml @@ -37,7 +37,7 @@ Schnellschach Schild-Arena Schnellschach Schild Klassische Schild-Arena - Klassisches Schild + Klassisch-Schild %s Schild-Arena %s Schild %s Schnellschach-Arena diff --git a/translation/source/storm.xml b/translation/source/storm.xml new file mode 100644 index 0000000000..d8fe3e16ac --- /dev/null +++ b/translation/source/storm.xml @@ -0,0 +1,20 @@ + + + Move to start + puzzles solved + New daily highscore! + New weekly highscore! + New monthly highscore! + New all-time highscore! + Previous highscore was %s + Play again + + 1 run + %s runs + + + Played one run of %2$s + Played %1$s runs of %2$s + + Highscore: %s + diff --git a/ui/analyse/src/study/topics.ts b/ui/analyse/src/study/topics.ts index ee5e6ab73a..5f86e1850e 100644 --- a/ui/analyse/src/study/topics.ts +++ b/ui/analyse/src/study/topics.ts @@ -1,11 +1,11 @@ -import { h } from 'snabbdom' -import { VNode } from 'snabbdom/vnode' import * as modal from '../modal'; -import { bind, bindSubmit, onInsert } from '../util'; -import { prop, Prop } from 'common'; import * as xhr from 'common/xhr'; -import { StudyCtrl, Topic } from './interfaces'; +import { bind, bindSubmit, onInsert } from '../util'; +import { h } from 'snabbdom' +import { prop, Prop } from 'common'; import { Redraw } from '../interfaces'; +import { StudyCtrl, Topic } from './interfaces'; +import { VNode } from 'snabbdom/vnode' export interface TopicsCtrl { open: Prop; @@ -63,7 +63,7 @@ export function formView(ctrl: TopicsCtrl, userId?: string): VNode { }, [ h('textarea', { hook: onInsert(elm => setupTagify(elm, userId)) - }, ctrl.getTopics().join(', ')), + }, ctrl.getTopics().join(', ').replace(/[<>]/g, '')), h('button.button', { type: 'submit' }, ctrl.trans.noarg('apply')) diff --git a/ui/build b/ui/build index 8d0b27c5ed..8b6ae04df2 100755 --- a/ui/build +++ b/ui/build @@ -15,7 +15,7 @@ mkdir -p public/compiled apps1="common" apps2="chess ceval game tree chat nvui" -apps3="site swiss msg chat cli challenge notify learn insight editor puzzle round analyse lobby tournament tournamentSchedule tournamentCalendar simul dasher speech palantir serviceWorker dgt" +apps3="site swiss msg chat cli challenge notify learn insight editor puzzle round analyse lobby tournament tournamentSchedule tournamentCalendar simul dasher speech palantir serviceWorker dgt storm" site_plugins="tvEmbed puzzleEmbed analyseEmbed user modUser clas coordinate captcha expandText team forum account coachShow coachForm challengePage checkout login passwordComplexity tourForm teamBattleForm gameSearch userComplete infiniteScroll flatpickr teamAdmin" round_plugins="nvui keyboardMove" analyse_plugins="nvui studyTopicForm" diff --git a/ui/common/src/mini-board.ts b/ui/common/src/mini-board.ts new file mode 100644 index 0000000000..6b9a3a24fa --- /dev/null +++ b/ui/common/src/mini-board.ts @@ -0,0 +1,27 @@ +import * as domData from './data'; + +export const init = (node: HTMLElement): void => { + const [fen, orientation, lm] = node.getAttribute('data-state')!.split(','); + initWith(node, fen, orientation as Color, lm); +} + +export const initWith = (node: HTMLElement, fen: string, orientation: Color, lm?: string): void => { + if (!window.Chessground) setTimeout(() => init(node), 500); + else { + domData.set(node, 'chessground', window.Chessground(node, { + orientation, + coordinates: false, + viewOnly: !node.getAttribute('data-playable'), + resizable: false, + fen, + lastMove: lm && (lm[1] === '@' ? [lm.slice(2)] : [lm[0] + lm[1], lm[2] + lm[3]]), + drawable: { + enabled: false, + visible: false + } + })); + } +} + +export const initAll = (parent?: HTMLElement) => + Array.from((parent || document).getElementsByClassName('mini-board--init')).forEach(init); diff --git a/ui/common/src/number.ts b/ui/common/src/number.ts index 3e053dcb0f..5db2cdd22c 100644 --- a/ui/common/src/number.ts +++ b/ui/common/src/number.ts @@ -5,3 +5,26 @@ export const numberFormat = (n: number) => { if (numberFormatter === null) return '' + n; return numberFormatter.format(n); }; + +export const numberSpread = (el: HTMLElement, nbSteps: number, duration: number, previous: number) => { + let displayed: string; + const display = (prev: number, cur: number, it: number) => { + const val = numberFormat(Math.round(((prev * (nbSteps - 1 - it)) + (cur * (it + 1))) / nbSteps)); + if (val !== displayed) { + el.textContent = val; + displayed = val; + } + }; + let timeouts: Timeout[] = []; + return (nb: number, overrideNbSteps?: number) => { + if (!el || (!nb && nb !== 0)) return; + if (overrideNbSteps) nbSteps = Math.abs(overrideNbSteps); + timeouts.forEach(clearTimeout); + timeouts = []; + const prev = previous === 0 ? 0 : (previous || nb); + previous = nb; + const interv = Math.abs(duration / nbSteps); + for (let i = 0; i < nbSteps; i++) + timeouts.push(setTimeout(display.bind(null, prev, nb, i), Math.round(i * interv))); + }; +} diff --git a/ui/learn/src/run/stageComplete.js b/ui/learn/src/run/stageComplete.js index 95ee98c8e7..c7acb39355 100644 --- a/ui/learn/src/run/stageComplete.js +++ b/ui/learn/src/run/stageComplete.js @@ -1,7 +1,7 @@ var m = require('mithril'); var util = require('../util'); var scoring = require('../score'); -var numberFormat = require('common/number').numberFormat; +var numberSpread = require('common/number').numberSpread; function makeStars(rank) { var stars = []; @@ -27,9 +27,7 @@ module.exports = function(ctrl) { m('span', { config: function(el, isUpdate) { if (!isUpdate) setTimeout(function() { - spreadNumber(el, 50, function() { - return 3000; - }, 0)(score); + numberSpread(el, 50, 3000, 0)(score); }, 300); } }, 0) @@ -52,26 +50,3 @@ module.exports = function(ctrl) { ]) ); }; - -function spreadNumber(el, nbSteps, getDuration, previous) { - var displayed; - var display = function(prev, cur, it) { - var val = numberFormat(Math.round(((prev * (nbSteps - 1 - it)) + (cur * (it + 1))) / nbSteps)); - if (val !== displayed) { - el.textContent = val; - displayed = val; - } - }; - var timeouts = []; - return function(nb, overrideNbSteps) { - if (!el || (!nb && nb !== 0)) return; - if (overrideNbSteps) nbSteps = Math.abs(overrideNbSteps); - timeouts.forEach(clearTimeout); - timeouts = []; - var prev = previous === 0 ? 0 : (previous || nb); - previous = nb; - var interv = Math.abs(getDuration() / nbSteps); - for (var i = 0; i < nbSteps; i++) - timeouts.push(setTimeout(display.bind(null, prev, nb, i), Math.round(i * interv))); - }; -} diff --git a/ui/puzzle/css/_history.scss b/ui/puzzle/css/_history.scss index 983edf8a2c..e7e0a514e6 100644 --- a/ui/puzzle/css/_history.scss +++ b/ui/puzzle/css/_history.scss @@ -1,17 +1,19 @@ .puzzle-history { - &__session { margin-bottom: 5em; &__title { @extend %flex-between; + align-items: flex-end; margin-bottom: 1rem; + time { font-size: 1.5rem; margin-right: 1ch; } } + &__rounds { display: grid; grid-template-columns: repeat(auto-fill, minmax(15em, 1fr)); @@ -21,7 +23,6 @@ &__round { padding: .4em; - color: $c-font; &__meta { @extend %flex-between; @@ -32,6 +33,7 @@ } &:hover .puzzle-history__round__id { + color: $c-font; visibility: visible; } } diff --git a/ui/site/css/_page.scss b/ui/site/css/_page.scss index 294869cc55..fdb5168984 100644 --- a/ui/site/css/_page.scss +++ b/ui/site/css/_page.scss @@ -4,6 +4,8 @@ h2 { margin-top: 1.3em; + border-bottom: 1px solid $c-brag; + line-height: 2.5em; } p, @@ -29,7 +31,8 @@ h3 { @extend %roboto; - font-size: 1.3em; + font-size: 1.5em; + line-height: 2.5em; } h4 { diff --git a/ui/site/css/user/_activity.scss b/ui/site/css/user/_activity.scss index c2ccb42e63..29b8b6acdb 100644 --- a/ui/site/css/user/_activity.scss +++ b/ui/site/css/user/_activity.scss @@ -3,7 +3,7 @@ $c-contours: mix($c-brag, $c-shade, 80%); .activity { section { font-size: 1.2em; - margin-left: 1rem; + margin-left: 2rem; padding-top: 1rem; } diff --git a/ui/site/css/user/_trophy.scss b/ui/site/css/user/_trophy.scss index 2f3030bae6..fd505e6a09 100644 --- a/ui/site/css/user/_trophy.scss +++ b/ui/site/css/user/_trophy.scss @@ -99,10 +99,6 @@ text-shadow: none; color: #cd4606 !important; } - - &.bongcloudWarrior { - filter: hue-rotate(70deg); - } } .packed .trophy { diff --git a/ui/site/src/component/mini-board.ts b/ui/site/src/component/mini-board.ts deleted file mode 100644 index 4969c1b6b3..0000000000 --- a/ui/site/src/component/mini-board.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as domData from 'common/data'; - -export const init = (node: HTMLElement) => { - if (!window.Chessground) return setTimeout(() => init(node), 500); - const $el = $(node).removeClass('mini-board--init'), - [fen, orientation, lm] = $el.data('state').split(','); - domData.set(node, 'chessground', window.Chessground(node, { - orientation, - coordinates: false, - viewOnly: !node.getAttribute('data-playable'), - resizable: false, - fen, - lastMove: lm && (lm[1] === '@' ? [lm.slice(2)] : [lm[0] + lm[1], lm[2] + lm[3]]), - drawable: { - enabled: false, - visible: false - } - })); -} - -export const initAll = (parent?: HTMLElement) => - Array.from((parent || document).getElementsByClassName('mini-board--init')).forEach(init); diff --git a/ui/site/src/site.lichess.globals.ts b/ui/site/src/site.lichess.globals.ts index 75702616df..4b13f0373d 100644 --- a/ui/site/src/site.lichess.globals.ts +++ b/ui/site/src/site.lichess.globals.ts @@ -14,7 +14,7 @@ import { unload, redirect, reload } from "./component/reload"; import announce from "./component/announce"; import trans from "./component/trans"; import sound from "./component/sound"; -import * as miniBoard from "./component/mini-board"; +import * as miniBoard from "common/mini-board"; import * as miniGame from "./component/mini-game"; import { format as timeago } from "./component/timeago"; import watchers from "./component/watchers"; diff --git a/ui/site/src/site.ts b/ui/site/src/site.ts index cc742ee995..d00d99fade 100644 --- a/ui/site/src/site.ts +++ b/ui/site/src/site.ts @@ -1,4 +1,4 @@ -import * as miniBoard from "./component/mini-board"; +import * as miniBoard from "common/mini-board"; import * as miniGame from "./component/mini-game"; import * as timeago from "./component/timeago"; import * as xhr from 'common/xhr'; diff --git a/ui/storm/css/_clock.scss b/ui/storm/css/_clock.scss new file mode 100644 index 0000000000..7b5b960d41 --- /dev/null +++ b/ui/storm/css/_clock.scss @@ -0,0 +1,51 @@ +.storm { + &__clock { + @extend %flex-center-nowrap; + + font-family: 'storm'; + + &__time { + font-size: 6em; + transition: color .3s; + margin: 2vh 0; + + @include breakpoint($mq-col2) { + margin: 0; + } + + + .storm--mod-bonus-slow & { + color: $c-good; + } + + .storm--mod-malus-slow & { + color: $c-bad; + } + } + + @keyframes mod-fade-out { + from { + transform: translate(0, -10px); + opacity: 1; + } + + to { + transform: translate(0, -40px); + opacity: 0; + } + } + + &__bonus, &__malus { + font-size: 3.5em; + color: $c-good; + text-shadow: 0 0 15px $c-good; + margin-left: .3ch; + animation: mod-fade-out 1.1s ease-out; + } + + &__malus { + color: $c-bad; + text-shadow: 0 0 15px $c-bad; + } + } +} diff --git a/ui/storm/css/_combo.scss b/ui/storm/css/_combo.scss new file mode 100644 index 0000000000..3434ad14d0 --- /dev/null +++ b/ui/storm/css/_combo.scss @@ -0,0 +1,169 @@ +.storm { + &__combo { + display: flex; + flex-flow: row nowrap; + align-items: flex-end; + flex: 0 0 25%; + + &__counter { + display: flex; + flex-flow: column; + margin-bottom: .25em; + + &__value { + @extend %flex-center-nowrap; + + justify-content: center; + font-family: 'storm'; + font-size: 2.4em; + line-height: .9em; + width: 2ch; + } + + &__combo { + font-size: .8em; + letter-spacing: -1px; + color: $c-font-dim; + } + + transition: color .1s; + + .storm--mod-move & { + color: $c-brag; + } + } + + &__bars { + display: flex; + flex-flow: column; + flex: 1 1 100%; + margin-left: 1em; + } + + &__bar { + @extend %box-radius; + + $c-bar-base: $c-bg-zebra2; + $c-in-base: $c-brag; + $c-in-flash: mix($c-in-base, white, 75%); + + flex: 0 0 2.2em; + background: $c-bar-base; + border: $border; + position: relative; + + &__in, + &__in-full { + @extend %box-radius; + + position: absolute; + bottom: 0; + left: 0; + height: 100%; + } + + &__in { + background: $c-in-base; + box-shadow: 0 0 15px $c-in-base; + + .storm--mod-move & { + background: $c-in-flash; + box-shadow: 0 0 15px $c-in-flash; + } + + transition: all .5s ease-in-out; + + .storm--mod-bonus-slow & { + display: none; + } + + .storm--mod-malus-slow & { + transition-property: width; + background: $c-bad; + box-shadow: 0 0 10px $c-bad, 0 0 20px $c-bad; + } + } + + &__in-full { + background: $c-primary; + box-shadow: 0 0 10px $c-primary, 0 0 20px $c-primary; + width: 100%; + display: none; + opacity: 0; + + @keyframes bar-full { + from { + opacity: 1; + } + + to { + opacity: 0; + } + } + + .storm--mod-bonus-slow & { + display: block; + animation: bar-full .9s ease-in-out; + } + } + } + + &__levels { + @extend %flex-center; + + margin: .3em 0 0 -.6em; + } + + &__level { + $c-level: $c-primary; + + transform: skewX(-45deg); + flex: 21% 0 0; + margin-right: 4%; + font-size: .9em; + height: 1.5em; + line-height: 1.5em; + border: $border; + background: $c-bg-zebra; + text-align: center; + color: $c-font-dimmer; + font-weight: bold; + + span { + transform: skewX(45deg); + display: block; + } + + @keyframes level-fade-in { + from { + background: white; + box-shadow: 0 0 15px white, 0 0 25px white; + } + + to { + box-shadow: 0 0 10px $c-level; + } + } + + &.active { + animation: level-fade-in 1s ease-out; + background: mix($c-level, black, 80%); + border: 1px solid $c-level; + box-shadow: 0 0 10px $c-level; + color: white; + + &:nth-child(2) { + background: $c-level; + } + + &:nth-child(3) { + background: mix($c-level, white, 60%); + } + + &:nth-child(4) { + background: mix($c-level, white, 40%); + } + } + } + } +} diff --git a/ui/storm/css/_dashboard.scss b/ui/storm/css/_dashboard.scss new file mode 100644 index 0000000000..bb94f47b48 --- /dev/null +++ b/ui/storm/css/_dashboard.scss @@ -0,0 +1,33 @@ +@import "font"; +@import "play-again"; +@import "high"; + +.storm-dashboard { + + .storm-play-again { + margin: 2vh 0; + } + + &__history { + overflow: hidden; + + th:not(:first-child) { + text-align: right; + } + + td:not(:first-child) { + text-align: right; + } + + color: $c-font-dim; + + number { + font-family: 'storm'; + font-size: 2em; + + &.score { + color: $c-brag; + } + } + } +} diff --git a/ui/storm/css/_end.scss b/ui/storm/css/_end.scss new file mode 100644 index 0000000000..ede58cffcf --- /dev/null +++ b/ui/storm/css/_end.scss @@ -0,0 +1,109 @@ +@import "history"; +@import "play-again"; + +.storm--end { + display: grid; + + &__high { + grid-area: high; + } + + &__score { + grid-area: score; + } + + &__stats { + grid-area: stats; + } + + &__history { + grid-area: history; + } + + .storm-play-again { + grid-area: play; + } + + grid-row-gap: $block-gap; + grid-column-gap: $block-gap; + grid-template-areas: 'high' 'score' 'play' 'stats' 'history'; + + @include breakpoint($mq-col2) { + grid-template-areas: 'high high' 'score stats' 'play play' 'history history'; + } + + + &__high { + @extend %box-neat; + + padding: 1.5em 1.5em; + background: $c-brag; + color: $c-brag-over; + + &__content { + @extend %flex-between; + + @include breakpoint($mq-col2) { + &::before, + &::after { + content: ' '; + width: 7em; + height: 7em; + margin: 3em; + background-image: img-url("icons/tornado-white.svg"); + background-size: cover; + } + } + } + + &__text { + @extend %flex-column; + + align-items: center; + margin: auto; + + strong { + font-size: 2.5em; + margin: .5em 0; + } + } + } + + &__stats { + @extend %flex-center; + + padding: 2vh var(--box-padding); + align-items: stretch; + + table { + width: 100%; + + td { + padding: .5em 1em; + text-align: right; + + number { + font-size: 2em; + font-family: 'storm'; + } + } + } + } + + &__score { + @extend %box-neat, %flex-column; + + justify-content: center; + align-items: center; + background: $c-good; + color: $c-good-over; + padding: 1em 3em; + + &__number { + font-family: 'storm'; + font-size: 14em; + width: 3ch; + text-align: center; + } + } +} diff --git a/ui/storm/css/_font.scss b/ui/storm/css/_font.scss new file mode 100644 index 0000000000..2a2ebb8db1 --- /dev/null +++ b/ui/storm/css/_font.scss @@ -0,0 +1,7 @@ +@font-face { + font-family: 'storm'; + font-style: normal; + font-weight: 400; + + src: url("#{$font-path}/Segment7.woff2") format("woff2"), url("#{$font-path}/Segment7.woff") format("woff"); +} diff --git a/ui/storm/css/_high.scss b/ui/storm/css/_high.scss new file mode 100644 index 0000000000..bd15babfec --- /dev/null +++ b/ui/storm/css/_high.scss @@ -0,0 +1,39 @@ +.storm-dashboard__high { + &__periods { + display: flex; + flex-flow: row wrap; + } + + &__period { + @extend %flex-column, %box-neat; + + align-items: center; + justify-content: center; + flex: 1 1 auto; + margin-right: 2vw; + background: $c-bg-box; + padding: 1.5em 1em; + + strong { + font-family: 'storm'; + font-weight: normal; + font-size: 5em; + } + + .highlight-alltime & { + &:first-child { + background: $c-brag; + color: $c-brag-over; + + strong { + font-size: 10em; + line-height: 1em; + } + } + } + + &:last-child { + margin-right: 0; + } + } +} diff --git a/ui/storm/css/_history.scss b/ui/storm/css/_history.scss new file mode 100644 index 0000000000..5b203c1497 --- /dev/null +++ b/ui/storm/css/_history.scss @@ -0,0 +1,75 @@ +.storm--end { + &__history { + + h2 { + margin: -.5em 0 1em 0; + } + + &__rounds { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(12em, 1fr)); + align-content: start; + } + + &__round { + padding: .4em; + + &__meta { + @extend %flex-between; + } + + &__result { + @extend %flex-center-nowrap; + + rating { + @extend %page-text; + + font-size: .9em; + } + } + + &__id { + @extend %page-text; + + visibility: hidden; + } + + &:hover .storm__history__round__id { + color: $c-font; + visibility: visible; + } + } + + good, bad { + @extend %flex-center; + + color: white; + padding: 0 .5em .1em .3em; + margin-right: 1ch; + font-size: .9em; + opacity: .7; + + &::before { + @extend %data-icon; + + margin-right: .2em; + } + } + + good { + background: $c-good; + + &::before { + content: 'E'; + } + } + + bad { + background: $c-bad; + + &::before { + content: 'L'; + } + } + } +} diff --git a/ui/storm/css/_play-again.scss b/ui/storm/css/_play-again.scss new file mode 100644 index 0000000000..c8bbb5cba5 --- /dev/null +++ b/ui/storm/css/_play-again.scss @@ -0,0 +1,49 @@ +@keyframes play-shake { + 10%, 90% { + transform: translate3d(-1px, 0, 0); + } + + 20%, 80% { + transform: translate3d(2px, 0, 0); + } + + 30%, 50%, 70% { + transform: translate3d(-4px, 0, 0); + } + + 40%, 60% { + transform: translate3d(4px, 0, 0); + } +} + +.storm-play-again { + @extend %flex-center; + + justify-content: center; + padding: 1em 2em; + font-size: 2em; + letter-spacing: .6em; + + @include breakpoint($mq-small) { + justify-content: space-between; + + &::before, + &::after { + content: ' '; + width: 7rem; + height: 7rem; + background-image: img-url("icons/tornado-white.svg"); + background-size: cover; + opacity: .8; + transition: opacity .5s; + } + + &[href]:hover { + &::before, + &::after { + opacity: 1; + animation: play-shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; + } + } + } +} diff --git a/ui/storm/css/_play.scss b/ui/storm/css/_play.scss new file mode 100644 index 0000000000..6b9adc77bf --- /dev/null +++ b/ui/storm/css/_play.scss @@ -0,0 +1,27 @@ +@import "side"; +@import "combo"; +@import "clock"; + +.storm { + &--play { + display: grid; + + &__side { + grid-area: side; + } + + &__board { + grid-area: board; + } + + grid-row-gap: $block-gap; + grid-column-gap: $block-gap; + grid-template-areas: 'board' 'side'; + + @include breakpoint($mq-col2) { + grid-template-columns: $col2-uniboard-width $col2-uniboard-table; + grid-template-rows: fit-content(0); + grid-template-areas: 'board side'; + } + } +} diff --git a/ui/storm/css/_side.scss b/ui/storm/css/_side.scss new file mode 100644 index 0000000000..003508366c --- /dev/null +++ b/ui/storm/css/_side.scss @@ -0,0 +1,70 @@ +.storm { + &__side { + @extend %box-neat; + + display: flex; + flex-flow: column; + justify-content: space-between; + background: $c-bg-box; + padding: 3vh 2vw; + margin: 0; + } + + &__top { + flex: 0 0 25%; + display: flex; + flex-flow: row nowrap; + + &::before { + content: ' '; + width: 5rem; + height: 5rem; + background-image: img-url("icons/tornado.svg"); + background-repeat: no-repeat; + margin-right: 1.5rem; + } + } + + &__start { + color: $c-brag; + margin: auto; + + @include breakpoint($mq-col2) { + margin: 0; + } + + + &__text { + @extend %flex-column; + + strong { + font-size: 2.2em; + font-weight: normal; + } + + span { + @extend %roboto; + + font-size: 1.5em; + letter-spacing: .2em; + } + } + } + + &__solved { + text-align: center; + white-space: nowrap; + + &__text { + font-family: 'storm'; + font-size: 5.5rem; + color: $c-brag; + margin-right: 1rem; + transition: text-shadow .1s; + } + + .storm--mod-puzzle & { + text-shadow: 0 0 15px white; + } + } +} diff --git a/ui/storm/css/_storm.scss b/ui/storm/css/_storm.scss new file mode 100644 index 0000000000..f0ad364003 --- /dev/null +++ b/ui/storm/css/_storm.scss @@ -0,0 +1,63 @@ +$mq-col2: $mq-col2-uniboard; + +#main-wrap { + --main-max-width: calc(100vh - #{$site-header-outer-height} - #{$col1-uniboard-controls}); + + @include breakpoint($mq-col2) { + --main-max-width: auto; + } + + + user-select: none; +} + +@import "font"; +@import "play"; +@import "end"; +@import "high"; + +.storm { + &-play-scores { + @extend %flex-between; + + color: $c-font-page; + margin: 2vh 2vw; + + @include breakpoint($mq-col2) { + margin: 2vh .5rem; + } + + + span { + text-transform: uppercase; + } + } + + &-dashboard__high__periods { + @include breakpoint($mq-not-xx-small) { + display: none; + } + } + + &--dup { + @extend %flex-column; + + justify-content: stretch; + text-align: center; + + i { + font-size: 15em; + line-height: 1.2em; + } + + p { + margin: 3em 0; + } + } + + &__about__link { + margin-top: 2vh; + text-align: center; + font-size: .8em; + } +} diff --git a/ui/storm/css/build/_storm.dashboard.scss b/ui/storm/css/build/_storm.dashboard.scss new file mode 100644 index 0000000000..856339949e --- /dev/null +++ b/ui/storm/css/build/_storm.dashboard.scss @@ -0,0 +1,4 @@ +@import "../../../common/css/plugin"; +@import "../../../common/css/component/slist"; + +@import "../dashboard"; diff --git a/ui/storm/css/build/_storm.scss b/ui/storm/css/build/_storm.scss new file mode 100644 index 0000000000..12fa18f30a --- /dev/null +++ b/ui/storm/css/build/_storm.scss @@ -0,0 +1,8 @@ +@import "../../../common/css/plugin"; +@import "../../../common/css/vendor/chessground/coords"; +@import "../../../common/css/layout/uniboard"; +@import "../../../common/css/component/board-resize"; +@import "../../../common/css/component/bar-glider"; +@import "../../../chess/css/promotion"; + +@import "../storm"; diff --git a/ui/storm/css/build/storm.dark.scss b/ui/storm/css/build/storm.dark.scss new file mode 100644 index 0000000000..33765a2d71 --- /dev/null +++ b/ui/storm/css/build/storm.dark.scss @@ -0,0 +1,2 @@ +@import '../../../common/css/theme/dark'; +@import 'storm'; diff --git a/ui/storm/css/build/storm.dashboard.dark.scss b/ui/storm/css/build/storm.dashboard.dark.scss new file mode 100644 index 0000000000..3a218e3986 --- /dev/null +++ b/ui/storm/css/build/storm.dashboard.dark.scss @@ -0,0 +1,2 @@ +@import '../../../common/css/theme/dark'; +@import 'storm.dashboard'; diff --git a/ui/storm/css/build/storm.dashboard.light.scss b/ui/storm/css/build/storm.dashboard.light.scss new file mode 100644 index 0000000000..50ea62238d --- /dev/null +++ b/ui/storm/css/build/storm.dashboard.light.scss @@ -0,0 +1,2 @@ +@import '../../../common/css/theme/light'; +@import 'storm.dashboard'; diff --git a/ui/storm/css/build/storm.dashboard.transp.scss b/ui/storm/css/build/storm.dashboard.transp.scss new file mode 100644 index 0000000000..ba20999a86 --- /dev/null +++ b/ui/storm/css/build/storm.dashboard.transp.scss @@ -0,0 +1,2 @@ +@import '../../../common/css/theme/transp'; +@import 'storm.dashboard'; diff --git a/ui/storm/css/build/storm.light.scss b/ui/storm/css/build/storm.light.scss new file mode 100644 index 0000000000..993c373e9f --- /dev/null +++ b/ui/storm/css/build/storm.light.scss @@ -0,0 +1,2 @@ +@import '../../../common/css/theme/light'; +@import 'storm'; diff --git a/ui/storm/css/build/storm.transp.scss b/ui/storm/css/build/storm.transp.scss new file mode 100644 index 0000000000..36d1c3a17a --- /dev/null +++ b/ui/storm/css/build/storm.transp.scss @@ -0,0 +1,2 @@ +@import '../../../common/css/theme/transp'; +@import 'storm'; diff --git a/ui/storm/package.json b/ui/storm/package.json new file mode 100644 index 0000000000..d022cf9778 --- /dev/null +++ b/ui/storm/package.json @@ -0,0 +1,27 @@ +{ + "name": "storm", + "version": "2.0.0", + "private": true, + "description": "lichess.org puzzle storm", + "keywords": [ + "chess", + "lichess", + "puzzle", + "storm" + ], + "author": "Thibault Duplessis", + "license": "AGPL-3.0-or-later", + "devDependencies": { + "@build/rollupProject": "2.0.0", + "@types/lichess": "2.0.0" + }, + "dependencies": { + "chessground": "^7.9.2", + "common": "2.0.0", + "snabbdom": "^0.7.4" + }, + "scripts": { + "dev": "rollup --config", + "prod": "rollup --config --config-prod" + } +} diff --git a/ui/storm/rollup.config.js b/ui/storm/rollup.config.js new file mode 100644 index 0000000000..9e9b805be3 --- /dev/null +++ b/ui/storm/rollup.config.js @@ -0,0 +1,9 @@ +import { rollupProject } from '@build/rollupProject'; + +export default rollupProject({ + main: { + name: 'LichessStorm', + input: 'src/main.ts', + output: 'storm', + }, +}); diff --git a/ui/storm/src/config.ts b/ui/storm/src/config.ts new file mode 100644 index 0000000000..deb62b3adc --- /dev/null +++ b/ui/storm/src/config.ts @@ -0,0 +1,30 @@ +// [combo threshold, time bonus] +const realLevels = [ + [0, 0], + [5, 3], + [12, 5], + [20, 7], + [30, 10] +]; +const quickLevels = [ + [0, 0], + [3, 5], + [9, 10], + [12, 15], + [15, 20] +]; + +const config = { + // all times in seconds + clock: { + initial: 3 * 60, + // initial: 10, + malus: 10 + }, + combo: { + levels: realLevels, + // levels: quickLevels, + } +}; + +export default config; diff --git a/ui/storm/src/ctrl.ts b/ui/storm/src/ctrl.ts new file mode 100644 index 0000000000..3626243a44 --- /dev/null +++ b/ui/storm/src/ctrl.ts @@ -0,0 +1,247 @@ +import * as xhr from './xhr'; +import config from './config'; +import makePromotion from './promotion'; +import { Api as CgApi } from 'chessground/api'; +import { Chess } from 'chessops/chess'; +import { chessgroundDests } from 'chessops/compat'; +import { Config as CgConfig } from 'chessground/config'; +import { getNow } from './util'; +import { parseFen, makeFen } from 'chessops/fen'; +import { parseUci, opposite } from 'chessops/util'; +import { prop, Prop } from 'common'; +import { Role } from 'chessground/types'; +import { StormOpts, StormData, StormPuzzle, StormVm, Promotion, TimeMod, StormRun } from './interfaces'; + +export default class StormCtrl { + + data: StormData; + vm: StormVm; + trans: Trans; + promotion: Promotion; + ground = prop(false) as Prop; + + constructor(readonly opts: StormOpts, readonly redraw: () => void) { + this.data = opts.data; + this.trans = lichess.trans(opts.i18n); + this.vm = { + puzzleIndex: 0, + moveIndex: 0, + clock: config.clock.initial * 1000, + history: [], + combo: 0, + comboBest: 0, + modifier: { + moveAt: 0 + }, + run: { + startAt: 0, + moves: 0, + errors: 0 + }, + }; + this.promotion = makePromotion(this.withGround, this.makeCgOpts, redraw); + this.checkDupTab(); + } + + clockMillis = (): number | undefined => + this.vm.run.startAt && Math.max(0, this.vm.run.startAt + this.vm.clock - getNow()); + + end = (): void => { + this.vm.history.reverse(); + this.vm.run.endAt = getNow(); + this.ground(false); + this.redraw(); + this.sound.end(); + xhr.record(this.runStats(), this.data.notAnExploit).then(res => { + this.vm.run.response = res; + this.redraw(); + }); + this.redrawSlow(); + } + + naturalFlag = () => { + this.pushToHistory(false); + this.end(); + }; + + userMove = (orig: Key, dest: Key): void => { + if (!this.promotion.start(orig, dest, this.playUserMove)) this.playUserMove(orig, dest); + } + + playUserMove = (orig: Key, dest: Key, promotion?: Role): void => { + if (!this.vm.run.moves) this.vm.run.startAt = getNow(); + this.vm.run.moves++; + this.promotion.cancel(); + const expected = this.line()[this.vm.moveIndex + 1]; + const uci = `${orig}${dest}${promotion ? (promotion == 'knight' ? 'n' : promotion[0]) : ''}`; + const pos = this.position(); + const move = parseUci(uci)!; + const capture = pos.board.occupied.has(move.to); + pos.play(move); + if (pos.isCheckmate() || uci == expected) { + this.vm.moveIndex++; + this.vm.combo++; + this.vm.comboBest = Math.max(this.vm.comboBest, this.vm.combo); + this.vm.modifier.moveAt = getNow(); + const bonus = this.computeComboBonus(); + if (bonus) { + this.vm.modifier.bonus = bonus; + this.vm.clock += bonus.seconds * 1000; + this.sound.bonus(); + } + this.sound.move(capture); + if (this.vm.moveIndex == this.line().length - 1) { + this.pushToHistory(true); + this.vm.moveIndex = 0; + if (!this.incPuzzle()) this.end(); + } else { + this.vm.moveIndex++; + } + } else { + lichess.sound.play('error'); + this.pushToHistory(false); + this.vm.run.errors++; + this.vm.combo = 0; + this.vm.clock -= config.clock.malus * 1000; + this.vm.modifier.malus = { + seconds: config.clock.malus, + at: getNow() + }; + if (!this.boundedClockMillis()) this.end(); + else { + this.vm.moveIndex = 0; + if (!this.incPuzzle()) this.end(); + } + } + this.redraw(); + this.redrawQuick(); + this.redrawSlow(); + this.withGround(this.showGround); + }; + + private redrawQuick = () => setTimeout(this.redraw, 100); + private redrawSlow = () => setTimeout(this.redraw, 1000); + + private computeComboBonus = (): TimeMod | undefined => { + if (this.comboPercent() == 0) { + const level = this.comboLevel(); + if (level > 0) return { + seconds: config.combo.levels[level][1], + at: getNow() + }; + } + return; + }; + + boundedClockMillis = () => this.vm.run.startAt ? + Math.max(0, this.vm.run.startAt + this.vm.clock - getNow()) : + this.vm.clock; + + private pushToHistory = (win: boolean) => { + const now = getNow(); + this.vm.history.push({ + puzzle: this.puzzle(), + win, + millis: this.vm.puzzleStartAt ? now - this.vm.puzzleStartAt : 0 + }); + this.vm.puzzleStartAt = now; + }; + + private incPuzzle = (): boolean => { + if (this.vm.puzzleIndex < this.data.puzzles.length - 1) { + this.vm.puzzleIndex++; + return true; + } + return false; + } + + puzzle = (): StormPuzzle => this.data.puzzles[this.vm.puzzleIndex]; + + line = (): Uci[] => this.puzzle().line.split(' '); + + position = (): Chess => { + const pos = Chess.fromSetup(parseFen(this.puzzle().fen).unwrap()).unwrap(); + this.line().slice(0, this.vm.moveIndex + 1).forEach(uci => + pos.play(parseUci(uci)!) + ); + return pos; + } + + makeCgOpts = (): CgConfig => { + const puzzle = this.puzzle(); + const pos = this.position(); + const pov = opposite(parseFen(puzzle.fen).unwrap().turn); + const canMove = !this.vm.run.endAt; + return { + fen: makeFen(pos.toSetup()), + orientation: pov, + turnColor: pos.turn, + movable: canMove ? { + color: pov, + dests: chessgroundDests(pos) + } : undefined, + premovable: { + enabled: false + }, + check: !!pos.isCheck(), + lastMove: this.uciToLastMove(this.line()[this.vm.moveIndex]) + }; + } + + comboLevel = () => config.combo.levels.reduce((lvl, [threshold, _], index) => threshold <= this.vm.combo ? index : lvl, 0); + + comboPercent = () => { + const lvl = this.comboLevel(); + const levels = config.combo.levels; + const lastLevel = levels[levels.length - 1]; + if (lvl >= levels.length - 1) { + const range = (lastLevel[0] - levels[levels.length - 2][0]); + return ((this.vm.combo - lastLevel[0]) / range) * 100 % 100; + } + const bounds = [levels[lvl][0], levels[lvl + 1][0]]; + return Math.floor((this.vm.combo - bounds[0]) / (bounds[1] - bounds[0]) * 100); + }; + + countWins = (): number => this.vm.history.reduce((c, r) => c + (r.win ? 1 : 0), 0); + + withGround = (f: (cg: CgApi) => A): A | false => { + const g = this.ground(); + return g && f(g); + } + + runStats = (): StormRun => ({ + puzzles: this.vm.history.length, + score: this.countWins(), + moves: this.vm.run.moves, + errors: this.vm.run.errors, + combo: this.vm.comboBest, + time: (this.vm.run.endAt! - this.vm.run.startAt) / 1000, + highest: this.vm.history.reduce((h, r) => r.win && r.puzzle.rating > h ? r.puzzle.rating : h, 0) + }); + + private showGround = (g: CgApi): void => g.set(this.makeCgOpts()); + + private uciToLastMove = (uci: string): [Key, Key] => [uci.substr(0, 2) as Key, uci.substr(2, 2) as Key]; + + private loadSound = (file: string, volume?: number) => { + lichess.sound.loadOggOrMp3(file, `${lichess.sound.baseUrl}/${file}`); + return () => lichess.sound.play(file, volume); + }; + + private sound = { + move: (take: boolean) => lichess.sound.play(take ? 'capture' : 'move'), + bonus: this.loadSound('other/ping', 0.8), + end: this.loadSound('other/gewonnen', 0.6) + }; + + private checkDupTab = () => { + const dupTabMsg = lichess.storage.make('storm.tab'); + dupTabMsg.fire(this.data.puzzles[0].id); + dupTabMsg.listen(ev => { + if (!this.vm.run.startAt && ev.value == this.data.puzzles[0].id) { + this.vm.dupTab = true; + this.redraw(); + } + }); + } +} diff --git a/ui/storm/src/interfaces.ts b/ui/storm/src/interfaces.ts new file mode 100644 index 0000000000..87b99c731b --- /dev/null +++ b/ui/storm/src/interfaces.ts @@ -0,0 +1,100 @@ +import { Role } from 'chessground/types'; +import { VNode } from 'snabbdom/vnode' + +export type MaybeVNode = VNode | string | null | undefined; +export type MaybeVNodes = MaybeVNode[]; +export type Redraw = () => void; + +export interface StormOpts { + data: StormData; + pref: StormPrefs; + i18n: any; +} + +export interface StormPrefs { + coords: 0 | 1 | 2; + is3d: boolean; + destination: boolean; + rookCastle: boolean; + moveEvent: number; + highlight: boolean; +} + +export interface StormData { + puzzles: StormPuzzle[]; + notAnExploit: string; +} + +export interface StormVm { + puzzleIndex: number; + moveIndex: number; + clock: number; + history: Round[]; + puzzleStartAt?: number; + combo: number; + comboBest: number; + modifier: StormModifier; + run: { + startAt: number; + endAt?: number; + moves: number; + errors: number; + response?: RunResponse; + } + dupTab?: boolean; +} + +export interface Round { + puzzle: StormPuzzle; + win: boolean; + millis: number; +} + +export interface StormModifier { + moveAt: number; + malus?: TimeMod; + bonus?: TimeMod; +} + +export interface TimeMod { + seconds: number; + at: number; +} + +export interface StormPuzzle { + id: string; + fen: string; + line: string; + rating: number; +} + +export interface Promotion { + start(orig: Key, dest: Key, callback: (orig: Key, dest: Key, prom: Role) => void): boolean; + cancel(): void; + view(): MaybeVNode; +} + +export interface DailyBest { + score: number; + prev?: number; + at: number; +} + +export interface StormRun { + puzzles: number; + score: number; + moves: number; + errors: number; + combo: number; + time: number; + highest: number; +} + +export interface RunResponse { + newHigh?: NewHigh; +} + +export interface NewHigh { + key: 'day' | 'week' | 'month' | 'allTime'; + prev: number; +} diff --git a/ui/storm/src/main.ts b/ui/storm/src/main.ts new file mode 100644 index 0000000000..b73eeae09f --- /dev/null +++ b/ui/storm/src/main.ts @@ -0,0 +1,38 @@ +import attributes from 'snabbdom/modules/attributes'; +import klass from 'snabbdom/modules/class'; +import menuHover from 'common/menuHover'; +import StormCtrl from './ctrl'; +import { Chessground } from 'chessground'; +import { init } from 'snabbdom'; +import { StormOpts } from './interfaces'; +import { VNode } from 'snabbdom/vnode' + + +const patch = init([klass, attributes]); + +import view from './view/main'; + +export function start(opts: StormOpts) { + + const element = document.querySelector('.storm-app') as HTMLElement; + + let vnode: VNode; + + function redraw() { + vnode = patch(vnode, view(ctrl)); + } + + const ctrl = new StormCtrl(opts, redraw); + + const blueprint = view(ctrl); + element.innerHTML = ''; + vnode = patch(element, blueprint); + + redraw(); + + menuHover(); +}; + +// that's for the rest of lichess to access chessground +// without having to include it a second time +window.Chessground = Chessground; diff --git a/ui/storm/src/promotion.ts b/ui/storm/src/promotion.ts new file mode 100644 index 0000000000..b1cf964f1a --- /dev/null +++ b/ui/storm/src/promotion.ts @@ -0,0 +1,96 @@ +import { h } from 'snabbdom'; +import { bind, onInsert } from './util'; +import { Api as CgApi } from 'chessground/api'; +import { Config as CgConfig } from 'chessground/config'; +import * as cgUtil from 'chessground/util'; +import { Role } from 'chessground/types'; +import { MaybeVNode, Redraw, Promotion } from './interfaces'; + +export default function(withGround: (f: (cg: CgApi) => A) => A | false, makeCgOpts: () => CgConfig, redraw: Redraw): Promotion { + + let promoting: any = false; + + function start(orig: Key, dest: Key, callback: (orig: Key, key: Key, prom: Role) => void) { + return !!withGround(g => { + const piece = g.state.pieces.get(dest); + if (piece && piece.role == 'pawn' && ( + (dest[1] == '8' && g.state.turnColor == 'black') || + (dest[1] == '1' && g.state.turnColor == 'white'))) { + promoting = { + orig: orig, + dest: dest, + callback: callback + }; + redraw(); + return true; + } + return false; + }); + } + + function promote(g: CgApi, key: Key, role: Role): void { + const piece = g.state.pieces.get(key); + if (piece && piece.role == 'pawn') { + g.setPieces(new Map([[key, { + color: piece.color, + role, + promoted: true, + }]])); + } + } + + function finish(role: Role): void { + if (promoting) withGround(g => promote(g, promoting.dest, role)); + if (promoting.callback) promoting.callback(promoting.orig, promoting.dest, role); + promoting = false; + } + + function cancel(): void { + if (promoting) { + promoting = false; + withGround(g => g.set(makeCgOpts())); + redraw(); + } + } + + function renderPromotion(dest: Key, pieces: Role[], color: Color, orientation: Color): MaybeVNode { + if (!promoting) return; + + let left = (7 - cgUtil.key2pos(dest)[0]) * 12.5; + if (orientation === 'white') left = 87.5 - left; + + const vertical = color === orientation ? 'top' : 'bottom'; + + return h('div#promotion-choice.' + vertical, { + hook: onInsert(el => { + el.addEventListener('click', cancel); + el.oncontextmenu = () => false; + }) + }, pieces.map(function(serverRole, i) { + const top = (color === orientation ? i : 7 - i) * 12.5; + return h('square', { + attrs: { + style: 'top: ' + top + '%;left: ' + left + '%' + }, + hook: bind('click', e => { + e.stopPropagation(); + finish(serverRole); + }) + }, [h('piece.' + serverRole + '.' + color)]); + })); + } + + return { + start, + cancel, + view() { + if (!promoting) return; + const pieces: Role[] = ['queen', 'knight', 'rook', 'bishop']; + return withGround(g => + renderPromotion(promoting.dest, pieces, + cgUtil.opposite(g.state.turnColor), + g.state.orientation) + ) || null; + } + }; +} diff --git a/ui/storm/src/util.ts b/ui/storm/src/util.ts new file mode 100644 index 0000000000..0e91a1c964 --- /dev/null +++ b/ui/storm/src/util.ts @@ -0,0 +1,21 @@ +import { Hooks } from 'snabbdom/hooks'; + +export function bind(eventName: string, f: (e: Event) => any, redraw?: () => void): Hooks { + return onInsert(el => + el.addEventListener(eventName, e => { + const res = f(e); + if (redraw) redraw(); + return res; + }) + ); +} + +export function onInsert(f: (element: A) => void): Hooks { + return { + insert: vnode => f(vnode.elm as A) + }; +} + +export function getNow(): number { + return Math.round(performance.now()); +} diff --git a/ui/storm/src/view/chessground.ts b/ui/storm/src/view/chessground.ts new file mode 100644 index 0000000000..f87db1c748 --- /dev/null +++ b/ui/storm/src/view/chessground.ts @@ -0,0 +1,66 @@ +import StormCtrl from '../ctrl'; +import changeColorHandle from 'common/coordsColor'; +import resizeHandle from 'common/resize'; +import { Chessground } from 'chessground'; +import { Config as CgConfig } from 'chessground/config'; +import { h } from 'snabbdom' +import { VNode } from 'snabbdom/vnode'; + +export default function(ctrl: StormCtrl): VNode { + return h('div.cg-wrap', { + hook: { + insert: vnode => ctrl.ground(Chessground((vnode.elm as HTMLElement), makeConfig(ctrl))), + destroy: _ => ctrl.withGround(g => g.destroy()) + } + }); +} + +function makeConfig(ctrl: StormCtrl): CgConfig { + const opts = ctrl.makeCgOpts(); + const pref = ctrl.opts.pref; + return { + fen: opts.fen, + orientation: opts.orientation, + turnColor: opts.turnColor, + check: opts.check, + lastMove: opts.lastMove, + coordinates: pref.coords !== 0, + addPieceZIndex: pref.is3d, + movable: { + free: false, + color: opts.movable!.color, + dests: opts.movable!.dests, + showDests: pref.destination, + rookCastle: pref.rookCastle + }, + draggable: { + enabled: pref.moveEvent > 0, + showGhost: pref.highlight + }, + selectable: { + enabled: pref.moveEvent !== 1 + }, + events: { + move: ctrl.userMove, + insert(elements) { + resizeHandle(elements, 2, 0, (_) => !ctrl.clockMillis()); + if (pref.coords == 1) changeColorHandle(); + } + }, + premovable: { + enabled: false + }, + drawable: { + enabled: true, + defaultSnapToValidMove: (lichess.storage.get('arrow.snap') || 1) != '0' + }, + highlight: { + lastMove: pref.highlight, + check: pref.highlight + }, + animation: { + enabled: false + }, + disableContextMenu: true + }; +} diff --git a/ui/storm/src/view/clock.ts b/ui/storm/src/view/clock.ts new file mode 100644 index 0000000000..8f89b147ae --- /dev/null +++ b/ui/storm/src/view/clock.ts @@ -0,0 +1,54 @@ +import StormCtrl from '../ctrl'; +import { defined } from 'common'; +import { getNow } from '../util'; +import { h } from 'snabbdom'; +import { VNode } from 'snabbdom/vnode'; +import { TimeMod } from '../interfaces'; + +let refreshInterval: Timeout; + +export default function renderClock(ctrl: StormCtrl): VNode { + const malus = ctrl.vm.modifier.malus; + const bonus = ctrl.vm.modifier.bonus; + return h('div.storm__clock', [ + h('div.storm__clock__time', { + hook: { + insert(node) { + const el = node.elm as HTMLDivElement; + el.innerText = formatMs(ctrl.vm.clock); + refreshInterval = setInterval(() => renderIn(ctrl, el), 100); + }, + destroy() { + if (refreshInterval) clearInterval(refreshInterval); + } + } + }), + !!malus && malus.at > getNow() - 900 ? h('div.storm__clock__malus', '-' + malus.seconds) : null, + !!bonus && bonus.at > getNow() - 900 ? h('div.storm__clock__bonus', '+' + bonus.seconds) : null + ]); +} + +function renderIn(ctrl: StormCtrl, el: HTMLElement) { + if (!ctrl.vm.run.startAt) return; + const clock = ctrl.vm.clock; + const mods = ctrl.vm.modifier; + const now = getNow(); + const millis = ctrl.vm.run.startAt + clock - getNow(); + const diffs = computeModifierDiff(now, mods.bonus) - computeModifierDiff(now, mods.malus); + el.innerText = formatMs(millis - diffs); + if (millis < 1 && !ctrl.vm.run.endAt) ctrl.naturalFlag(); +} + +const pad = (x: number): string => (x < 10 ? '0' : '') + x; + +const formatMs = (millis: number): string => { + const date = new Date(Math.max(0, Math.ceil(millis / 1000) * 1000)), + minutes = date.getUTCMinutes(), + seconds = date.getUTCSeconds(); + return minutes + ':' + pad(seconds); +} + +function computeModifierDiff(now: number, mod?: TimeMod) { + const millisSince: number | undefined = mod && (now - mod.at < 1000 ? now - mod.at : undefined); + return defined(millisSince) ? mod!.seconds * 1000 * (1 - millisSince / 1000) : 0; +} diff --git a/ui/storm/src/view/end.ts b/ui/storm/src/view/end.ts new file mode 100644 index 0000000000..35fbf80cb6 --- /dev/null +++ b/ui/storm/src/view/end.ts @@ -0,0 +1,109 @@ +import * as miniBoard from "common/mini-board"; +import StormCtrl from '../ctrl'; +import { Chess } from 'chessops/chess'; +import { getNow, onInsert } from '../util'; +import { h } from 'snabbdom' +import { numberSpread } from 'common/number'; +import { parseFen, makeFen } from 'chessops/fen'; +import { parseUci } from 'chessops/util'; +import { VNode } from 'snabbdom/vnode'; + +const renderEnd = (ctrl: StormCtrl): VNode[] => [ + ...renderSummary(ctrl), + renderHistory(ctrl) +]; + +const newHighI18n = { + day: 'newDailyHighscore', + week: 'newWeeklyHighscore', + month: 'newMonthlyHighscore', + allTime: 'newAllTimeHighscore' +} + +const renderSummary = (ctrl: StormCtrl): VNode[] => { + const run = ctrl.runStats(); + const high = ctrl.vm.run.response?.newHigh; + const accuracy = 100 * (run.moves - run.errors) / run.moves; + return [ + ...(high ? [ + h('div.storm--end__high.storm--end__high-daily.bar-glider', + h('div.storm--end__high__content', [ + h('div.storm--end__high__text', [ + h('strong', ctrl.trans(newHighI18n[high.key])), + high.prev ? h('span', ctrl.trans('previousHighscoreWasX', high.prev)) : null + ]) + ]) + )] : []), + h('div.storm--end__score', [ + h('span.storm--end__score__number', { + hook: onInsert(el => numberSpread(el, run.score, Math.round(run.score * 50), 0)(run.score)) + }, '0'), + h('p', ctrl.trans('puzzlesSolved')) + ]), + h('div.storm--end__stats.box.box-pad', [ + h('table.slist', [ + h('tbody', [ + h('tr', [ + h('th', 'Moves played'), + h('td', h('number', run.moves)) + ]), + h('tr', [ + h('th', 'Accuracy'), + h('td', [h('number', Number(accuracy).toFixed(1)), '%']) + ]), + h('tr', [ + h('th', 'Best combo'), + h('td', h('number', ctrl.vm.comboBest)) + ]), + h('tr', [ + h('th', 'Total time'), + h('td', [h('number', Math.round(run.time)), 's']) + ]), + h('tr', [ + h('th', 'Time per move'), + h('td', [h('number', Number(run.time / run.moves).toFixed(2)), 's']) + ]), + h('tr', [ + h('th', 'Highest solved'), + h('td', h('number', run.highest)) + ]) + ]) + ]) + ]), + h('a.storm-play-again.button', { + attrs: ctrl.vm.run.endAt! < getNow() - 900 ? { href: '/storm' } : {} + }, ctrl.trans('playAgain')) + ]; +} + +const renderHistory = (ctrl: StormCtrl): VNode => + h('div.storm--end__history.box.box-pad', [ + h('h2', 'Puzzles played'), + h('div.storm--end__history__rounds', + ctrl.vm.history.map(round => + h('div.storm--end__history__round', [ + h('a.storm--end__history__round__puzzle.mini-board.cg-wrap.is2d', { + attrs: { + href: `/training/${round.puzzle.id}`, + target: '_blank' + }, + hook: onInsert(e => { + const pos = Chess.fromSetup(parseFen(round.puzzle.fen).unwrap()).unwrap(); + const uci = round.puzzle.line.split(' ')[0]; + pos.play(parseUci(uci)!); + miniBoard.initWith(e, makeFen(pos.toSetup()), pos.turn, uci); + }) + }), + h('span.storm--end__history__round__meta', [ + h('span.storm--end__history__round__result', [ + h(round.win ? 'good' : 'bad', Math.round(round.millis / 1000) + 's'), + h('rating', round.puzzle.rating) + ]), + h('span.storm--end__history__round__id', '#' + round.puzzle.id) + ]) + ]) + ) + ) + ]); + +export default renderEnd; diff --git a/ui/storm/src/view/main.ts b/ui/storm/src/view/main.ts new file mode 100644 index 0000000000..e000a1794a --- /dev/null +++ b/ui/storm/src/view/main.ts @@ -0,0 +1,90 @@ +import chessground from './chessground'; +import config from '../config'; +import renderClock from './clock'; +import renderEnd from "./end"; +import StormCtrl from '../ctrl'; +import { getNow } from '../util'; +import { h } from 'snabbdom' +import { VNode } from 'snabbdom/vnode'; + +export default function(ctrl: StormCtrl): VNode { + if (ctrl.vm.dupTab) return renderDupTab(); + if (!ctrl.vm.run.endAt) return h('div.storm.storm-app.storm--play', { + class: playModifiers(ctrl) + }, renderPlay(ctrl)); + return h('main.storm.storm--end', renderEnd(ctrl)); +} + +const playModifiers = (ctrl: StormCtrl) => { + const now = getNow(); + const malus = ctrl.vm.modifier.malus; + const bonus = ctrl.vm.modifier.bonus; + return { + 'storm--mod-puzzle': !!ctrl.vm.puzzleStartAt && ctrl.vm.puzzleStartAt > now - 90, + 'storm--mod-move': ctrl.vm.modifier.moveAt > now - 90, + 'storm--mod-malus-quick': !!malus && malus.at > now - 90, + 'storm--mod-malus-slow': !!malus && malus.at > now - 950, + 'storm--mod-bonus-slow': !!bonus && bonus.at > now - 950 + }; +} + +const renderPlay = (ctrl: StormCtrl): VNode[] => [ + h('div.storm__board.main-board', [ + chessground(ctrl), + ctrl.promotion.view() + ]), + h('div.storm__side', [ + ctrl.vm.run.startAt ? renderSolved(ctrl) : renderStart(ctrl), + renderClock(ctrl), + renderCombo(ctrl) + ]) +]; + +const renderCombo = (ctrl: StormCtrl): VNode => { + const level = ctrl.comboLevel(); + return h('div.storm__combo', [ + h('div.storm__combo__counter', [ + h('span.storm__combo__counter__value', ctrl.vm.combo), + h('span.storm__combo__counter__combo', 'COMBO') + ]), + h('div.storm__combo__bars', [ + h('div.storm__combo__bar', [ + h('div.storm__combo__bar__in', { + attrs: { style: `width:${ctrl.comboPercent()}%` } + }), + h('div.storm__combo__bar__in-full') + ]), + h('div.storm__combo__levels', + [0, 1, 2, 3].map(l => + h('div.storm__combo__level', { + class: { + active: l < level + } + }, h('span', `${config.combo.levels[l + 1][1]}s`)) + ) + ) + ]) + ]); +} + +const renderSolved = (ctrl: StormCtrl): VNode => + h('div.storm__top.storm__solved', [ + h('div.storm__solved__text', ctrl.countWins()) + ]); + +const renderStart = (ctrl: StormCtrl) => + h('div.storm__top.storm__start', + h('div.storm__start__text', [ + h('strong', 'Puzzle Storm'), + h('span', ctrl.trans('moveToStart')) + ]) + ); + +const renderDupTab = () => + h('div.storm.storm--dup.box.box-pad', [ + h('i', { attrs: { 'data-icon': '~' } }), + h('p', 'This run was opened in another tab!'), + h('a.storm--dup__reload.button', { + attrs: { href: '/storm' } + }, 'Click to reload') + ]); diff --git a/ui/storm/src/xhr.ts b/ui/storm/src/xhr.ts new file mode 100644 index 0000000000..39ed9c6f7b --- /dev/null +++ b/ui/storm/src/xhr.ts @@ -0,0 +1,13 @@ +import * as xhr from 'common/xhr'; +import { RunResponse, StormRun } from './interfaces'; + +export function record(run: StormRun, notAnExploit: string): Promise { + return xhr.json('/storm', { + method: 'POST', + body: xhr.form({ + ...run, + time: Math.round(run.time), + notAnExploit + }) + }); +} diff --git a/ui/storm/tsconfig.json b/ui/storm/tsconfig.json new file mode 100644 index 0000000000..4eb37fee05 --- /dev/null +++ b/ui/storm/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.base.json" +}