diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56526631..72bc3e27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: matrix: os: [ubuntu-latest] scala: [3.0.1] - java: [adopt@1.8, adopt@1.11, adopt@1.16] + java: [adopt@1.11, adopt@1.16] runs-on: ${{ matrix.os }} steps: - name: Checkout current branch (full) @@ -33,7 +33,7 @@ jobs: fetch-depth: 0 - name: Setup Java and Scala - uses: olafurpg/setup-scala@v10 + uses: olafurpg/setup-scala@v13 with: java-version: ${{ matrix.java }} @@ -53,15 +53,17 @@ jobs: run: sbt ++${{ matrix.scala }} githubWorkflowCheck - name: Lint check with scalafmt - run: sbt ++${{ matrix.scala }} scalafmtCheck + run: sbt ++${{ matrix.scala }} scalafmtCheckAll - name: Tests - run: sbt ++${{ matrix.scala }} 'core / test' + run: sbt ++${{ matrix.scala }} test - name: Generate JaCoCo report + if: ${{ matrix.java }} == 'adopt@1.11' && ${{ matrix.scala }} == '3.0.1' && github.event_name != 'pull_request' run: sbt ++${{ matrix.scala }} 'core / jacoco' - name: Publish coverage to codecov + if: ${{ matrix.java }} == 'adopt@1.11' && ${{ matrix.scala }} == '3.0.1' && github.event_name != 'pull_request' uses: codecov/codecov-action@v2 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -92,7 +94,7 @@ jobs: matrix: os: [ubuntu-latest] scala: [3.0.1] - java: [adopt@1.8] + java: [adopt@1.11] runs-on: ${{ matrix.os }} steps: - name: Checkout current branch (full) @@ -101,7 +103,7 @@ jobs: fetch-depth: 0 - name: Setup Java and Scala - uses: olafurpg/setup-scala@v10 + uses: olafurpg/setup-scala@v13 with: java-version: ${{ matrix.java }} @@ -134,6 +136,9 @@ jobs: args: '-output-format=pdf -file-line-error -synctex=1 -halt-on-error -interaction=nonstopmode -shell-escape' working_directory: doc + - name: Create FatJar for the demo + run: sbt ++${{ matrix.scala }} 'demo / assembly' + - name: Release to Sonatype env: PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} @@ -153,4 +158,4 @@ jobs: core/target/scala-3.0.1/*.jar core/target/scala-3.0.1/*.pom demo/target/scala-3.0.1/ECScalaDemo.jar - doc/ecscala-report.pdf \ No newline at end of file + doc/ecscala-report.pdf diff --git a/.github/workflows/clean.yml b/.github/workflows/clean.yml index b535fcc1..547aaa43 100644 --- a/.github/workflows/clean.yml +++ b/.github/workflows/clean.yml @@ -56,4 +56,4 @@ jobs: printf "Deleting '%s' #%d, %'d bytes\n" $name ${ARTCOUNT[$name]} $size ghapi -X DELETE $REPO/actions/artifacts/$id done - done \ No newline at end of file + done diff --git a/README.md b/README.md index 7447910d..b722075b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # ECScala -General-purpose ECS Scala framework +An ECS Scala framework [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Maven Central](https://img.shields.io/maven-central/v/dev.atedeg/ecscala_3)](https://search.maven.org/artifact/dev.atedeg/ecscala_3) [![GitHub release](https://img.shields.io/github/release/nicolasfara/ecscala.svg)](https://gitHub.com/nicolasfara/ecscala/releases/) ![example workflow](https://github.com/nicolasfara/ecscala/workflows/CI/badge.svg) [![codecov](https://codecov.io/gh/nicolasfara/ecscala/branch/develop/graph/badge.svg?token=0XZ4XF71AY)](https://codecov.io/gh/nicolasfara/ecscala) @@ -10,7 +11,7 @@ General-purpose ECS Scala framework ## Getting Started ```scala -libraryDependencies += "dev.atedeg" %% "ecscala" % "0.1.0" +libraryDependencies += "dev.atedeg" %% "ecscala" % "0.2.1" ``` ## Usage @@ -29,7 +30,7 @@ object AnObject extends ECScalaDSL { Position(1, 2) &: Velocity(3, 4) &: Gravity(9.8) } - entity1 + Position(3, 6) + entity1 += Position(3, 6) } ``` diff --git a/benchmarks/src/main/scala/ecscala/ComponentsContainerBenchmark.scala b/benchmarks/src/main/scala/ecscala/ComponentsContainerBenchmark.scala new file mode 100644 index 00000000..e26aedca --- /dev/null +++ b/benchmarks/src/main/scala/ecscala/ComponentsContainerBenchmark.scala @@ -0,0 +1,20 @@ +package ecscala + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil } +import ecscala.utils.{ JmhSettings, Position, Velocity } +import org.openjdk.jmh.annotations.Benchmark + +class ComponentsContainerBenchmark extends JmhSettings { + + @Benchmark + def componentsContainerBenchmark: Unit = { + val view = world.getView[Position &: Velocity &: CNil] + view foreach { (entity, comps) => + val pos = entity.getComponent[Position].get + val vel = entity.getComponent[Velocity].get + entity.setComponent(Position(pos.x + 1, pos.y + 1)) + entity.setComponent(Velocity(vel.x + 1, vel.y + 1)) + } + } +} diff --git a/benchmarks/src/main/scala/ecscala/MapBenchmark.scala b/benchmarks/src/main/scala/ecscala/MapBenchmark.scala deleted file mode 100644 index 2bc1d44a..00000000 --- a/benchmarks/src/main/scala/ecscala/MapBenchmark.scala +++ /dev/null @@ -1,38 +0,0 @@ -package ecscala - -import dev.atedeg.ecscala.util.mutable.IterableMap -import org.openjdk.jmh.annotations.* - -import java.util.concurrent.TimeUnit -import scala.collection.mutable - -@BenchmarkMode(Array(Mode.AverageTime)) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 50, time = 200, timeUnit = TimeUnit.MILLISECONDS) -@Measurement(iterations = 50, time = 200, timeUnit = TimeUnit.MILLISECONDS) -@Fork(2) -class MapBenchmark { - case class Key(key: Int) - case class Value(value: Int) - - private val keys = 0 until 1_000_000 map { Key.apply } - private val values = 0 until 1_000_000 map { Value.apply } - - private val baseMutableMap = scala.collection.mutable.HashMap.from(keys zip values) - private val mutableIterableMap = IterableMap.from(keys zip values) - - @Benchmark - def mutableBaseline(): Unit = { - testMap(baseMutableMap) - } - - @Benchmark - def mutableIterable(): Unit = { - testMap(mutableIterableMap) - } - - private def testMap(map: mutable.Map[Key, Value]): Unit = { - for (key <- map.keys) map += (key -> Value(map(key).value + 1)) - } -} diff --git a/benchmarks/src/main/scala/ecscala/SystemBenchmark.scala b/benchmarks/src/main/scala/ecscala/SystemBenchmark.scala index a28871ad..00d7fb03 100644 --- a/benchmarks/src/main/scala/ecscala/SystemBenchmark.scala +++ b/benchmarks/src/main/scala/ecscala/SystemBenchmark.scala @@ -1,7 +1,7 @@ package ecscala -import dev.atedeg.ecscala.util.types.given -import dev.atedeg.ecscala.{ &:, CNil, System, World } +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, IteratingSystem, World } import ecscala.utils.{ JmhSettings, Position, Velocity } import org.openjdk.jmh.annotations.{ Benchmark, Setup } @@ -11,10 +11,10 @@ class SystemBenchmark extends JmhSettings { @Setup def init: Unit = { - world.addSystem[Position &: Velocity &: CNil]((_, comps, _) => { + world.addSystem(IteratingSystem[Position &: Velocity &: CNil]((_, comps, _) => { val Position(x, y) &: Velocity(v1, v2) &: CNil = comps Position(x + 1, y) &: Velocity(v1, v2) - }) + })) } @Benchmark diff --git a/benchmarks/src/main/scala/ecscala/ViewBenchmark.scala b/benchmarks/src/main/scala/ecscala/ViewBenchmark.scala index 5aa3b872..e41c7646 100644 --- a/benchmarks/src/main/scala/ecscala/ViewBenchmark.scala +++ b/benchmarks/src/main/scala/ecscala/ViewBenchmark.scala @@ -1,6 +1,6 @@ package ecscala -import dev.atedeg.ecscala.util.types.given +import dev.atedeg.ecscala.given import dev.atedeg.ecscala.{ &:, CNil, Component, World } import ecscala.utils.{ JmhSettings, Position, Velocity } import org.openjdk.jmh.annotations.Benchmark @@ -12,6 +12,6 @@ class ViewBenchmark extends JmhSettings { @Benchmark def viewIterationBenchmark: Unit = { val view = world.getView[Position &: Velocity &: CNil] - view foreach (_.head.addComponent(Position(2, 3))) + view foreach (_.head setComponent Position(2, 3)) } } diff --git a/benchmarks/src/main/scala/ecscala/utils/JmhSettings.scala b/benchmarks/src/main/scala/ecscala/utils/JmhSettings.scala index 916ea8a5..536cfddf 100644 --- a/benchmarks/src/main/scala/ecscala/utils/JmhSettings.scala +++ b/benchmarks/src/main/scala/ecscala/utils/JmhSettings.scala @@ -1,6 +1,6 @@ package ecscala.utils -import dev.atedeg.ecscala.util.types.given +import dev.atedeg.ecscala.given import dev.atedeg.ecscala.{ &:, CNil, System, World } import org.openjdk.jmh.annotations.{ Benchmark, @@ -22,22 +22,22 @@ import org.openjdk.jmh.annotations.{ import java.util.concurrent.TimeUnit @State(Scope.Thread) -@BenchmarkMode(Array(Mode.AverageTime)) +@BenchmarkMode(Array(Mode.SampleTime)) @Threads(1) @Fork(1) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 50, time = 100, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 100, time = 100, timeUnit = TimeUnit.MILLISECONDS) class JmhSettings { - @Param(Array("1024", "2048", "4096")) + @Param(Array("1024", "2048", "4096", "10000")) var nEntities: Int = _ val world: World = World() @Setup def setup: Unit = { val entities = (0 until nEntities) map (_ => world.createEntity()) - entities foreach (_.addComponent(Position(1, 2))) - entities foreach (_.addComponent(Velocity(3, 4))) + entities foreach (_ setComponent Position(1, 2)) + entities foreach (_ setComponent Velocity(3, 4)) } } diff --git a/build.sbt b/build.sbt index d3e3e0fd..81676d3f 100644 --- a/build.sbt +++ b/build.sbt @@ -1,10 +1,9 @@ -import sbtghactions.GenerativePlugin.autoImport.WorkflowStep -import xerial.sbt.Sonatype.autoImport.sonatypeRepository - val scala3Version = "3.0.1" Global / onChangedBuildSource := ReloadOnSourceChanges +ThisBuild / resolvers += Resolver.jcenterRepo + ThisBuild / homepage := Some(url("https://github.com/nicolasfara/ecscala")) ThisBuild / organization := "dev.atedeg" ThisBuild / licenses := List("MIT" -> url("https://opensource.org/licenses/MIT")) @@ -38,23 +37,33 @@ ThisBuild / developers := List( ), ) -ThisBuild / githubWorkflowScalaVersions := Seq("3.0.1") -ThisBuild / githubWorkflowJavaVersions := Seq("adopt@1.8", "adopt@1.11", "adopt@1.16") +ThisBuild / githubWorkflowScalaVersions := Seq(scala3Version) +ThisBuild / githubWorkflowJavaVersions := Seq("adopt@1.11", "adopt@1.16") ThisBuild / githubWorkflowTargetBranches := Seq("master", "develop") ThisBuild / githubWorkflowTargetTags ++= Seq("v*") ThisBuild / githubWorkflowPublishTargetBranches := Seq(RefPredicate.StartsWith(Ref.Tag("v"))) ThisBuild / githubWorkflowBuild := Seq( - WorkflowStep.Sbt(List("scalafmtCheck"), name = Some("Lint check with scalafmt")), - WorkflowStep.Sbt(List("core / test"), name = Some("Tests")), + WorkflowStep.Sbt( + List("scalafmtCheckAll"), + name = Some("Lint check with scalafmt"), + ), + WorkflowStep.Sbt( + List("test"), + name = Some("Tests"), + ), WorkflowStep.Sbt( List("core / jacoco"), + cond = Some( + "${{ matrix.java }} == 'adopt@1.11' && ${{ matrix.scala }} == '3.0.1' && github.event_name != 'pull_request'", + ), name = Some("Generate JaCoCo report"), ), WorkflowStep.Use( - "codecov", - "codecov-action", - "v2", + UseRef.Public("codecov", "codecov-action", "v2"), + cond = Some( + "${{ matrix.java }} == 'adopt@1.11' && ${{ matrix.scala }} == '3.0.1' && github.event_name != 'pull_request'", + ), name = Some("Publish coverage to codecov"), params = Map( "token" -> "${{ secrets.CODECOV_TOKEN }}", @@ -63,9 +72,7 @@ ThisBuild / githubWorkflowBuild := Seq( ), ), WorkflowStep.Use( - "xu-cheng", - "latex-action", - "v2", + UseRef.Public("xu-cheng", "latex-action", "v2"), name = Some("Build LaTeX report"), params = Map( "root_file" -> "ecscala-report.tex", @@ -77,9 +84,7 @@ ThisBuild / githubWorkflowBuild := Seq( ThisBuild / githubWorkflowPublish := Seq( WorkflowStep.Use( - "xu-cheng", - "latex-action", - "v2", + UseRef.Public("xu-cheng", "latex-action", "v2"), name = Some("Build LaTeX report"), params = Map( "root_file" -> "ecscala-report.tex", @@ -87,6 +92,10 @@ ThisBuild / githubWorkflowPublish := Seq( "working_directory" -> "doc", ), ), + WorkflowStep.Sbt( + List("demo / assembly"), + name = Some("Create FatJar for the demo"), + ), WorkflowStep.Sbt( List("ci-release"), name = Some("Release to Sonatype"), @@ -99,9 +108,7 @@ ThisBuild / githubWorkflowPublish := Seq( ), ), WorkflowStep.Use( - "marvinpinto", - "action-automatic-releases", - "latest", + UseRef.Public("marvinpinto", "action-automatic-releases", "latest"), name = Some("Release to Github Releases"), params = Map( "repo_token" -> "${{ secrets.GITHUB_TOKEN }}", @@ -112,14 +119,21 @@ ThisBuild / githubWorkflowPublish := Seq( ), ) -val scalaTest = Seq( +addCommandAlias("run", "demo / run") + +lazy val scalaTestLibrary = Seq( "org.scalactic" %% "scalactic" % "3.2.9", "org.scalatest" %% "scalatest" % "3.2.9" % "test", ) +lazy val javaFxLibrary = for { + module <- Seq("base", "controls", "fxml", "graphics", "media", "swing", "web") + os <- Seq("win", "mac", "linux") +} yield "org.openjfx" % s"javafx-$module" % "16" classifier os + lazy val root = project .in(file(".")) - .aggregate(core, benchmarks) + .aggregate(core, benchmarks, demo) .settings( sonatypeCredentialHost := "s01.oss.sonatype.org", sonatypeRepository := "https://s01.oss.sonatype.org/service/local", @@ -131,7 +145,7 @@ lazy val core = project .in(file("core")) .settings( name := "ecscala", - libraryDependencies := scalaTest, + libraryDependencies := scalaTestLibrary, scalacOptions ++= Seq( "-Yexplicit-nulls", ), @@ -142,7 +156,7 @@ lazy val core = project formats = Seq(JacocoReportFormats.HTML, JacocoReportFormats.XML), fileEncoding = "utf-8", ), - Test / jacocoExcludes := Seq("**.macros.*", "**.types.*"), + Test / jacocoExcludes := Seq("*Tag*"), ) lazy val benchmarks = project @@ -155,34 +169,26 @@ lazy val benchmarks = project githubWorkflowArtifactUpload := false, ) -// Determine OS version of JavaFX binaries -lazy val osName = System.getProperty("os.name") match { - case n if n.startsWith("Linux") => "linux" - case n if n.startsWith("Mac") => "mac" - case n if n.startsWith("Windows") => "win" - case _ => throw new Exception("Unknown platform!") -} - -// Add dependency on JavaFX libraries, OS dependent -lazy val javaFXModules = Seq("base", "controls", "fxml", "graphics", "web", "media", "swing") - -ThisBuild / assemblyMergeStrategy := { - case PathList("module-info.class") => MergeStrategy.discard - case x if x.endsWith("/module-info.class") => MergeStrategy.discard - case x => - val oldStrategy = (ThisBuild / assemblyMergeStrategy).value - oldStrategy(x) -} - lazy val demo = project .in(file("demo")) .dependsOn(core) .settings( publish / skip := true, - test / skip := true, + Test / fork := true, assembly / assemblyJarName := "ECScalaDemo.jar", githubWorkflowArtifactUpload := false, - libraryDependencies ++= scalaTest, - libraryDependencies += "org.scalafx" %% "scalafx" % "16.0.0-R24", - libraryDependencies ++= javaFXModules.map(m => "org.openjfx" % s"javafx-$m" % "16" classifier osName), + libraryDependencies ++= scalaTestLibrary ++ javaFxLibrary ++ Seq( + "org.scalatestplus" %% "mockito-3-12" % "3.2.10.0" % "test", + "org.scalafx" %% "scalafx" % "16.0.0-R24", + "org.testfx" % "testfx-core" % "4.0.16-alpha" % "test", + "org.testfx" % "testfx-junit5" % "4.0.16-alpha" % "test", + "org.testfx" % "openjfx-monocle" % "jdk-12.0.1+2" % "test", + "org.junit.jupiter" % "junit-jupiter" % "5.8.1" % "test", + "net.aichler" % "jupiter-interface" % JupiterKeys.jupiterVersion.value % "test", + ), ) + +ThisBuild / assemblyMergeStrategy := { + case PathList("META-INF", _ @_*) => MergeStrategy.discard + case _ => MergeStrategy.first +} diff --git a/core/src/main/scala/dev/atedeg/ecscala/CList.scala b/core/src/main/scala/dev/atedeg/ecscala/CList.scala index 75a18a16..d3f87812 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/CList.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/CList.scala @@ -1,9 +1,6 @@ package dev.atedeg.ecscala -import scala.annotation.{ showAsInfix, tailrec } -import scala.collection.IterableOps -import dev.atedeg.ecscala.{ Component, Deleted } -import dev.atedeg.ecscala.util.types.ComponentTag +import scala.annotation.showAsInfix /** * Represents a CList whose elements can either be a standard [[Component]] or a special [[Deleted]] component, diff --git a/core/src/main/scala/dev/atedeg/ecscala/util/types/CListTag.scala b/core/src/main/scala/dev/atedeg/ecscala/CListTag.scala similarity index 71% rename from core/src/main/scala/dev/atedeg/ecscala/util/types/CListTag.scala rename to core/src/main/scala/dev/atedeg/ecscala/CListTag.scala index 72149b87..b29d1138 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/util/types/CListTag.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/CListTag.scala @@ -1,16 +1,22 @@ -package dev.atedeg.ecscala.util.types - -import dev.atedeg.ecscala.{ &:, CList, CNil, Component } -import dev.atedeg.ecscala.util.types +package dev.atedeg.ecscala +import scala.annotation.targetName import scala.quoted.{ Expr, Quotes, Type } sealed trait CListTag[L <: CList] { - def tags: Seq[ComponentTag[? <: Component]] + def tags: Seq[ComponentTag[Component]] } inline given [L <: CList]: CListTag[L] = ${ deriveCListTagImpl[L] } +extension [L <: CList: CListTag](list: L) + def taggedWith(clt: CListTag[L]): Iterable[(Component, ComponentTag[Component])] = list zip clt.tags + +extension [L <: CList: CListTag](list: Deletable[L]) + + @targetName("deletableTaggedWith") + def taggedWith(clt: CListTag[L]): Iterable[(Component, ComponentTag[Component])] = list zip clt.tags + private def deriveCListTagImpl[L <: CList: Type](using quotes: Quotes): Expr[CListTag[L]] = { import quotes.reflect.* val typeReprOfL = TypeRepr.of[L] @@ -33,10 +39,10 @@ private def deriveCListTagImpl[L <: CList: Type](using quotes: Quotes): Expr[CLi } } -inline private def getTags[L <: CList]: Seq[ComponentTag[? <: Component]] = { +inline private def getTags[L <: CList]: Seq[ComponentTag[Component]] = { import scala.compiletime.erasedValue inline erasedValue[L] match { - case _: (head &: tail) => summon[ComponentTag[head]] +: getTags[tail] + case _: (head &: tail) => summon[ComponentTag[head]].asInstanceOf[ComponentTag[Component]] +: getTags[tail] case _ => Seq() } } diff --git a/core/src/main/scala/dev/atedeg/ecscala/Component.scala b/core/src/main/scala/dev/atedeg/ecscala/Component.scala index 48287df2..0b918591 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/Component.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/Component.scala @@ -1,7 +1,5 @@ package dev.atedeg.ecscala -import dev.atedeg.ecscala.util.types.ComponentTag - /** * This trait represents an [[Entity]] 's feature. */ @@ -9,7 +7,7 @@ trait Component { private var _entity: Option[Entity] = Option.empty def entity: Option[Entity] = _entity - private[ecscala] def setEntity(entity: Option[Entity]): Unit = { + private[ecscala] def entity_=(entity: Option[Entity]): Unit = { _entity = entity } } diff --git a/core/src/main/scala/dev/atedeg/ecscala/util/types/ComponentTag.scala b/core/src/main/scala/dev/atedeg/ecscala/ComponentTag.scala similarity index 73% rename from core/src/main/scala/dev/atedeg/ecscala/util/types/ComponentTag.scala rename to core/src/main/scala/dev/atedeg/ecscala/ComponentTag.scala index d3ed059e..9904f0e2 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/util/types/ComponentTag.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/ComponentTag.scala @@ -1,6 +1,4 @@ -package dev.atedeg.ecscala.util.types - -import dev.atedeg.ecscala.{ CList, Component } +package dev.atedeg.ecscala import scala.quoted.{ Expr, Quotes, Type } @@ -24,12 +22,15 @@ private def deriveComponentTagImpl[C: Type](using quotes: Quotes): Expr[Componen else if !(typeReprOfC <:< TypeRepr.of[Component]) then report.error(s"${typeReprOfC.show} must be a subtype of Component") + val computedString = typeReprOfC.show + val computedHashCode = computedString.hashCode '{ new ComponentTag[C] { - override def toString: String = ${ Expr(typeReprOfC.show) } - override def hashCode: Int = this.toString.hashCode + override def toString: String = ${ Expr(computedString) } + override def hashCode: Int = ${ Expr(computedHashCode) } override def equals(obj: Any) = obj match { - case that: ComponentTag[_] => that.toString == this.toString + case that: ComponentTag[_] => + (this eq that) || (this.hashCode == that.hashCode && this.toString == that.toString) case _ => false } } diff --git a/core/src/main/scala/dev/atedeg/ecscala/Entity.scala b/core/src/main/scala/dev/atedeg/ecscala/Entity.scala index 9f6843a7..8b6f3731 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/Entity.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/Entity.scala @@ -1,7 +1,6 @@ package dev.atedeg.ecscala -import dev.atedeg.ecscala.util.immutable.ComponentsContainer -import dev.atedeg.ecscala.util.types.ComponentTag +import dev.atedeg.ecscala.util.mutable.ComponentsContainer /** * This trait represents an entity of ECS whose state is defined by its components. @@ -16,7 +15,7 @@ sealed trait Entity { * @return * itself. */ - def addComponent[C <: Component: ComponentTag](component: C): Entity + def setComponent[C <: Component: ComponentTag](component: C): Entity /** * @tparam C @@ -55,9 +54,13 @@ object Entity { private case class EntityImpl(private val id: Id, private val world: World) extends Entity { - override def addComponent[C <: Component](component: C)(using ct: ComponentTag[C]): Entity = { - component.setEntity(Some(this)) - world += (this -> component) + override def setComponent[C <: Component](component: C)(using ct: ComponentTag[C]): Entity = { + require( + component.entity.isEmpty || component.entity.get == this, + "The given component already belongs to a different entity", + ) + component.entity = Some(this) + world addComponent (this -> component) this } @@ -66,26 +69,21 @@ object Entity { override def removeComponent[C <: Component](using ct: ComponentTag[C]): Entity = { val componentToRemove = world.getComponents(using ct) flatMap (_.get(this)) - componentToRemove match { - case Some(component) => - component.setEntity(None) - world -= (this -> component) - case None => () - } + componentToRemove.foreach(removeComponent(_)) this } override def removeComponent[C <: Component](component: C)(using ct: ComponentTag[C]): Entity = { component.entity match { - case Some(entity) if entity == this => - component.setEntity(None) - world -= (this -> component) + case Some(entity) if entity == this => world removeComponent (this -> component) case _ => () } this } override def toString: String = s"Entity($id)" + + override def hashCode(): Id = id } private object IdGenerator { diff --git a/core/src/main/scala/dev/atedeg/ecscala/System.scala b/core/src/main/scala/dev/atedeg/ecscala/System.scala index 2f7f01bd..ca961874 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/System.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/System.scala @@ -1,62 +1,93 @@ package dev.atedeg.ecscala import scala.annotation.tailrec -import dev.atedeg.ecscala.{ CList, Entity, View } -import dev.atedeg.ecscala.util.types.given -import dev.atedeg.ecscala.util.types.{ CListTag, ComponentTag } +import dev.atedeg.ecscala.given -type DeltaTime = Float +type DeltaTime = Double /** - * Represent a way to iterate over entities with specific components (given by the type parameter L) and manupulate - * them. - * @tparam L - * a [[CList]] representing the Components available to the [[System]]. + * This trait represents a system, which can update the [[World]] 's state. */ -trait System[L <: CList](using private val clt: CListTag[L]) { +trait System { - private[ecscala] final def apply(world: World, deltaTime: DeltaTime): Unit = { + private[ecscala] final def apply(deltaTime: DeltaTime, world: World): Unit = { if (shouldRun) { - val view = getView(world) - before(deltaTime, world, view) - view foreach { (entity, components) => - val updatedComponents = this.update(entity, components)(deltaTime, world, view) - updateComponents(updatedComponents)(entity)(using clt) - } - after(deltaTime, world, view) + update(deltaTime, world) } } /** * @return - * wether this [[System]] should be executed or not. + * whether this [[System]] should be executed or not. */ def shouldRun: Boolean = true /** - * This method is executed before each iteration of the [[System]]. + * This method is executed every time the [[World]] is updated. * @param deltaTime * the delta time used to update. * @param world * the [[World]] in which the [[System]] is being executed. + */ + def update(deltaTime: DeltaTime, world: World): Unit +} + +object System { + + /** + * Create a [[System]] from a lambda that specifies its behaviour. + * @param f + * the behaviour of the [[System]] that takes [[DeltaTime]] and the [[World]] and returns Unit. + * @return + * the created [[System]]. + */ + def apply(f: (DeltaTime, World) => Unit): System = new System { + override def update(deltaTime: DeltaTime, world: World): Unit = f(deltaTime, world) + } + + /** + * Create a [[SystemBuilder]]. + * @tparam L + * a [[CList]] representing the Components to be iterated. + * @return + * the [[SystemBuilder]]. + */ + def apply[L <: CList: CListTag]: SystemBuilder[L] = SystemBuilder[L] +} + +/** + * Represent a way to iterate over entities with specific components (given by the type parameter L) and manupulate + * them. + * @tparam L + * a [[CList]] representing the Components available to the [[IteratingSystem]]. + */ +trait IteratingSystem[L <: CList](using private val clt: CListTag[L]) extends System { + + /** + * This method is executed before each iteration of the [[IteratingSystem]]. + * @param deltaTime + * the delta time used to update. + * @param world + * the [[World]] in which the [[IteratingSystem]] is being executed. * @param view - * a [[View]] with the Components specified by the [[System]] type. + * a [[View]] with the Components specified by the [[IteratingSystem]] type. */ def before(deltaTime: DeltaTime, world: World, view: View[L]): Unit = {} /** - * This method is executed after each iteration of the [[System]]. + * This method is executed after each iteration of the [[IteratingSystem]]. * @param deltaTime * the delta time used to update. * @param world - * the [[World]] in which the [[System]] is being executed. + * the [[World]] in which the [[IteratingSystem]] is being executed. * @param view - * a [[View]] with the Components specified by the [[System]] type. + * a [[View]] with the Components specified by the [[IteratingSystem]] type. */ def after(deltaTime: DeltaTime, world: World, view: View[L]): Unit = {} /** - * Describes how this [[System]] updates the components (described by the type of the System) of an [[Entity]]. + * Describes how this [[IteratingSystem]] updates the components (described by the type of the System) of an + * [[Entity]]. * @param entity * the [[Entity]] whose components are being updated. * @param components @@ -64,7 +95,7 @@ trait System[L <: CList](using private val clt: CListTag[L]) { * @param deltaTime * the delta time used to update. * @param world - * the [[World]] in which this [[System]] is being used. + * the [[World]] in which this [[IteratingSystem]] is being used. * @param view * the [[View]] of all entities with the components described by L. * @return @@ -75,20 +106,38 @@ trait System[L <: CList](using private val clt: CListTag[L]) { */ def update(entity: Entity, components: L)(deltaTime: DeltaTime, world: World, view: View[L]): Deletable[L] + override final def update(deltaTime: DeltaTime, world: World): Unit = { + val view = getView(world) + before(deltaTime, world, view) + view foreach { (entity, components) => + val updatedComponents = update(entity, components)(deltaTime, world, view) + updateComponents(updatedComponents)(entity)(using clt) + } + after(deltaTime, world, view) + } + protected def getView(world: World): View[L] = world.getView(using clt) private def updateComponents[L <: CList](components: Deletable[L])(entity: Entity)(using clt: CListTag[L]): Unit = { - val taggedComponents = clt.tags.asInstanceOf[Seq[ComponentTag[Component]]] zip components - taggedComponents foreach { taggedComponent => - val (ct, component) = taggedComponent + components.taggedWith(clt) foreach { taggedComponent => + val (component, ct) = taggedComponent component match { case Deleted => entity.removeComponent(using ct) - case _ => entity.addComponent(component)(using ct) + case _ => entity.setComponent(component)(using ct) } } } } +object IteratingSystem { + + def apply[L <: CList: CListTag](f: (Entity, L, DeltaTime) => Deletable[L]): IteratingSystem[L] = + SystemBuilder[L].withUpdate(f) + + def apply[L <: CList: CListTag](f: (Entity, L, DeltaTime, World, View[L]) => Deletable[L]): IteratingSystem[L] = + SystemBuilder[L].withUpdate(f) +} + /** * Represent a way to iterate over entities with specific components (given by the type parameter LIncluded) and without * specific components (given by the type parameter LExcluded) and manipulate them. @@ -100,23 +149,19 @@ trait System[L <: CList](using private val clt: CListTag[L]) { trait ExcludingSystem[LIncluded <: CList, LExcluded <: CList](using private val cltIncl: CListTag[LIncluded], private val cltExcl: CListTag[LExcluded], -) extends System[LIncluded] { +) extends IteratingSystem[LIncluded] { override protected def getView(world: World): View[LIncluded] = world.getView(using cltIncl, cltExcl) } -trait EmptySystem extends System[CNil] { - def update(): Unit - - override final def update(entity: Entity, components: CNil)(deltaTime: DeltaTime, world: World, view: View[CNil]) = - throw new IllegalStateException("An EmptySystem's update method should never be called.") +object ExcludingSystem { - override final def before(deltaTime: DeltaTime, world: World, view: View[CNil]): Unit = update() - override final def after(deltaTime: DeltaTime, world: World, view: View[CNil]): Unit = () -} + def apply[L <: CList: CListTag, E <: CList: CListTag]( + f: (Entity, L, DeltaTime) => Deletable[L], + ): ExcludingSystem[L, E] = + SystemBuilder[L].excluding[E].withUpdate(f) -object EmptySystem { - - def apply(f: () => Unit): EmptySystem = new EmptySystem { - override def update(): Unit = f() - } + def apply[L <: CList: CListTag, E <: CList: CListTag]( + f: (Entity, L, DeltaTime, World, View[L]) => Deletable[L], + ): ExcludingSystem[L, E] = SystemBuilder[L].excluding[E].withUpdate(f) + def apply[L <: CList: CListTag, E <: CList: CListTag]: ExcludingSystemBuilder[L, E] = ExcludingSystemBuilder[L, E] } diff --git a/core/src/main/scala/dev/atedeg/ecscala/SystemBuilder.scala b/core/src/main/scala/dev/atedeg/ecscala/SystemBuilder.scala new file mode 100644 index 00000000..e03bc2fe --- /dev/null +++ b/core/src/main/scala/dev/atedeg/ecscala/SystemBuilder.scala @@ -0,0 +1,202 @@ +package dev.atedeg.ecscala + +import dev.atedeg.ecscala.given + +/** + * The generic operations that a SystemBuilder provides. + * @tparam L + * the type of the [[CList]] used by the built [[IteratingSystem]]. + */ +trait SystemBuilderOps[L <: CList: CListTag] { + + /** + * The type of the SystemBuilder produced by the different chained operations. + */ + type BuilderType <: SystemBuilderOps[L] + + /** + * The type of the [[IteratingSystem]] produced when closing the builder. + */ + type SystemType <: IteratingSystem[L] + + /** + * @param before + * the before function used by Systems created by the returned Builder. + * @return + * the new Builder with the specified before function. + */ + def withBefore(before: (DeltaTime, World, View[L]) => Unit): BuilderType + + /** + * @param before + * the after function used by Systems created by the returned Builder. + * @return + * the new Builder with the specified after function. + */ + def withAfter(after: (DeltaTime, World, View[L]) => Unit): BuilderType + + /** + * @param before + * the precondition used by Systems created by the returned Builder. + * @return + * the new Builder with the specified precondition. + */ + def withPrecondition(precondition: => Boolean): BuilderType + + /** + * @param f + * the [[System.update]] function to be used by the created System + * @return + * a System with the given update function + */ + def withUpdate(f: (Entity, L, DeltaTime) => Deletable[L]): SystemType + + /** + * @param f + * the [[System.update]] function to be used by the created System + * @return + * a System with the given update function + */ + def withUpdate(f: (Entity, L, DeltaTime, World, View[L]) => Deletable[L]): SystemType +} + +/** + * A builder used to create [[IteratingSystem]]. + * @tparam L + * the type of the [[CList]] used by the built [[IteratingSystem]]. + */ +trait SystemBuilder[L <: CList: CListTag] extends SystemBuilderOps[L] { + override type BuilderType = SystemBuilder[L] + override type SystemType = IteratingSystem[L] + + /** + * Converts this builder to an [[ExcludingSystemBuilder]] + * @tparam E + * the type of the [[CList]] of components to be excluded. + * @return + * an [[ExcludingSystemBuilder]] from this builder. + */ + def excluding[E <: CList: CListTag]: ExcludingSystemBuilder[L, E] +} + +object SystemBuilder { + + /** + * @tparam L + * the type of the [[CList]] used by the built [[IteratingSystem]]. + * @return + * a new [[SystemBuilder]] + */ + def apply[L <: CList: CListTag]: SystemBuilder[L] = BuilderUtils.SystemBuilderImpl() +} + +/** + * A builder used to create [[ExcludingSystem]]. + * @tparam L + * the type of the [[CList]] used by the built [[IteratingSystem]]. + * @tparam E + * the type of the [[CList]] of components to be excluded. + */ +trait ExcludingSystemBuilder[L <: CList: CListTag, E <: CList: CListTag] extends SystemBuilderOps[L] { + override type BuilderType = ExcludingSystemBuilder[L, E] + override type SystemType = ExcludingSystem[L, E] +} + +object ExcludingSystemBuilder { + + /** + * @tparam L + * the type of the [[CList]] used by the built [[IteratingSystem]]. + * @tparam E + * the type of the [[CList]] of components to be excluded. + * @return + * a new [[ExcludingSystemBuilder]] + */ + def apply[L <: CList: CListTag, E <: CList: CListTag]: ExcludingSystemBuilder[L, E] = + BuilderUtils.ExcludingSystemBuilderImpl() +} + +private object BuilderUtils { + + abstract class BaseSystemBuilder[L <: CList: CListTag]( + before: (DeltaTime, World, View[L]) => Unit = (_, _, _: View[L]) => (), + after: (DeltaTime, World, View[L]) => Unit = (_, _, _: View[L]) => (), + precondition: => Boolean = true, + ) extends SystemBuilderOps[L] { + def systemConstructor(f: (Entity, L, DeltaTime) => Deletable[L]): SystemType + def systemConstructor(f: (Entity, L, DeltaTime, World, View[L]) => Deletable[L]): SystemType + + def builderConstructor( + before: (DeltaTime, World, View[L]) => Unit, + after: (DeltaTime, World, View[L]) => Unit, + precondition: => Boolean, + ): BuilderType + + override def withBefore(newBefore: (DeltaTime, World, View[L]) => Unit) = + builderConstructor(newBefore, after, precondition) + + override def withAfter(newAfter: (DeltaTime, World, View[L]) => Unit) = + builderConstructor(before, newAfter, precondition) + override def withPrecondition(newPrecondition: => Boolean) = builderConstructor(before, after, newPrecondition) + override def withUpdate(f: (Entity, L, DeltaTime) => Deletable[L]) = systemConstructor(f) + override def withUpdate(f: (Entity, L, DeltaTime, World, View[L]) => Deletable[L]) = systemConstructor(f) + } + + class SystemBuilderImpl[L <: CList: CListTag]( + beforeHandler: (DeltaTime, World, View[L]) => Unit = (_, _, _: View[L]) => (), + afterHandler: (DeltaTime, World, View[L]) => Unit = (_, _, _: View[L]) => (), + precondition: => Boolean = true, + ) extends BaseSystemBuilder[L](beforeHandler, afterHandler, precondition) + with SystemBuilder[L] { + + override def systemConstructor(f: (Entity, L, DeltaTime) => Deletable[L]) = new IteratingSystem[L] { + override def update(e: Entity, c: L)(dt: DeltaTime, w: World, v: View[L]) = f(e, c, dt) + override def before(dt: DeltaTime, w: World, v: View[L]): Unit = beforeHandler(dt, w, v) + override def after(dt: DeltaTime, w: World, v: View[L]): Unit = afterHandler(dt, w, v) + override def shouldRun = precondition + } + + override def systemConstructor(f: (Entity, L, DeltaTime, World, View[L]) => Deletable[L]) = new IteratingSystem[L] { + override def update(e: Entity, c: L)(dt: DeltaTime, w: World, v: View[L]) = f(e, c, dt, w, v) + override def before(dt: DeltaTime, w: World, v: View[L]): Unit = beforeHandler(dt, w, v) + override def after(dt: DeltaTime, w: World, v: View[L]): Unit = afterHandler(dt, w, v) + override def shouldRun = precondition + } + + override def builderConstructor( + before: (DeltaTime, World, View[L]) => Unit, + after: (DeltaTime, World, View[L]) => Unit, + precondition: => Boolean, + ) = SystemBuilderImpl(before, after, precondition) + override def excluding[E <: CList: CListTag] = ExcludingSystemBuilderImpl(beforeHandler, afterHandler, precondition) + } + + class ExcludingSystemBuilderImpl[L <: CList: CListTag, E <: CList: CListTag]( + beforeHandler: (DeltaTime, World, View[L]) => Unit = (_, _, _: View[L]) => (), + afterHandler: (DeltaTime, World, View[L]) => Unit = (_, _, _: View[L]) => (), + precondition: => Boolean = true, + ) extends BaseSystemBuilder[L](beforeHandler, afterHandler, precondition) + with ExcludingSystemBuilder[L, E] { + + override def systemConstructor(f: (Entity, L, DeltaTime) => Deletable[L]) = new ExcludingSystem[L, E] { + override def update(e: Entity, c: L)(dt: DeltaTime, w: World, v: View[L]) = f(e, c, dt) + override def before(dt: DeltaTime, w: World, v: View[L]): Unit = beforeHandler(dt, w, v) + override def after(dt: DeltaTime, w: World, v: View[L]): Unit = afterHandler(dt, w, v) + override def shouldRun = precondition + } + + override def systemConstructor(f: (Entity, L, DeltaTime, World, View[L]) => Deletable[L]) = + new ExcludingSystem[L, E] { + override def update(e: Entity, c: L)(dt: DeltaTime, w: World, v: View[L]) = f(e, c, dt, w, v) + override def before(dt: DeltaTime, w: World, v: View[L]): Unit = beforeHandler(dt, w, v) + override def after(dt: DeltaTime, w: World, v: View[L]): Unit = afterHandler(dt, w, v) + override def shouldRun = precondition + } + + override def builderConstructor( + before: (DeltaTime, World, View[L]) => Unit, + after: (DeltaTime, World, View[L]) => Unit, + precondition: => Boolean, + ) = ExcludingSystemBuilderImpl(before, after, precondition) + } +} diff --git a/core/src/main/scala/dev/atedeg/ecscala/View.scala b/core/src/main/scala/dev/atedeg/ecscala/View.scala index eac1cc10..be10b7b0 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/View.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/View.scala @@ -1,8 +1,8 @@ package dev.atedeg.ecscala import scala.annotation.targetName -import dev.atedeg.ecscala.util.types.{ CListTag, ComponentTag } -import dev.atedeg.ecscala.util.types.given +import scala.collection.Map +import dev.atedeg.ecscala.given /** * A [[View]] on a [[World]] that allows to iterate over its entities with components of the type specified in L. @@ -24,7 +24,7 @@ trait ExcludingView[LIncluded <: CList, LExcluded <: CList] extends View[LInclud private[ecscala] object View { def apply[L <: CList](world: World)(using clt: CListTag[L]): View[L] = new View[L] { - override def iterator: Iterator[(Entity, L)] = new ViewIterator(world)(using clt) + override def iterator: Iterator[(Entity, L)] = ViewIterator(world)(using clt) } def apply[LIncluded <: CList, LExcluded <: CList]( @@ -32,7 +32,7 @@ private[ecscala] object View { )(using cltIncl: CListTag[LIncluded], cltExcl: CListTag[LExcluded]): ExcludingView[LIncluded, LExcluded] = new ExcludingView[LIncluded, LExcluded] { - override def iterator: Iterator[(Entity, LIncluded)] = new ExcludingViewIterator(world)(using cltIncl, cltExcl) + override def iterator: Iterator[(Entity, LIncluded)] = ExcludingViewIterator(world)(using cltIncl, cltExcl) } private abstract class BaseViewIterator[L <: CList](world: World)(using clt: CListTag[L]) @@ -68,7 +68,7 @@ private[ecscala] object View { private val excludingMaps = taggedExcludingMaps map (_._2) override protected def isValid(entity: Entity): Boolean = - otherMaps.forall(_ contains entity) && !excludingMaps.exists(_ contains entity) + super.isValid(entity) && !excludingMaps.exists(_ contains entity) } private def getEntityComponents[L <: CList]( diff --git a/core/src/main/scala/dev/atedeg/ecscala/World.scala b/core/src/main/scala/dev/atedeg/ecscala/World.scala index 27f93962..d8b6218b 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/World.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/World.scala @@ -1,8 +1,8 @@ package dev.atedeg.ecscala import scala.annotation.targetName -import dev.atedeg.ecscala.util.immutable.ComponentsContainer -import dev.atedeg.ecscala.util.types.{ CListTag, ComponentTag } +import scala.collection.Map +import dev.atedeg.ecscala.util.mutable.ComponentsContainer /** * A container for [[Entity]], Components and System. @@ -32,7 +32,7 @@ sealed trait World { /** * Remove all the entites and their respective components from the [[World]] */ - def clear(): Unit + def clearEntities(): Unit /** * A [[View]] on this [[World]] that allows to iterate over its entities with components of the type specified in L. @@ -59,54 +59,15 @@ sealed trait World { * Add a [[System]] to the [[World]]. * @param system * the system to add. - * @tparam L - * the [[CList]] of system components. */ - def addSystem[L <: CList: CListTag](system: System[L]): Unit + def addSystem(system: System): Unit /** - * Add an anonymous [[System]] to the [[World]]. + * Remove a [[System]] from the [[World]]. * @param system - * a function that will be run for each matching entity. - * @tparam L - * the [[CList]] of system components. - */ - def addSystem[L <: CList: CListTag](system: (Entity, L, DeltaTime) => Deletable[L]): Unit - - /** - * Add an anonymous [[ExcludingSystem]] to the [[World]]. - * @param system - * a function that will be run for each matching entity. - * @tparam LIncluded - * the [[CList]] of included system components. - * @tparam LExcluded - * the [[CList]] of excluded system components. - */ - def addSystem[LIncluded <: CList: CListTag, LExcluded <: CList: CListTag]( - system: (Entity, LIncluded, DeltaTime) => Deletable[LIncluded], - ): Unit - - /** - * Add an anonymous [[System]] to the [[World]]. - * @param system - * a function that will be run for each matching entity. - * @tparam L - * the [[CList]] of system components. + * the system to remove. */ - def addSystem[L <: CList: CListTag](system: (Entity, L, DeltaTime, World, View[L]) => Deletable[L]): Unit - - /** - * Add an anonymous [[ExcludingSystem]] to the [[World]]. - * @param system - * a function that will be run for each matching entity. - * @tparam LIncluded - * the [[CList]] of included system components. - * @tparam LExcluded - * the [[CList]] of excluded system components. - */ - def addSystem[LIncluded <: CList: CListTag, LExcluded <: CList: CListTag]( - system: (Entity, LIncluded, DeltaTime, World, View[LIncluded]) => Deletable[LIncluded], - ): Unit + def removeSystem(system: System): Unit /** * Update the world. @@ -117,11 +78,9 @@ sealed trait World { private[ecscala] def getComponents[C <: Component: ComponentTag]: Option[Map[Entity, C]] - @targetName("addComponent") - private[ecscala] def +=[C <: Component: ComponentTag](entityComponentPair: (Entity, C)): World + private[ecscala] def addComponent[C <: Component: ComponentTag](entityComponentPair: (Entity, C)): World - @targetName("removeComponent") - private[ecscala] def -=[C <: Component: ComponentTag](entityComponentPair: (Entity, C)): World + private[ecscala] def removeComponent[C <: Component: ComponentTag](entityComponentPair: (Entity, C)): World } /** @@ -133,7 +92,7 @@ object World { private class WorldImpl() extends World { private var entities: Set[Entity] = Set() private var componentsContainer = ComponentsContainer() - private var systems: List[(CListTag[?], System[? <: CList])] = List() + private var systems: List[System] = List() override def entitiesCount: Int = entities.size @@ -148,7 +107,7 @@ object World { componentsContainer -= entity } - override def clear(): Unit = { + override def clearEntities(): Unit = { entities foreach { componentsContainer -= _ } entities = Set() } @@ -160,94 +119,31 @@ object World { cltExcl: CListTag[LExcluded], ): ExcludingView[LIncluded, LExcluded] = View(this)(using cltIncl, cltExcl) - override def addSystem[L <: CList](system: System[L])(using clt: CListTag[L]): Unit = - systems = systems :+ (clt -> system) + override def addSystem(system: System): Unit = + systems = systems :+ system - override def addSystem[L <: CList](system: (Entity, L, DeltaTime) => Deletable[L])(using clt: CListTag[L]): Unit = - addSystem(convertFunctionToSystem[L](system))(using clt) + override def removeSystem(system: System): Unit = + systems = systems filter (_ != system) - override def addSystem[LIncluded <: CList, LExcluded <: CList]( - system: (Entity, LIncluded, DeltaTime) => Deletable[LIncluded], - )(using cltIncl: CListTag[LIncluded], cltExcl: CListTag[LExcluded]): Unit = addSystem( - convertFunctionToSystem[LIncluded, LExcluded](system), - )(using cltIncl) - - override def addSystem[L <: CList](system: (Entity, L, DeltaTime, World, View[L]) => Deletable[L])(using - clt: CListTag[L], - ): Unit = addSystem(convertFunctionToSystem[L](system))(using clt) - - override def addSystem[LIncluded <: CList, LExcluded <: CList]( - system: (Entity, LIncluded, DeltaTime, World, View[LIncluded]) => Deletable[LIncluded], - )(using cltIncl: CListTag[LIncluded], cltExcl: CListTag[LExcluded]): Unit = addSystem( - convertFunctionToSystem[LIncluded, LExcluded](system), - )(using cltIncl) - - override def update(deltaTime: DeltaTime): Unit = systems foreach (taggedSystem => { - val (ct, system) = taggedSystem - system(this, deltaTime) - }) + override def update(deltaTime: DeltaTime): Unit = systems foreach (_(deltaTime, this)) override def toString: String = componentsContainer.toString private[ecscala] override def getComponents[C <: Component: ComponentTag]: Option[Map[Entity, C]] = componentsContainer[C] - @targetName("addComponent") - private[ecscala] override def +=[C <: Component: ComponentTag](entityComponentPair: (Entity, C)): World = { + private[ecscala] override def addComponent[C <: Component: ComponentTag]( + entityComponentPair: (Entity, C), + ): World = { componentsContainer += entityComponentPair this } - @targetName("removeComponent") - private[ecscala] override def -=[C <: Component: ComponentTag](entityComponentPair: (Entity, C)): World = { + private[ecscala] override def removeComponent[C <: Component: ComponentTag]( + entityComponentPair: (Entity, C), + ): World = { componentsContainer -= entityComponentPair this } - - private def convertFunctionToSystem[L <: CList]( - system: (Entity, L, DeltaTime) => Deletable[L], - )(using clt: CListTag[L]): System[L] = - new System[L](using clt) { - - override def update( - entity: Entity, - components: L, - )(deltaTime: DeltaTime, world: World, view: View[L]): Deletable[L] = system(entity, components, deltaTime) - } - - private def convertFunctionToSystem[L <: CList]( - system: (Entity, L, DeltaTime, World, View[L]) => Deletable[L], - )(using clt: CListTag[L]): System[L] = new System[L](using clt) { - - override def update( - entity: Entity, - components: L, - )(deltaTime: DeltaTime, world: World, view: View[L]): Deletable[L] = - system(entity, components, deltaTime, world, view) - } - - private def convertFunctionToSystem[LIncluded <: CList, LExcluded <: CList]( - system: (Entity, LIncluded, DeltaTime) => Deletable[LIncluded], - )(using cltIncl: CListTag[LIncluded], cltExcl: CListTag[LExcluded]): ExcludingSystem[LIncluded, LExcluded] = - new ExcludingSystem[LIncluded, LExcluded](using cltIncl, cltExcl) { - - override def update( - entity: Entity, - components: LIncluded, - )(deltaTime: DeltaTime, world: World, view: View[LIncluded]): Deletable[LIncluded] = - system(entity, components, deltaTime) - } - - private def convertFunctionToSystem[LIncluded <: CList, LExcluded <: CList]( - system: (Entity, LIncluded, DeltaTime, World, View[LIncluded]) => Deletable[LIncluded], - )(using cltIncl: CListTag[LIncluded], cltExcl: CListTag[LExcluded]): ExcludingSystem[LIncluded, LExcluded] = - new ExcludingSystem[LIncluded, LExcluded] { - - override def update( - entity: Entity, - components: LIncluded, - )(deltaTime: DeltaTime, world: World, view: View[LIncluded]): Deletable[LIncluded] = - system(entity, components, deltaTime, world, view) - } } } diff --git a/core/src/main/scala/dev/atedeg/ecscala/dsl/Conversions.scala b/core/src/main/scala/dev/atedeg/ecscala/dsl/Conversions.scala index 0a4ad2e0..4e5ee0b0 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/dsl/Conversions.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/dsl/Conversions.scala @@ -1,22 +1,21 @@ package dev.atedeg.ecscala.dsl -import dev.atedeg.ecscala.{ &:, CList, CNil, Component, Entity } -import dev.atedeg.ecscala.util.types.{ CListTag, ComponentTag } +import dev.atedeg.ecscala.{ &:, CNil, Component, ComponentTag, Entity } trait Conversions { /** - * This conversion enable the removal of a single component from an entity with the following syntax: + * This conversion enables the removal of a single component from an entity with the following syntax: * - * remove { Component() } from entity1 + * remove { myComponent } from myEntity */ given componentToClist[C <: Component: ComponentTag]: Conversion[C, C &: CNil] with def apply(component: C): C &: CNil = component &: CNil /** - * This conversion enable the removal of a single entity from the world with the following syntax: + * This conversion enables the removal of a single entity from the world with the following syntax: * - * remove { entity1 } from world + * remove { myEntity } from world */ given Conversion[Entity, Seq[Entity]] = Seq(_) } diff --git a/core/src/main/scala/dev/atedeg/ecscala/dsl/ECScalaDSL.scala b/core/src/main/scala/dev/atedeg/ecscala/dsl/ECScalaDSL.scala index 0a85fe7e..d8744abc 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/dsl/ECScalaDSL.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/dsl/ECScalaDSL.scala @@ -1,157 +1,144 @@ package dev.atedeg.ecscala.dsl -import dev.atedeg.ecscala.util.types.{ CListTag, ComponentTag } -import dev.atedeg.ecscala.{ CList, CNil, Component, Deletable, DeltaTime, Entity, System, View, World } -import dev.atedeg.ecscala.dsl.Words.* -import dev.atedeg.ecscala.util.types +import dev.atedeg.ecscala.{ + CList, + CListTag, + CNil, + Component, + ComponentTag, + Entity, + IteratingSystem, + System, + View, + World, +} +import dev.atedeg.ecscala.dsl.Syntax +//import dev.atedeg.ecscala.dsl.Words.EntityWord /** * This trait provides a domain specific language (DSL) for expressing the ECScala framework operations using an * english-like syntax. Here's the things you can do: * - * '''Create an entity in a world:''' + * '''Create an Entity in a World:''' * {{{ * val world = World() * val entity1 = world hasAn entity * }}} * - * '''Remove entities from a world:''' + * '''Remove Entities from a World:''' * {{{ - * * world - entity1 + * * world -= entity1 * * remove (entity1) from world * * remove (List(entity1, entity2, entity3)) from world * }}} * - * '''Create an entity in a world with a component:''' + * '''Create an Entity in a World with a Component:''' * {{{ - * val entity1 = world hasAn entity withComponent MyComponent() + * val entity1 = world hasAn entity withComponent myComponent * }}} * - * '''Create an entity in a world with multiple components:''' + * '''Create an Entity in a World with multiple Components:''' * {{{ * val entity1 = world hasAn entity withComponents { - * MyComponent1() &: MyComponent2() &: MyComponent3() + * myComponent1 &: myComponent2 &: myComponent3 * } * }}} * - * '''Add components to an entity:''' + * '''Add Components to an Entity:''' * {{{ - * * entity1 + MyComponent() - * * entity1 withComponent MyComponent() - * * entity1 withComponents { MyComponent1() &: MyComponent2() } + * * entity1 += myComponent + * * entity1 withComponent myComponent + * * entity1 withComponents { myComponent1 &: myComponent2 } * }}} * - * '''Remove components from an entity:''' + * '''Remove Components from an Entity:''' * {{{ - * * remove { MyComponent() } from entity1 - * * entity1 - MyComponent() - * * remove { MyComponent1() &: MyComponent2() &: MyComponent3() } from entity1 + * * remove (myComponent) from entity1 + * * entity1 -= myComponent + * * remove { myComponent1 &: myComponent2 &: myComponent3 } from entity1 * }}} * - * '''Add a system to a world:''' + * '''Add a System to a World:''' * {{{ - * world hasA system[MyComponent &: CNil] { (_,_,_) => {}} + * * world hasA system[MyComponent &: CNil] { (_,_,_) => {}} + * * world hasA system(mySistem) + * * world += mySystem * }}} * - * '''Get a view from a world:''' + * '''Remove a System from a World''' + * {{{ + * * remove (mySystem) from world + * * world -= mySystem + * }}} + * + * '''Get a View from a World:''' * {{{ * val view = getView[MyComponent1 &: MyComponent2 &: CNil] from world * }}} * - * '''Remove all entities and their components from a world:''' + * '''Get a View without certain Components''' + * {{{ + * val view = getView[MyComponent1 &: CNil].excluding[MyComponent2 &: CNil] from world + * }}} + * + * '''Remove all Entities and their Components from a World:''' * {{{ - * clearAll from world + * clearAllEntities from world * }}} */ -trait ECScalaDSL extends ExtensionMethods with Conversions with FromSyntax { +trait ECScalaDSL extends ExtensionMethods with Conversions with Syntax with Words { /** - * Keyword that enables the use of the word "entity" in the dsl. + * Keyword that enables the use of the word "entity". */ def entity: EntityWord = EntityWord() /** - * Keyword that enables the use of the word "system" in the dsl. + * Keyword that enables the use of the word "system". */ - def system[L <: CList](system: (Entity, L, DeltaTime, World, View[L]) => Deletable[L])(using - clt: CListTag[L], - )(using world: World): Unit = world.addSystem(system)(using clt) + def system(system: System)(using world: World): Unit = world.addSystem(system) /** - * Keyword that enables the use of the word "getView" in the dsl. + * Keyword that enables the use of the word "system". */ - def getView[L <: CList](using clt: CListTag[L]) = ViewFromWorld(using clt) + def system[L <: CList](system: IteratingSystem[L])(using clt: CListTag[L])(using world: World): Unit = + world.addSystem(system) /** - * Keyword that enables the use of the word "remove" in the dsl. + * Keyword that enables the use of the word "getView". */ - def remove(entities: Seq[Entity]) = FromWorld(entities) + def getView[L <: CList](using clt: CListTag[L]): ViewFromWorld[L] = ViewFromWorld(using clt) /** - * Keyword that enables the use of the word "remove" in the dsl. + * Keyword that enables the use of the word "remove" for the removal of a [[Clist]] of [[Component]] from an + * [[Entity]]. */ - def remove[L <: CList: CListTag](componentsList: L): FromEntity[L] = FromEntity(componentsList) + def remove[L <: CList: CListTag](componentsList: L): From[Entity, Unit] = ComponentsFromEntity(componentsList) /** - * Keyword that enables the use of the word "clearAll" in the dsl. + * Keyword that enables the use of the word "remove" for the removal of a [[CList]] of [[Component]] specifing their + * type from an [[Entity]]. */ - def clearAll: FromWorld = FromWorld(ClearWord()) -} - -private[dsl] trait FromSyntax { - - class FromWorld(left: Seq[Entity] | ClearWord) { + def remove[L <: CList: CListTag]: ComponentsTypeFromEntity[L] = ComponentsTypeFromEntity() - /** - * This method enables the following syntax: - * - * {{{ - * * remove (entity1) from world - * * clearAll from world - * }}} - */ - def from(world: World): Unit = left match - case entitities: Seq[Entity] => entitities foreach { world.removeEntity(_) } - case _: ClearWord => world.clear() - } - - class FromEntity[L <: CList](componentList: L)(using clt: CListTag[L]) { - - /** - * This method enables the following syntax: - * - * {{{ - * remove (myComponent) from entity1 - * }}} - */ - def from(entity: Entity): Unit = - componentList zip clt.tags.asInstanceOf[Seq[ComponentTag[Component]]] foreach { - entity.removeComponent(_)(using _) - } - } - - class ViewFromWorld[L <: CList](using clt: CListTag[L]) { + /** + * Keyword that enables the use of the word "remove" for the removal of a [[Component]] specifing its type from an + * [[Entity]]. + */ + def remove[C <: Component: ComponentTag]: From[Entity, Unit] = ComponentTypeFromEntity() - /** - * This method enables the following syntax: - * - * {{{ - * getView[MyComponent1 &: MyComponent2 &: CNil] from world - * }}} - */ - def from(world: World): View[L] = world.getView(using clt) - } -} + /** + * Keyword that enables the use of the word "remove" for the removal of an [[Entity]] from a [[World]]. + */ + def remove(entities: Seq[Entity]): From[World, Unit] = EntitiesFromWorld(entities) -object Words { + /** + * Keyword that enables the use of the word "remove" for the removal of a [[System]] from a [[World]]. + */ + def remove(system: System): From[World, Unit] = SystemFromWorld(system) /** - * This case class enables the following syntax: - * - * {{{ - * world hasAn entity - * }}} + * Keyword that enables the use of the word "clearAllEntities" in the dsl. */ - case class EntityWord() - private[dsl] case class ClearWord() + def clearAllEntities: From[World, Unit] = ClearAllFromWorld() } diff --git a/core/src/main/scala/dev/atedeg/ecscala/dsl/ExtensionMethods.scala b/core/src/main/scala/dev/atedeg/ecscala/dsl/ExtensionMethods.scala index 8888c47a..6da00398 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/dsl/ExtensionMethods.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/dsl/ExtensionMethods.scala @@ -1,9 +1,8 @@ package dev.atedeg.ecscala.dsl -import dev.atedeg.ecscala.util.types.{ CListTag, ComponentTag } -import dev.atedeg.ecscala.{ CList, Component, Entity, System, World } -import dev.atedeg.ecscala.dsl.Words.EntityWord -import dev.atedeg.ecscala.util.types.given +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ taggedWith, CList, CListTag, Component, ComponentTag, Entity, System, World } +import dev.atedeg.ecscala.dsl.EntityWord trait ExtensionMethods { @@ -17,7 +16,7 @@ trait ExtensionMethods { * }}} */ def withComponents[L <: CList](componentList: L)(using clt: CListTag[L]): Entity = { - componentList zip clt.tags.asInstanceOf[Seq[ComponentTag[Component]]] foreach { entity.addComponent(_)(using _) } + componentList.taggedWith(clt) foreach { entity.setComponent(_)(using _) } entity } @@ -28,25 +27,25 @@ trait ExtensionMethods { * entity withComponent Component() * }}} */ - def withComponent[C <: Component: ComponentTag](component: C): Entity = entity.addComponent(component) + def withComponent[C <: Component: ComponentTag](component: C): Entity = entity setComponent component /** * This method enables the following syntax: * * {{{ - * entity + Component() + * entity += Component() * }}} */ - def +[C <: Component: ComponentTag](component: C): Entity = entity.addComponent(component) + def +=[C <: Component: ComponentTag](component: C): Entity = entity setComponent component /** * This method enables the following syntax: * * {{{ - * entity - Component() + * entity -= Component() * }}} */ - def -[C <: Component: ComponentTag](component: C): Entity = entity.removeComponent(component) + def -=[C <: Component: ComponentTag](component: C): Entity = entity removeComponent component } extension (world: World) { @@ -55,10 +54,28 @@ trait ExtensionMethods { * This method enables the following syntax: * * {{{ - * world - entity + * world -= myEntity * }}} */ - def -(entity: Entity) = world.removeEntity(entity) + def -=(entity: Entity) = world removeEntity entity + + /** + * This method enables the following syntax: + * + * {{{ + * world += mySystem + * }}} + */ + def +=(system: System) = world addSystem system + + /** + * This method enables the following syntax: + * + * {{{ + * world -= mySystem + * }}} + */ + def -=(system: System) = world removeSystem system /** * This method enables the following syntax: diff --git a/core/src/main/scala/dev/atedeg/ecscala/dsl/Syntax.scala b/core/src/main/scala/dev/atedeg/ecscala/dsl/Syntax.scala new file mode 100644 index 00000000..84000ba8 --- /dev/null +++ b/core/src/main/scala/dev/atedeg/ecscala/dsl/Syntax.scala @@ -0,0 +1,126 @@ +package dev.atedeg.ecscala.dsl + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ taggedWith, CList, CListTag, Component, ComponentTag, Entity, System, View, World } + +/** + * Trait that enables the syntax of the DSL. + */ +trait Syntax { + + /** + * This trait enables the use of the word "from" in the dsl. + */ + sealed trait From[A, B] { + def from(elem: A): B + } + + /** + * This case class enables the following syntax: + * {{{ + * * remove (entity1) from world + * * remove (Seq(myEntity1, myEntity2)) from world + * }}} + */ + case class EntitiesFromWorld(entities: Seq[Entity]) extends From[World, Unit] { + override def from(world: World): Unit = entities foreach { world.removeEntity(_) } + } + + /** + * This case class enables the following syntax: + * {{{ + * remove (mySystem) from world + * }}} + */ + case class SystemFromWorld(system: System) extends From[World, Unit] { + override def from(world: World): Unit = world.removeSystem(system) + } + + /** + * This case class enables the following syntax: + * {{{ + * clearAll from world + * }}} + */ + case class ClearAllFromWorld() extends From[World, Unit] { + override def from(world: World): Unit = world.clearEntities() + } + + /** + * This case class enables the following syntax: + * + * {{{ + * remove { myComponent1 &: myComponent2 } from entity1 + * }}} + */ + case class ComponentsFromEntity[L <: CList](componentList: L)(using clt: CListTag[L]) extends From[Entity, Unit] { + + override def from(entity: Entity): Unit = + componentList.taggedWith(clt) foreach { entity.removeComponent(_)(using _) } + } + + /** + * This class enables the following syntax: + * + * {{{ + * remove[Component] from entity1 + * }}} + */ + class ComponentTypeFromEntity[C <: Component](using ct: ComponentTag[C]) extends From[Entity, Unit] { + override def from(entity: Entity): Unit = entity.removeComponent(using ct) + } + + /** + * This class enables the following syntax: + * + * {{{ + * remove[Component1 &: Component2 &: CNil ] from entity1 + * }}} + */ + class ComponentsTypeFromEntity[L <: CList](using clt: CListTag[L]) extends From[Entity, Unit] { + + override def from(entity: Entity): Unit = clt.tags foreach { entity.removeComponent(using _) } + } + + /** + * This class enables the following syntax: + * + * {{{ + * * getView[MyComponent1 &: MyComponent2 &: CNil] from world + * * getView[MyComponent1 &: MyComponent2 &: CNil].exluding[MyComponent3 &: CNil] from world + * }}} + */ + class ViewFromWorld[LA <: CList](using cltA: CListTag[LA]) extends From[World, View[LA]] { + override def from(world: World): View[LA] = world.getView(using cltA) + + def excluding[LB <: CList](using cltB: CListTag[LB]): ExcludingViewFromWorld[LA, LB] = ExcludingViewFromWorld(using + cltA, + )(using cltB) + } + + /** + * This class enables the following syntax: + * + * {{{ + * getView[MyComponent1 &: MyComponent2 &: CNil].exluding[MyComponent3 &: CNil] from world + * }}} + */ + class ExcludingViewFromWorld[LA <: CList, LB <: CList](using cltA: CListTag[LA])(using cltB: CListTag[LB]) + extends From[World, View[LA]] { + def from(world: World) = world.getView(using cltA, cltB) + } +} + +/** + * Trait that enables the words of the DSL. + */ +trait Words + +/** + * This case class enables the following syntax: + * + * {{{ + * world hasAn entity + * }}} + */ +case class EntityWord() extends Words diff --git a/core/src/main/scala/dev/atedeg/ecscala/util/BaseIterableMap.scala b/core/src/main/scala/dev/atedeg/ecscala/util/BaseIterableMap.scala deleted file mode 100644 index 49bd1988..00000000 --- a/core/src/main/scala/dev/atedeg/ecscala/util/BaseIterableMap.scala +++ /dev/null @@ -1,73 +0,0 @@ -package dev.atedeg.ecscala.util - -import scala.collection.* -import scala.collection.mutable.ReusableBuilder -import scala.collection.generic.DefaultSerializable - -trait IterableMap[K, +V] - extends Map[K, V] - with MapOps[K, V, IterableMap, IterableMap[K, V]] - with MapFactoryDefaults[K, V, IterableMap, Iterable] { - override def mapFactory: MapFactory[IterableMap] = IterableMap -} - -private[util] abstract class BaseIterableMap[K, V](elems: (K, V)*) extends IterableMap[K, V] { - - protected type Dense[T] <: IndexedSeq[T] with SeqOps[T, IndexedSeq, IndexedSeq[T]] - protected type Sparse[K, V] <: Map[K, V] - - protected def denseFactory: SeqFactory[Dense] - protected def sparseFactory: MapFactory[Sparse] - - protected val denseKeys: Dense[K] = denseFactory.from(elems map { _._1 }) - protected val denseValues: Dense[V] = denseFactory.from(elems map { _._2 }) - protected val sparseKeysIndices: Sparse[K, Int] = sparseFactory.from(denseKeys.zipWithIndex) - - override def mapFactory: MapFactory[IterableMap] = IterableMap - - override def get(key: K): Option[V] = sparseKeysIndices get key map { denseValues(_) } - - override def iterator: Iterator[(K, V)] = new Iterator[(K, V)] { - private var nextIndex = 0 - - override def hasNext: Boolean = nextIndex < math.min(denseKeys.size, denseValues.size) - - override def next(): (K, V) = { - val kv = (denseKeys(nextIndex), denseValues(nextIndex)) - nextIndex += 1 - kv - } - } - - override def keys: scala.Iterable[K] = denseKeys - - override def keySet: Set[K] = Set.from(denseKeys) - - override def keysIterator: Iterator[K] = denseKeys.iterator - - override def values: scala.Iterable[V] = denseValues - - override def valuesIterator: Iterator[V] = denseValues.iterator -} - -object IterableMap extends MapFactory.Delegate[IterableMap](dev.atedeg.ecscala.util.immutable.IterableMap) - -private[util] abstract class BaseIterableMapBuilder[K, V, CC[K, V] <: Map[K, V]] - extends ReusableBuilder[(K, V), CC[K, V]] { - - def emptyFactory(): CC[K, V] - def addElement(map: CC[K, V], elem: (K, V)): CC[K, V] - - private var elems: CC[K, V] = emptyFactory() - - override def clear(): Unit = { - elems = emptyFactory() - } - - override def result(): CC[K, V] = elems - - override def addOne(elem: (K, V)): this.type = { - elems = addElement(elems, elem) - this - } -} diff --git a/core/src/main/scala/dev/atedeg/ecscala/util/immutable/IterableMap.scala b/core/src/main/scala/dev/atedeg/ecscala/util/immutable/IterableMap.scala deleted file mode 100644 index f1731677..00000000 --- a/core/src/main/scala/dev/atedeg/ecscala/util/immutable/IterableMap.scala +++ /dev/null @@ -1,61 +0,0 @@ -package dev.atedeg.ecscala.util.immutable - -import scala.collection.generic.DefaultSerializable -import scala.collection.{ IterableFactory, MapFactory, MapFactoryDefaults } -import scala.collection.mutable.{ Builder, ReusableBuilder } -import scala.collection.immutable.{ Iterable, Map, MapOps } - -import dev.atedeg.ecscala.util.{ BaseIterableMap, BaseIterableMapBuilder } - -/** - * This trait represents an immutable [[scala.collection.immutable.Map]] that can be efficiently iterated. - * - * @tparam K - * the type of the keys contained in this map. - * @tparam V - * the type of the values associated with the keys in this map. - */ -trait IterableMap[K, +V] - extends dev.atedeg.ecscala.util.IterableMap[K, V] - with Map[K, V] - with MapOps[K, V, IterableMap, IterableMap[K, V]] - with MapFactoryDefaults[K, V, IterableMap, Iterable] - with DefaultSerializable { - override def mapFactory: MapFactory[IterableMap] = IterableMap -} - -/** - * This object provides a set of operations to create [[dev.atedeg.ecscala.util.immutable.IterableMap]] values. - */ -object IterableMap extends MapFactory[IterableMap] { - - override def empty[K, V]: IterableMap[K, V] = new IterableMapImpl() - - override def from[K, V](it: IterableOnce[(K, V)]): IterableMap[K, V] = new IterableMapImpl(it.iterator.toSeq: _*) - - override def newBuilder[K, V]: Builder[(K, V), IterableMap[K, V]] = new IterableMapBuilderImpl() - - override def apply[K, V](elems: (K, V)*): IterableMap[K, V] = new IterableMapImpl(elems: _*) - - private class IterableMapImpl[K, V](elems: (K, V)*) extends BaseIterableMap[K, V](elems: _*) with IterableMap[K, V] { - - override type Dense[T] = Vector[T] - override type Sparse[K, V] = Map[K, V] - - override protected def denseFactory = Vector - override protected def sparseFactory = Map - - private def withoutElem(key: K): Seq[(K, V)] = denseKeys zip denseValues filter { _._1 != key } - - override def removed(key: K): IterableMap[K, V] = IterableMap.from(withoutElem(key)) - - override def updated[V1 >: V](key: K, value: V1): IterableMap[K, V1] = - IterableMap.from(withoutElem(key) :+ (key, value)) - } - - private class IterableMapBuilderImpl[K, V] extends BaseIterableMapBuilder[K, V, IterableMap] { - - override def emptyFactory(): IterableMap[K, V] = IterableMap.empty - override def addElement(map: IterableMap[K, V], elem: (K, V)): IterableMap[K, V] = map + elem - } -} diff --git a/core/src/main/scala/dev/atedeg/ecscala/util/immutable/ComponentsContainer.scala b/core/src/main/scala/dev/atedeg/ecscala/util/mutable/ComponentsContainer.scala similarity index 54% rename from core/src/main/scala/dev/atedeg/ecscala/util/immutable/ComponentsContainer.scala rename to core/src/main/scala/dev/atedeg/ecscala/util/mutable/ComponentsContainer.scala index 06fba09d..5951b5b7 100644 --- a/core/src/main/scala/dev/atedeg/ecscala/util/immutable/ComponentsContainer.scala +++ b/core/src/main/scala/dev/atedeg/ecscala/util/mutable/ComponentsContainer.scala @@ -1,7 +1,9 @@ -package dev.atedeg.ecscala.util.immutable +package dev.atedeg.ecscala.util.mutable -import dev.atedeg.ecscala.{ Component, Entity } -import dev.atedeg.ecscala.util.types.ComponentTag +import scala.collection.Map +import scala.collection.mutable.AnyRefMap +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ Component, ComponentTag, Entity } /** * This trait represents a container of multiple [[scala.collection.immutable.Map]] [Entity, T], with T subtype of @@ -66,69 +68,53 @@ private[ecscala] trait ComponentsContainer { private[ecscala] object ComponentsContainer { def apply(): ComponentsContainer = new ComponentsContainerImpl - private def apply(map: Map[ComponentTag[? <: Component], Map[Entity, ? <: Component]]) = new ComponentsContainerImpl( - map, - ) - private class ComponentsContainerImpl( - private val componentsMap: Map[ComponentTag[? <: Component], Map[Entity, ? <: Component]] = Map(), + private val componentsMap: AnyRefMap[ComponentTag[? <: Component], AnyRefMap[Entity, ? <: Component]] = + AnyRefMap(), ) extends ComponentsContainer { - override def apply[C <: Component](using ct: ComponentTag[C]) = - // This cast is needed to return a map with the appropriate type and not a generic "Component" type. - // It is always safe to perform such a cast since the ComponentTag holds the type of the retrieved map's components. - componentsMap.get(ct) map (_.asInstanceOf[Map[Entity, C]]) + override def apply[C <: Component](using ct: ComponentTag[C]): Option[Map[Entity, C]] = getContainer[C](using ct) override def addComponent[C <: Component](entityComponentPair: (Entity, C))(using ct: ComponentTag[C]) = { - val newComponentMap = this.apply[C] map (_ + entityComponentPair) getOrElse (Map(entityComponentPair)) - val newComponentsMap = componentsMap + (ct -> newComponentMap) - ComponentsContainer(newComponentsMap) - } - - extension [C <: Component](map: Map[Entity, C]) { - - def -(entityComponentPair: (Entity, C)): Map[Entity, C] = { - val (entity, component) = entityComponentPair - // The components are compared using the eq method because, when removing elements, two components are - // considered to be equal only if they are the same object. - map filterNot ((e, c) => e == entity && c.eq(component)) + val (entity, component) = entityComponentPair + getContainer[C] match { + case None => componentsMap += ct -> AnyRefMap(entityComponentPair) + case Some(componentMap) => { + val oldComponent = componentMap get entity + oldComponent map (_.entity = None) + componentMap += entityComponentPair + } } - - /** - * @param entityComponentPair - * the pair to remove. - * @return - * an [[Option]] with the map with the removed pair if the map still has some elements; if the removed element - * was the last one and the map would be empty it returns a None. - */ - def -?(entityComponentPair: (Entity, C)): Option[Map[Entity, C]] = - Some(map - entityComponentPair) filter (!_.isEmpty) - - /** - * @param entity - * the [[Entity]] to remove. - * @return - * an [[Option]] with the map with the removed [[Entity]] if the map still has some elements; if the removed - * element was the last one and the map would be empty it returns a None. - */ - def -?(entity: Entity): Option[Map[Entity, C]] = Some(map - entity) filter (_.nonEmpty) + this } override def removeComponent[C <: Component](entityComponentPair: (Entity, C))(using ct: ComponentTag[C]) = { - val newComponentsMap = - this.apply[C] flatMap (_ -? entityComponentPair) match { - case Some(componentMap) => componentsMap + (ct -> componentMap) - case None => componentsMap - ct + getContainer[C] foreach { componentMap => + val (entity, component) = entityComponentPair + val actualComponent = componentMap get entity filter (_ eq component) + actualComponent map { c => + componentMap -= entity + c.entity = None } - ComponentsContainer(newComponentsMap) + } + this } override def removeEntity(entity: Entity) = { - val newComponentsMap: Map[ComponentTag[? <: Component], Map[Entity, Component]] = - componentsMap flatMap { (ct, componentMap) => (componentMap -? entity) map (ct -> _) } - ComponentsContainer(newComponentsMap) + componentsMap foreach { (ct, componentMap) => + val foundComponent = componentMap get entity + foundComponent foreach { _.entity = None } + componentMap -= entity + } + this } override def toString: String = componentsMap.toString + + private def getContainer[C <: Component](using ct: ComponentTag[C]): Option[AnyRefMap[Entity, C]] = { + // This cast is needed to return a map with the appropriate type and not a generic "Component" type. + // It is always safe to perform such a cast since the ComponentTag holds the type of the retrieved map's components. + componentsMap get ct map (_.asInstanceOf[AnyRefMap[Entity, C]]) filter (!_.isEmpty) + } } } diff --git a/core/src/main/scala/dev/atedeg/ecscala/util/mutable/IterableMap.scala b/core/src/main/scala/dev/atedeg/ecscala/util/mutable/IterableMap.scala deleted file mode 100644 index 036459e3..00000000 --- a/core/src/main/scala/dev/atedeg/ecscala/util/mutable/IterableMap.scala +++ /dev/null @@ -1,92 +0,0 @@ -package dev.atedeg.ecscala.util.mutable - -import scala.collection.generic.DefaultSerializable -import scala.collection.{ mutable, MapFactory, MapFactoryDefaults, SeqFactory } -import scala.collection.mutable.{ AbstractMap, ArrayBuffer, Builder, HashMap, Iterable, Map, MapOps, ReusableBuilder } -import dev.atedeg.ecscala.util.{ BaseIterableMap, BaseIterableMapBuilder } - -/** - * This trait represents a mutable [[scala.collection.mutable.Map]] that can be efficiently iterated. - * - * @tparam K - * the type of the keys contained in this map. - * @tparam V - * the type of the values associated with the keys in this map. - */ -trait IterableMap[K, V] - extends dev.atedeg.ecscala.util.IterableMap[K, V] - with Map[K, V] - with MapOps[K, V, IterableMap, IterableMap[K, V]] - with MapFactoryDefaults[K, V, IterableMap, Iterable] - with DefaultSerializable { - override def mapFactory: MapFactory[IterableMap] = IterableMap -} - -/** - * This object provides a set of operations to create [[dev.atedeg.ecscala.util.mutable.IterableMap]] values. - */ -object IterableMap extends MapFactory[IterableMap] { - - override def empty[K, V]: IterableMap[K, V] = new IterableMapImpl() - - override def from[K, V](it: IterableOnce[(K, V)]): IterableMap[K, V] = new IterableMapImpl(it.iterator.toSeq: _*) - - override def newBuilder[K, V]: mutable.Builder[(K, V), IterableMap[K, V]] = new IterableMapBuilderImpl() - - override def apply[K, V](elems: (K, V)*): IterableMap[K, V] = new IterableMapImpl(elems: _*) - - private class IterableMapImpl[K, V](elems: (K, V)*) extends BaseIterableMap[K, V](elems: _*) with IterableMap[K, V] { - - override protected type Dense[T] = ArrayBuffer[T] - override protected type Sparse[K, V] = HashMap[K, V] - - override protected def denseFactory = ArrayBuffer - override protected def sparseFactory = HashMap - - override def addOne(elem: (K, V)): this.type = { - val (key, value) = elem - sparseKeysIndices get key match { - // If there already is an element with the given key it simply replaces the value associated with it, there is no need to change the sparse index - case Some(keyIndex) => denseValues(keyIndex) = value - case None => { - val denseIndex = denseKeys.size + 1 - denseKeys += key - denseValues += value - sparseKeysIndices += (key -> denseIndex) - } - } - this - } - - override def subtractOne(elem: K): this.type = { - // We switch the last item in place of the one we deleted - val elemIndex = sparseKeysIndices get elem - elemIndex match { - case Some(index) => { - sparseKeysIndices -= elem - if (index != denseKeys.size - 1) replaceWithLast(index) - removeLast() - this - } - case None => this - } - } - - private def replaceWithLast(index: Int): Unit = { - denseKeys(index) = denseKeys.last - denseValues(index) = denseValues.last - sparseKeysIndices += (denseKeys.last -> index) - } - - private def removeLast(): Unit = { - denseKeys.dropRightInPlace(1) - denseValues.dropRightInPlace(1) - } - } - - private class IterableMapBuilderImpl[K, V] extends BaseIterableMapBuilder[K, V, IterableMap] { - - override def emptyFactory(): IterableMap[K, V] = IterableMap.empty - override def addElement(map: IterableMap[K, V], elem: (K, V)): IterableMap[K, V] = map.addOne(elem) - } -} diff --git a/core/src/test/scala/dev/atedeg/ecscala/util/types/CListTagTest.scala b/core/src/test/scala/dev/atedeg/ecscala/CListTagTest.scala similarity index 97% rename from core/src/test/scala/dev/atedeg/ecscala/util/types/CListTagTest.scala rename to core/src/test/scala/dev/atedeg/ecscala/CListTagTest.scala index c2157d9c..2df505ae 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/util/types/CListTagTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/CListTagTest.scala @@ -1,9 +1,9 @@ -package dev.atedeg.ecscala.util.types +package dev.atedeg.ecscala import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -import dev.atedeg.ecscala.{ &:, CList, CNil } import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Position, Velocity } +import dev.atedeg.ecscala.{ &:, CList, CNil } class CListTagTest extends AnyWordSpec with Matchers { diff --git a/core/src/test/scala/dev/atedeg/ecscala/CListTest.scala b/core/src/test/scala/dev/atedeg/ecscala/CListTest.scala index cb6e234d..e09a6a43 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/CListTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/CListTest.scala @@ -1,9 +1,9 @@ package dev.atedeg.ecscala -import dev.atedeg.ecscala.util.types.given -import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Mass, Position, Velocity } import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Mass, Position, Velocity } class CListTest extends AnyWordSpec with Matchers { diff --git a/core/src/test/scala/dev/atedeg/ecscala/util/types/ComponentTagTest.scala b/core/src/test/scala/dev/atedeg/ecscala/ComponentTagTest.scala similarity index 97% rename from core/src/test/scala/dev/atedeg/ecscala/util/types/ComponentTagTest.scala rename to core/src/test/scala/dev/atedeg/ecscala/ComponentTagTest.scala index 8d7a31a3..8545341a 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/util/types/ComponentTagTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/ComponentTagTest.scala @@ -1,4 +1,4 @@ -package dev.atedeg.ecscala.util.types +package dev.atedeg.ecscala import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec diff --git a/core/src/test/scala/dev/atedeg/ecscala/EntityTest.scala b/core/src/test/scala/dev/atedeg/ecscala/EntityTest.scala index a4610ff4..2a4e871f 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/EntityTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/EntityTest.scala @@ -1,9 +1,9 @@ package dev.atedeg.ecscala -import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Mass, Position, WorldFixture } -import dev.atedeg.ecscala.util.types.given -import org.scalatest.matchers.should.* +import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.fixtures.{ Mass, Position, WorldFixture } class EntityTest extends AnyWordSpec with Matchers { @@ -14,13 +14,20 @@ class EntityTest extends AnyWordSpec with Matchers { entities shouldBe entities.distinct } } + "forbid having an already assigned component" in new WorldFixture { + val component = Position(0, 0) + val entity1 = world.createEntity() + val entity2 = world.createEntity() + entity1 setComponent component + an[IllegalArgumentException] shouldBe thrownBy(entity2 setComponent component) + } "get its components correctly" in new WorldFixture { val entity1 = world.createEntity() val entity2 = world.createEntity() val c1 = Position(1, 1) val c2 = Position(2, 2) - entity1 addComponent c1 - entity2 addComponent c2 + entity1 setComponent c1 + entity2 setComponent c2 entity1.getComponent[Position] shouldBe Some(c1) entity1.getComponent[Position] flatMap (_.entity) shouldBe Some(entity1) entity2.getComponent[Position] shouldBe Some(c2) @@ -32,7 +39,7 @@ class EntityTest extends AnyWordSpec with Matchers { val entity = world.createEntity() val component = Position(1, 1) component.entity shouldBe empty - entity addComponent component + entity setComponent component component.entity should contain(entity) removal(entity, component) component.entity shouldBe empty diff --git a/core/src/test/scala/dev/atedeg/ecscala/SystemBuilderTest.scala b/core/src/test/scala/dev/atedeg/ecscala/SystemBuilderTest.scala new file mode 100644 index 00000000..8e7d90fa --- /dev/null +++ b/core/src/test/scala/dev/atedeg/ecscala/SystemBuilderTest.scala @@ -0,0 +1,124 @@ +package dev.atedeg.ecscala + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.fixtures.{ Position, SystemBuilderFixture, Velocity } + +class SystemBuilderTest extends AnyWordSpec with Matchers { + def using = afterWord("using") + + "A SystemBuilder" should { + "work with the update with the partial parameter list" in new SystemBuilderFixture { + var updateExecuted = false + world.addSystem(SystemBuilder[Position &: CNil].withUpdate { (_, c, _) => + updateExecuted = true; c + }) + world.update(10) + updateExecuted shouldBe true + } + "work with the update with the complete parameter list" in new SystemBuilderFixture { + var updateExecuted = false + world.addSystem(SystemBuilder[Position &: CNil].withUpdate { (_, c, _, _, _) => + updateExecuted = true; c + }) + world.update(10) + updateExecuted shouldBe true + } + "return the correct system" when using { + "withBefore" in new SystemBuilderFixture { + var beforeExecuted = false + world.addSystem( + SystemBuilder[Position &: CNil].withBefore { (_, _, _) => beforeExecuted = true }.withUpdate { (_, c, _) => + c + }, + ) + world.update(10) + beforeExecuted shouldBe true + } + "withAfter" in new SystemBuilderFixture { + var afterExecuted = false + world.addSystem( + SystemBuilder[Position &: CNil].withAfter { (_, _, _) => afterExecuted = true }.withUpdate { (_, c, _) => c }, + ) + world.update(10) + afterExecuted shouldBe true + } + "withPrecondition" in new SystemBuilderFixture { + var updateExecuted = false + world.addSystem( + SystemBuilder[Position &: CNil] + .withPrecondition(false) + .withUpdate { (_, c, _) => + updateExecuted = true; c + }, + ) + world.update(10) + updateExecuted shouldBe false + } + "withBefore and withAfter" in new SystemBuilderFixture { + var afterExecuted = false + var beforeExecuted = false + world.addSystem( + SystemBuilder[Position &: CNil].withBefore { (_, _, _) => beforeExecuted = true }.withAfter { (_, _, _) => + afterExecuted = true + }.withUpdate { (_, c, _) => c }, + ) + world.update(10) + afterExecuted shouldBe true + beforeExecuted shouldBe true + } + } + } + + "A SystemBuilder" can { + "be converted to an ExcludingSystemBuilder independently from when it is called" in new SystemBuilderFixture { + var updateExecuted = false + world.addSystem( + SystemBuilder[Position &: CNil] + .excluding[Velocity &: CNil] + .withBefore { (_, _, _) => () } + .withAfter { (_, _, _) => () } + .withUpdate { (_, c, _) => + updateExecuted = true; c + }, + ) + world.addSystem( + SystemBuilder[Position &: CNil].withBefore { (_, _, _) => () } + .excluding[Velocity &: CNil] + .withAfter { (_, _, _) => () } + .withUpdate { (_, c, _) => + updateExecuted = true; c + }, + ) + world.addSystem( + SystemBuilder[Position &: CNil].withBefore { (_, _, _) => () }.withAfter { (_, _, _) => () } + .excluding[Velocity &: CNil] + .withUpdate { (_, c, _) => + updateExecuted = true; c + }, + ) + world.update(10) + updateExecuted shouldBe false + } + } + + "An ExcludingSystemBuilder" should { + "work with the update with the partial parameter list" in new SystemBuilderFixture { + var updateExecuted = false + world.addSystem(ExcludingSystemBuilder[Position &: CNil, Velocity &: CNil].withUpdate { (_, c, _) => + updateExecuted = true; c + }) + world.update(10) + updateExecuted shouldBe false + } + "work with the update with the full parameter list" in new SystemBuilderFixture { + var updateExecuted = false + world.addSystem(ExcludingSystemBuilder[Position &: CNil, Velocity &: CNil].withUpdate { (_, c, _, _, _) => + updateExecuted = true; c + }) + world.update(10) + updateExecuted shouldBe false + } + } +} diff --git a/core/src/test/scala/dev/atedeg/ecscala/SystemTest.scala b/core/src/test/scala/dev/atedeg/ecscala/SystemTest.scala index 8ac25db3..7fba25c6 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/SystemTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/SystemTest.scala @@ -1,9 +1,9 @@ package dev.atedeg.ecscala -import dev.atedeg.ecscala.fixtures.{ Mass, Position, Velocity, ViewFixture } -import dev.atedeg.ecscala.util.types.given import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.fixtures.{ Mass, Position, Velocity, ViewFixture } class SystemTest extends AnyWordSpec with Matchers { def beAbleTo = afterWord("be able to") @@ -12,28 +12,47 @@ class SystemTest extends AnyWordSpec with Matchers { "with a false precondition" should { "not execute" in new ViewFixture { var success = true - world.addSystem(new System[Position &: CNil] { - override def shouldRun = false - override def before(deltaTime: DeltaTime, world: World, view: View[Position &: CNil]): Unit = success = false - override def after(deltaTime: DeltaTime, world: World, view: View[Position &: CNil]): Unit = success = false - override def update( - entity: Entity, - components: Position &: CNil, - )(deltaTime: DeltaTime, world: World, view: View[Position &: CNil]) = { - success = false - components - } + world.addSystem(new System { + override def shouldRun: Boolean = false + + override def update(deltaTime: DeltaTime, world: World): Unit = success = false }) world.update(10) success shouldBe true } } + "execute when updating" in new ViewFixture { + var success = false + world.addSystem(System((_, _) => success = true)) + world.update(10) + success shouldBe true + } + } + + "An IteratingSystem" when { + "with a false precondition" should { + "not execute" in new ViewFixture { + var success = true + world.addSystem( + System[Position &: CNil] + .withPrecondition(false) + .withBefore { (_, _, _) => success = false } + .withAfter { (_, _, _) => success = false } + .withUpdate { (_, components, _) => + success = false + components + }, + ) + world.update(10) + success shouldBe true + } + } "executing its update" should beAbleTo { "update components" in new ViewFixture { - world.addSystem[Position &: Velocity &: CNil]((_, comps, _) => { + world.addSystem(IteratingSystem[Position &: Velocity &: CNil]((_, comps, _) => { val Position(x, y) &: Velocity(vx, vy) &: CNil = comps Position(x + 1, y + 1) &: Velocity(vx + 1, vy + 1) &: CNil - }) + })) world.update(10) world.getView[Position &: Velocity &: CNil] should contain theSameElementsAs List( @@ -43,15 +62,15 @@ class SystemTest extends AnyWordSpec with Matchers { ) } "remove components" in new ViewFixture { - world.addSystem[Position &: Velocity &: CNil]((_, _, _) => Deleted &: Deleted &: CNil) + world.addSystem(IteratingSystem[Position &: Velocity &: CNil]((_, _, _) => Deleted &: Deleted &: CNil)) world.update(10) world.getView[Position &: Velocity &: CNil] shouldBe empty } "add components" in new ViewFixture { - world.addSystem[Position &: Velocity &: CNil]((entity, comps, _) => { - entity addComponent Mass(10) + world.addSystem(IteratingSystem[Position &: Velocity &: CNil]((entity, comps, _) => { + entity setComponent Mass(10) comps - }) + })) world.update(10) world.getView[Mass &: CNil] should contain theSameElementsAs List( @@ -63,50 +82,44 @@ class SystemTest extends AnyWordSpec with Matchers { ) } "add entities to its world" in new ViewFixture { - world.addSystem[Position &: CNil]((_, comps, _, w, _) => { + world.addSystem(IteratingSystem[Position &: CNil]((_, comps, _, w, _) => { w.createEntity() comps - }) + })) world.update(10) world.entitiesCount shouldBe 9 } "remove entities from its world" in new ViewFixture { - world.addSystem[Position &: CNil]((entity, comps, _, w, _) => { + world.addSystem(IteratingSystem[Position &: CNil]((entity, comps, _, w, _) => { w.removeEntity(entity) comps - }) + })) world.update(10) world.entitiesCount shouldBe 1 } } "executing its update" should { "have the correct delta time" in new ViewFixture { - world.addSystem[Position &: CNil]((_, comps, dt) => { + world.addSystem(IteratingSystem[Position &: CNil]((_, comps, dt) => { dt shouldBe 10 comps - }) + })) world.update(10) } "execute its before and after handlers in the correct order" in new ViewFixture { type Comps = Position &: Velocity &: CNil - val testSystem = new System[Comps] { - override def before(deltaTime: DeltaTime, world: World, view: View[Comps]) = - view foreach (entityComponentsPair => { - val (entity, Position(px, py) &: _) = entityComponentsPair - entity.addComponent(Position(px * 2, py * 2)) - }) + val testSystem = System[Comps].withBefore { (deltaTime, world, view) => + view foreach (entityComponentsPair => { + val (entity, Position(px, py) &: _) = entityComponentsPair + entity setComponent Position(px * 2, py * 2) + }) + }.withAfter { (deltaTime, world, view) => + view foreach (entityComponentsPair => { + val (entity, Position(px, py) &: _) = entityComponentsPair + entity setComponent Position(px + 1, py + 1) + }) + }.withUpdate { (_, components, _) => components } - override def after(deltaTime: DeltaTime, world: World, view: View[Comps]) = - view foreach (entityComponentsPair => { - val (entity, Position(px, py) &: _) = entityComponentsPair - entity.addComponent(Position(px + 1, py + 1)) - }) - - override def update( - entity: Entity, - components: Comps, - )(deltaTime: DeltaTime, world: World, view: View[Comps]) = components - } world.addSystem(testSystem) world.update(10) @@ -122,10 +135,10 @@ class SystemTest extends AnyWordSpec with Matchers { "An ExcludingSystem" when { "executing its update" should beAbleTo { "update components" in new ViewFixture { - world.addSystem[Position &: Velocity &: CNil, Mass &: CNil]((_, comps, _) => { + world.addSystem(ExcludingSystem[Position &: Velocity &: CNil, Mass &: CNil]((_, comps, _, _, _) => { val Position(x, y) &: Velocity(vx, vy) &: CNil = comps Position(x + 1, y + 1) &: Velocity(vx + 1, vy + 1) &: CNil - }) + })) world.update(10) world.getView[Position &: Velocity &: CNil, Mass &: CNil] should contain theSameElementsAs List( @@ -134,14 +147,16 @@ class SystemTest extends AnyWordSpec with Matchers { ) } } - } - - "An EmptySystem" should { - "execute its update" in new ViewFixture { - var success = false - world.addSystem(EmptySystem(() => success = true)) - world.update(10) - success shouldBe true + "excludes included components" should { + "not run its update" in new ViewFixture { + var updateExecuted = false + world.addSystem( + System[Position &: CNil].excluding[Position &: CNil].withUpdate { (_, cs, _) => + updateExecuted = true; cs + }, + ) + updateExecuted shouldBe false + } } } } diff --git a/core/src/test/scala/dev/atedeg/ecscala/ViewTest.scala b/core/src/test/scala/dev/atedeg/ecscala/ViewTest.scala index e36b9547..13a40ff6 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/ViewTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/ViewTest.scala @@ -1,9 +1,9 @@ package dev.atedeg.ecscala -import dev.atedeg.ecscala.util.types.given -import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Gravity, Mass, Position, Velocity, ViewFixture, WorldFixture } import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.fixtures.{ Gravity, Mass, Position, Velocity, ViewFixture } class ViewTest extends AnyWordSpec with Matchers { @@ -53,7 +53,7 @@ class ViewTest extends AnyWordSpec with Matchers { } "allow to change the entities and reflect the changes on successive iteration" in new ViewFixture { val view = world.getView[Velocity &: Mass &: CNil] - view foreach (_.head.addComponent(Mass(11))) + view foreach (_.head setComponent Mass(11)) view should contain theSameElementsAs List((entity3, Velocity(1, 1) &: Mass(11))) } } diff --git a/core/src/test/scala/dev/atedeg/ecscala/WorldTest.scala b/core/src/test/scala/dev/atedeg/ecscala/WorldTest.scala index b8a86e5c..9f59b308 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/WorldTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/WorldTest.scala @@ -1,10 +1,9 @@ package dev.atedeg.ecscala -import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Position, ViewFixture, WorldFixture } -import dev.atedeg.ecscala.util.types.ComponentTag -import dev.atedeg.ecscala.util.types.given -import org.scalatest.matchers.should.* +import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Position, ViewFixture, WorldFixture } class WorldTest extends AnyWordSpec with Matchers { @@ -21,6 +20,16 @@ class WorldTest extends AnyWordSpec with Matchers { } } "has 1 entity" should { + "remove all its components" when { + "it is cleared" in new WorldFixture { + val entity = world.createEntity() + val position = Position(1, 1) + entity.setComponent(position) + world.clearEntities() + position.entity shouldBe empty + entity.getComponent[Position] shouldBe empty + } + } "have size 0" when { "an entity is removed" in new WorldFixture { val entity = world.createEntity() @@ -31,8 +40,8 @@ class WorldTest extends AnyWordSpec with Matchers { "not have a component of a removed entity" in new WorldFixture { val entity = world.createEntity() val entity1 = world.createEntity() - entity.addComponent(Position(1, 2)) - entity1.addComponent(Position(1, 2)) + entity setComponent Position(1, 2) + entity1 setComponent Position(1, 2) world.removeEntity(entity) world.getComponents[Position] should contain(Map(entity1 -> Position(1, 2))) @@ -45,7 +54,7 @@ class WorldTest extends AnyWordSpec with Matchers { val entity1 = world.createEntity() val entity2 = world.createEntity() - world.clear() + world.clearEntities() world.entitiesCount shouldBe 0 } @@ -53,10 +62,10 @@ class WorldTest extends AnyWordSpec with Matchers { "not have the components from the removed entities" in new WorldFixture { val entity = world.createEntity() val entity1 = world.createEntity() - entity.addComponent(Position(1, 2)) - entity1.addComponent(Position(3, 4)) + entity setComponent Position(1, 2) + entity1 setComponent Position(3, 4) - world.clear() + world.clearEntities() world.getComponents[Position] shouldBe empty } @@ -64,7 +73,7 @@ class WorldTest extends AnyWordSpec with Matchers { "has entities with components" should { "return the components" in new WorldFixture with ComponentsFixture { val entity = world.createEntity() - entity addComponent Position(1, 1) + entity setComponent Position(1, 1) world.getComponents[Position] should contain(Map(entity -> Position(1, 1))) } } @@ -72,9 +81,9 @@ class WorldTest extends AnyWordSpec with Matchers { "not return the components" in new WorldFixture with ComponentsFixture { val entity = world.createEntity() val component = Position(1, 1) - entity addComponent component + entity setComponent component entity removeComponent component - entity addComponent Position(1, 1) + entity setComponent Position(1, 1) entity.removeComponent[Position] world.getComponents[Position] shouldBe empty @@ -82,15 +91,15 @@ class WorldTest extends AnyWordSpec with Matchers { } "update is called" should { "execute all systems in the same order as they were added" in new ViewFixture { - world.addSystem[Position &: CNil]((_, comps, _, _, _) => { + world.addSystem(IteratingSystem[Position &: CNil]((_, comps, _) => { val Position(px, py) &: CNil = comps Position(px * 2, py * 2) &: CNil - }) + })) - world.addSystem[Position &: CNil]((_, comps, _, _, _) => { + world.addSystem(IteratingSystem[Position &: CNil]((_, comps, _) => { val Position(x, y) &: CNil = comps Position(x + 1, y + 1) &: CNil - }) + })) world.update(10) @@ -102,5 +111,23 @@ class WorldTest extends AnyWordSpec with Matchers { ) } } + "a System is removed" should { + "not execute its update" in new WorldFixture { + val entity = world.createEntity() + entity setComponent Position(1, 1) + val system = SystemBuilder[Position &: CNil].withBefore { (_, _, _) => () }.withAfter { (_, _, _) => + () + }.withUpdate { (_, c, _) => + val Position(x, y) &: CNil = c + Position(x + 1, y + 1) &: CNil + } + + world.addSystem(system) + world.removeSystem(system) + world.update(10) + + world.getView[Position &: CNil].toList shouldBe List((entity, Position(1, 1) &: CNil)) + } + } } } diff --git a/core/src/test/scala/dev/atedeg/ecscala/dsl/ECScalaDSLTest.scala b/core/src/test/scala/dev/atedeg/ecscala/dsl/ECScalaDSLTest.scala index 4314880f..f03e250a 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/dsl/ECScalaDSLTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/dsl/ECScalaDSLTest.scala @@ -1,22 +1,28 @@ package dev.atedeg.ecscala.dsl -import dev.atedeg.ecscala.{ &:, fixtures, CNil, Component, Entity, World } -import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Gravity, Position, Velocity, ViewFixture, WorldFixture } -import dev.atedeg.ecscala.util.types.ComponentTag +import scala.language.implicitConversions import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -import dev.atedeg.ecscala.util.types.given +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, fixtures, CNil, Component, Entity, IteratingSystem, System, View, World } import dev.atedeg.ecscala.dsl.ECScalaDSL -import scala.language.implicitConversions +import dev.atedeg.ecscala.fixtures.{ + ComponentsFixture, + Gravity, + Mass, + Position, + SystemFixture, + Velocity, + ViewFixture, + WorldFixture, +} class ECScalaDSLTest extends AnyWordSpec with Matchers with ECScalaDSL { "world hasAn entity withComponents { Component1 &: Component2 }" should { - "work the same way as the world.createEntity() &: entity.addComponent() methods" in new WorldFixture + "work the same way as the world.createEntity() &: entity.setComponent() methods" in new WorldFixture with ComponentsFixture { - val entity1 = world hasAn entity withComponents { - Position(1, 2) &: Velocity(3, 4) &: Gravity(9) - } + val entity1 = world hasAn entity withComponents { Position(1, 2) &: Velocity(3, 4) &: Gravity(9) } val entity2 = world hasAn entity withComponent Gravity(24) val world2 = World() @@ -32,21 +38,21 @@ class ECScalaDSLTest extends AnyWordSpec with Matchers with ECScalaDSL { } } - "myEntity - Component" should { + "myEntity -= myComponent" should { "work the same way as the entity.removeComponent() method" in new WorldFixture with ComponentsFixture { val position = Position(1, 2) val velocity = Velocity(3, 4) val entity1 = world hasAn entity - entity1 + position + entity1 += position world.getComponents[Position] should contain(Map(entity1 -> position)) - entity1 - position + entity1 -= position world.getComponents[Position] shouldBe empty } } - "remove (Component()) from world" should { + "remove (myComponent) from world" should { "work the same way as the entity.removeComponent() method" in new WorldFixture with ComponentsFixture { val position = Position(1, 2) val velocity = Velocity(3, 4) @@ -60,7 +66,17 @@ class ECScalaDSLTest extends AnyWordSpec with Matchers with ECScalaDSL { } } - "remove { Component1() &: Component2() } from world" should { + "remove[Component] from world" should { + "work the same way as the entity.removeComponent() method" in new WorldFixture with ComponentsFixture { + val entity1 = world hasAn entity withComponents { Position(1, 2) &: Velocity(3, 4) } + remove[Position] from entity1 + + world.getComponents[Position] shouldBe empty + world.getComponents[Velocity] should contain(Map(entity1 -> Velocity(3, 4))) + } + } + + "remove { myComponent1 &: myComponent2 } from world" should { "work the same way as multiple entity.removeComponent() method calls" in new WorldFixture with ComponentsFixture { val position = Position(1, 2) val velocity = Velocity(3, 4) @@ -74,10 +90,20 @@ class ECScalaDSLTest extends AnyWordSpec with Matchers with ECScalaDSL { } } - "world - myEntity" should { + "remove[Component1 &: Component2 &: CNil] from world" should { + "work the same way as multiple entity.removeComponent() method calls" in new WorldFixture with ComponentsFixture { + val entity1 = world hasAn entity withComponents { Position(1, 2) &: Velocity(3, 4) } + remove[Position &: Velocity &: CNil] from entity1 + + world.getComponents[Position] shouldBe empty + world.getComponents[Velocity] shouldBe empty + } + } + + "world -= myEntity" should { "work the same way as the world.removeEntity() method" in new WorldFixture { val entity1 = world hasAn entity - world - entity1 + world -= entity1 world.entitiesCount shouldBe 0 } } @@ -100,15 +126,15 @@ class ECScalaDSLTest extends AnyWordSpec with Matchers with ECScalaDSL { "world hasA system[Component &: CNil] { () => {} }" should { "work the same way as the world.addSystem() method" in new ViewFixture { - world hasA system[Position &: CNil]((_, comps, _, _, _) => { + world hasA system[Position &: CNil](IteratingSystem((_, comps, _) => { val Position(px, py) &: CNil = comps Position(px * 2, py * 2) &: CNil - }) + })) - world hasA system[Position &: CNil]((_, comps, _, _, _) => { + world hasA system[Position &: CNil](IteratingSystem((_, comps, _) => { val Position(x, y) &: CNil = comps Position(x + 1, y + 1) &: CNil - }) + })) world.update(10) @@ -121,8 +147,52 @@ class ECScalaDSLTest extends AnyWordSpec with Matchers with ECScalaDSL { } } + def testAddSystem(world: World): Unit = { + val entity1 = world hasAn entity withComponent Position(1, 1) + world.update(10) + world.getView[Position &: CNil] should contain theSameElementsAs List( + (entity1, Position(4, 4) &: CNil), + ) + } + + "world hasA system(mySystem)" should { + "work the same way as the world.addSystem() method" in new SystemFixture with WorldFixture { + world hasA system(mySystem1) + testAddSystem(world) + } + } + + "world += mySystem" should { + "work the same way as the world.addSystem() method" in new SystemFixture with WorldFixture { + world += mySystem1 + testAddSystem(world) + } + } + + def testRemoveSystem(world: World): Unit = { + val entity1 = world hasAn entity withComponent Position(1, 1) + world.update(10) + world.getView[Position &: CNil].toList shouldBe List((entity1, Position(1, 1) &: CNil)) + } + + "remove (mySystem) from world" should { + "work the same way as the world.removeSystem method" in new SystemFixture with WorldFixture { + world hasA system(mySystem2) + remove(mySystem2) from world + testRemoveSystem(world) + } + } + + "world -= mySystem" should { + "work the same way as the world.addSystem() method" in new SystemFixture with WorldFixture { + world hasA system(mySystem2) + world -= mySystem2 + testRemoveSystem(world) + } + } + "getView[Position &: CNil] from world" should { - "work the same way as the world.getView[Position &: CNil] method" in new ViewFixture with WorldFixture { + "work the same way as the world.getView[Position &: CNil] method" in new ViewFixture { val view = getView[Position &: Velocity &: CNil] from world view should contain theSameElementsAs List( @@ -133,12 +203,26 @@ class ECScalaDSLTest extends AnyWordSpec with Matchers with ECScalaDSL { } } - "clearAll from world" should { - "work the same way as the world.clear method" in new WorldFixture { + "geView[Position &: CNil].excluding[Velocity &: CNil] from world" should { + "work the same way as the world.getView[]" in new ViewFixture { + val view = getView[Position &: Velocity &: CNil].excluding[Mass &: CNil] from world + + view should contain theSameElementsAs List( + (entity1, Position(1, 1) &: Velocity(1, 1) &: CNil), + (entity4, Position(1, 1) &: Velocity(1, 1) &: CNil), + ) + + val view2 = getView[Velocity &: CNil].excluding[Position &: CNil] from world + view2 shouldBe empty + } + } + + "clearAllEntities from world" should { + "work the same way as the world.clearEntities method" in new WorldFixture { val entity1 = world hasAn entity withComponent Position(1, 2) val entity2 = world hasAn entity withComponent Position(3, 4) - clearAll from world + clearAllEntities from world world.entitiesCount shouldBe 0 world.getComponents[Position] shouldBe empty diff --git a/core/src/test/scala/dev/atedeg/ecscala/fixtures/ComponentsFixture.scala b/core/src/test/scala/dev/atedeg/ecscala/fixtures/ComponentsFixture.scala index 78fa2593..f675a369 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/fixtures/ComponentsFixture.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/fixtures/ComponentsFixture.scala @@ -1,7 +1,7 @@ package dev.atedeg.ecscala.fixtures import dev.atedeg.ecscala.Component -import dev.atedeg.ecscala.util.immutable.ComponentsContainer +import dev.atedeg.ecscala.util.mutable.ComponentsContainer case class Mass(m: Int) extends Component case class Position(x: Int, y: Int) extends Component diff --git a/core/src/test/scala/dev/atedeg/ecscala/fixtures/SystemBuilderFixture.scala b/core/src/test/scala/dev/atedeg/ecscala/fixtures/SystemBuilderFixture.scala new file mode 100644 index 00000000..0a9a57da --- /dev/null +++ b/core/src/test/scala/dev/atedeg/ecscala/fixtures/SystemBuilderFixture.scala @@ -0,0 +1,11 @@ +package dev.atedeg.ecscala.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.World + +trait SystemBuilderFixture { + val world = World() + val entity = world.createEntity() + entity setComponent Position(1, 1) + entity setComponent Velocity(1, 1) +} diff --git a/core/src/test/scala/dev/atedeg/ecscala/fixtures/SystemFixture.scala b/core/src/test/scala/dev/atedeg/ecscala/fixtures/SystemFixture.scala new file mode 100644 index 00000000..9347cf54 --- /dev/null +++ b/core/src/test/scala/dev/atedeg/ecscala/fixtures/SystemFixture.scala @@ -0,0 +1,18 @@ +package dev.atedeg.ecscala.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, IteratingSystem } +import dev.atedeg.ecscala.dsl.ECScalaDSL + +trait SystemFixture extends ECScalaDSL { + + val mySystem1 = IteratingSystem[Position &: CNil] { (_, comps, _) => + val Position(x, y) &: CNil = comps + Position(x + 3, y + 3) &: CNil + } + + val mySystem2 = IteratingSystem[Position &: CNil] { (_, comps, _) => + val Position(x, y) &: CNil = comps + Position(x + 1, y + 1) &: CNil + } +} diff --git a/core/src/test/scala/dev/atedeg/ecscala/fixtures/ViewFixture.scala b/core/src/test/scala/dev/atedeg/ecscala/fixtures/ViewFixture.scala index d4f3bf51..4dfac22f 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/fixtures/ViewFixture.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/fixtures/ViewFixture.scala @@ -1,7 +1,7 @@ package dev.atedeg.ecscala.fixtures -import dev.atedeg.ecscala.util.types.given -import dev.atedeg.ecscala.fixtures.* +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.fixtures.{ Mass, Position, Velocity } trait ViewFixture extends ComponentsFixture with WorldFixture { val entity1 = world.createEntity() @@ -10,18 +10,18 @@ trait ViewFixture extends ComponentsFixture with WorldFixture { val entity4 = world.createEntity() val entity5 = world.createEntity() - entity1.addComponent(Position(1, 1)) - entity1.addComponent(Velocity(1, 1)) + entity1 setComponent Position(1, 1) + entity1 setComponent Velocity(1, 1) - entity2.addComponent(Mass(1)) + entity2 setComponent Mass(1) - entity3.addComponent(Position(1, 1)) - entity3.addComponent(Velocity(1, 1)) - entity3.addComponent(Mass(1)) + entity3 setComponent Position(1, 1) + entity3 setComponent Velocity(1, 1) + entity3 setComponent Mass(1) - entity4.addComponent(Position(1, 1)) - entity4.addComponent(Velocity(1, 1)) + entity4 setComponent Position(1, 1) + entity4 setComponent Velocity(1, 1) - entity5.addComponent(Position(1, 1)) - entity5.addComponent(Mass(1)) + entity5 setComponent Position(1, 1) + entity5 setComponent Mass(1) } diff --git a/core/src/test/scala/dev/atedeg/ecscala/fixtures/WorldFixture.scala b/core/src/test/scala/dev/atedeg/ecscala/fixtures/WorldFixture.scala index 936a3349..d3a535bf 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/fixtures/WorldFixture.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/fixtures/WorldFixture.scala @@ -3,5 +3,5 @@ package dev.atedeg.ecscala.fixtures import dev.atedeg.ecscala.World trait WorldFixture { - lazy val world: World = World() + val world: World = World() } diff --git a/core/src/test/scala/dev/atedeg/ecscala/util/BaseMapTest.scala b/core/src/test/scala/dev/atedeg/ecscala/util/BaseMapTest.scala deleted file mode 100644 index 8badfd5f..00000000 --- a/core/src/test/scala/dev/atedeg/ecscala/util/BaseMapTest.scala +++ /dev/null @@ -1,96 +0,0 @@ -package dev.atedeg.ecscala.util - -import org.scalatest.matchers.should.* -import org.scalatest.wordspec.AnyWordSpec - -import scala.collection.{ Map, MapFactory } - -abstract class BaseMapTest[CC[K, V] <: Map[K, V]] extends AnyWordSpec with Matchers { - - def name: String - def mapFactory(): MapFactory[CC] - def add[K, V](map: CC[K, V], elem: (K, V)): CC[K, V] - def remove[K, V](map: CC[K, V], key: K): CC[K, V] - - s"$name" when { - "empty" should { - "have size 0" in { - mapFactory().empty.size shouldBe 0 - } - "have size 1" when { - "adding an element" in { - var map: CC[String, Int] = mapFactory().empty - map = add(map, "test" -> 1) - map.size shouldBe 1 - } - } - } - "has 1 element" should { - "have size 0" when { - "removing an element" in { - var map: CC[String, Int] = mapFactory()("test" -> 1) - map = remove(map, "test") - map.size shouldBe 0 - } - } - "have size 1" when { - "removing a non-existing element" in { - var map: CC[String, Int] = mapFactory()("key" -> 1) - map = remove(map, "test") - map.size shouldBe 1 - } - "updating an element" in { - var map: CC[String, Int] = mapFactory()("key" -> 1) - map = add(map, "key" -> 2) - map.size shouldBe 1 - map get "key" shouldBe Some(2) - } - } - } - "has 100 elements" should { - trait Fixture { - val map: CC[Int, Int] = mapFactory().from((0 until 100) map { i => (i, 2 * i) }) - } - "find an existing element" in new Fixture { - map get 50 shouldBe Some(100) - } - "return None for a non-existing element" in new Fixture { - map get 1000 shouldBe None - } - "return the correct element" when { - "deleting the last one" in new Fixture { - val removed = remove(map, 99) - removed get 99 shouldBe None - } - "deleting the middle one" in new Fixture { - val removed = remove(map, 50) - removed get 50 shouldBe None - removed get 99 shouldBe Some(198) - } - } - "return all the keys" in new Fixture { - map.keys should contain theSameElementsAs (0 until 100) - map.keysIterator.to(LazyList) should contain theSameElementsAs (0 until 100).iterator.to(LazyList) - } - "return a set with all the keys" in new Fixture { - map.keySet should contain theSameElementsAs (0 until 100) - } - "return all the values" in new Fixture { - map.values should contain theSameElementsAs (0 until 200 by 2) - map.valuesIterator.to(LazyList) should contain theSameElementsAs (0 until 200 by 2).iterator.to(LazyList) - } - } - } - - s"$name builder" should { - "create an iterable map" in { - val builder = mapFactory().newBuilder[String, Int] - builder += ("test1" -> 1) - builder += ("test2" -> 2) - builder += ("test3" -> 3) - builder.result shouldBe mapFactory()("test1" -> 1, "test2" -> 2, "test3" -> 3) - builder.clear() - builder.result shouldBe mapFactory().empty - } - } -} diff --git a/core/src/test/scala/dev/atedeg/ecscala/util/immutable/IterableMapTest.scala b/core/src/test/scala/dev/atedeg/ecscala/util/immutable/IterableMapTest.scala deleted file mode 100644 index e37b86a2..00000000 --- a/core/src/test/scala/dev/atedeg/ecscala/util/immutable/IterableMapTest.scala +++ /dev/null @@ -1,16 +0,0 @@ -package dev.atedeg.ecscala.util.immutable - -import dev.atedeg.ecscala.util.BaseMapTest - -import scala.collection.{ Map, MapFactory } - -class IterableMapTest extends BaseMapTest[IterableMap] { - - override def name: String = "An immutable iterable map" - - override def mapFactory(): MapFactory[IterableMap] = IterableMap - - override def add[K, V](map: IterableMap[K, V], elem: (K, V)): IterableMap[K, V] = map + elem - - override def remove[K, V](map: IterableMap[K, V], key: K): IterableMap[K, V] = map - key -} diff --git a/core/src/test/scala/dev/atedeg/ecscala/ComponentsContainerTest.scala b/core/src/test/scala/dev/atedeg/ecscala/util/mutable/ComponentsContainerTest.scala similarity index 96% rename from core/src/test/scala/dev/atedeg/ecscala/ComponentsContainerTest.scala rename to core/src/test/scala/dev/atedeg/ecscala/util/mutable/ComponentsContainerTest.scala index b7b717fa..0aaad507 100644 --- a/core/src/test/scala/dev/atedeg/ecscala/ComponentsContainerTest.scala +++ b/core/src/test/scala/dev/atedeg/ecscala/util/mutable/ComponentsContainerTest.scala @@ -1,11 +1,9 @@ -package dev.atedeg.ecscala +package dev.atedeg.ecscala.util.mutable -import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Position, Velocity, WorldFixture } -import dev.atedeg.ecscala.util.types.ComponentTag -import dev.atedeg.ecscala.util.types.given ComponentTag[_] -import dev.atedeg.ecscala.util.immutable.ComponentsContainer import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.fixtures.{ ComponentsFixture, Position, Velocity, WorldFixture } class ComponentsContainerTest extends AnyWordSpec with Matchers { diff --git a/core/src/test/scala/dev/atedeg/ecscala/util/mutable/IterableMapTest.scala b/core/src/test/scala/dev/atedeg/ecscala/util/mutable/IterableMapTest.scala deleted file mode 100644 index 0ade77a3..00000000 --- a/core/src/test/scala/dev/atedeg/ecscala/util/mutable/IterableMapTest.scala +++ /dev/null @@ -1,23 +0,0 @@ -package dev.atedeg.ecscala.util.mutable - -import dev.atedeg.ecscala.util.BaseMapTest - -import scala.collection.MapFactory -import scala.collection.{ Map, MapFactory } - -class IterableMapTest extends BaseMapTest[IterableMap] { - - override def name: String = "A mutable iterable map" - - override def mapFactory(): MapFactory[IterableMap] = IterableMap - - override def add[K, V](map: IterableMap[K, V], elem: (K, V)): IterableMap[K, V] = { - map += elem - map - } - - override def remove[K, V](map: IterableMap[K, V], key: K): IterableMap[K, V] = { - map -= key - map - } -} diff --git a/demo/src/main/resources/MainView.fxml b/demo/src/main/resources/MainView.fxml index f0054a78..10a440f5 100644 --- a/demo/src/main/resources/MainView.fxml +++ b/demo/src/main/resources/MainView.fxml @@ -5,34 +5,59 @@ - - - + + + + + + + + + + - - - - - - - - - - - \ No newline at end of file + + + + + + + + + diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/Components.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/Components.scala index 83efb491..e6d5342d 100644 --- a/demo/src/main/scala/dev/atedeg/ecscalademo/Components.scala +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/Components.scala @@ -1,6 +1,7 @@ package dev.atedeg.ecscalademo import dev.atedeg.ecscala.Component +import dev.atedeg.ecscalademo.{ Point, Vector } case class Color(r: Int, g: Int, b: Int) { require(r >= 0 && r <= 255) @@ -8,7 +9,27 @@ case class Color(r: Int, g: Int, b: Int) { require(b >= 0 && b <= 255) } -case class Position(position: Point) extends Component -case class Velocity(velocity: Vector) extends Component +case class Position(position: Point) extends Component { + def x: Double = position.x + def y: Double = position.y +} + +object Position { + def apply(x: Double, y: Double): Position = Position(Point(x, y)) +} + +given Conversion[Position, Point] = _.position + +case class Velocity(velocity: Vector) extends Component { + def x: Double = velocity.x + def y: Double = velocity.y +} + +object Velocity { + def apply(x: Double, y: Double): Velocity = Velocity(Vector(x, y)) +} + +given Conversion[Velocity, Vector] = _.velocity + case class Circle(radius: Double, color: Color) extends Component case class Mass(mass: Double) extends Component diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/ECSCanvas.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/ECSCanvas.scala index cd9916ae..2e749090 100644 --- a/demo/src/main/scala/dev/atedeg/ecscalademo/ECSCanvas.scala +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/ECSCanvas.scala @@ -1,40 +1,89 @@ -package dev.atedeg.ecscalademo - -import scalafx.scene.paint.Color -import scalafx.scene.shape.ArcType -import scalafx.scene.canvas.{ Canvas, GraphicsContext } - -trait ECSCanvas { - def drawCircle(coordinates: Point, radius: Double, color: Color, lineWidth: Double): Unit - def drawLine(from: Point, to: Point, color: Color, lineWidth: Double): Unit - def clear(): Unit -} - -object ScalaFXCanvas { - def apply(canvas: Canvas): ECSCanvas = new ScalaFXCanvasImpl(canvas) - - private class ScalaFXCanvasImpl(canvas: Canvas) extends ECSCanvas { - private var graphicsContext: GraphicsContext = canvas.graphicsContext2D - - override def drawCircle(coordinates: Point, radius: Double, color: Color, lineWidth: Double): Unit = { - graphicsContext.beginPath() - graphicsContext.arc(coordinates.x, coordinates.y, radius, radius, 0, 360) - graphicsContext.setFill(color) - graphicsContext.setStroke(Color.Black) - graphicsContext.lineWidth = lineWidth - graphicsContext.fill() - graphicsContext.stroke() - } - - override def drawLine(from: Point, to: Point, color: Color, lineWidth: Double): Unit = { - graphicsContext.beginPath() - graphicsContext.moveTo(from.x, from.y) - graphicsContext.lineTo(to.x, to.y) - graphicsContext.lineWidth = lineWidth - graphicsContext.setStroke(color) - graphicsContext.stroke() - } - - override def clear(): Unit = graphicsContext.clearRect(0, 0, canvas.getWidth, canvas.getHeight) - } -} +package dev.atedeg.ecscalademo + +import scalafx.scene.canvas.{ Canvas, GraphicsContext } +import scalafx.scene.paint.Color as ColorFx +import dev.atedeg.ecscalademo.Color + +/** + * This trait is an abstraction of a Canvas that can be used to draw the demo components. + */ +trait ECSCanvas { + + /** + * @param coordinates + * The point where to draw the ball. + * @param radius + * The ball radius. + * @param color + * The ball color. + * @param lineWidth + * The thickness of the ball's border. + */ + def drawCircle(coordinates: Point, radius: Double, color: Color, lineWidth: Double): Unit + + /** + * @param from + * The starting point of the line. + * @param to + * The end point of the line. + * @param color + * The line color. + * @param lineWidth + */ + def drawLine(from: Point, to: Point, color: Color, lineWidth: Double): Unit + + /** + * Remove all the elements from the Canvas. + */ + def clear(): Unit + + /** + * @return + * the width of the canvas. + */ + def width: Double + + /** + * @return + * the height of the canvas. + */ + def height: Double +} + +/** + * Object that uses the ScalaFX Canvas to draw the elements. + */ +object ScalaFXCanvas { + def apply(canvas: Canvas): ECSCanvas = new ScalaFXCanvasImpl(canvas) + + private class ScalaFXCanvasImpl(canvas: Canvas) extends ECSCanvas { + private val graphicsContext: GraphicsContext = canvas.graphicsContext2D + private val defaultCanvasWidth = 760.0 + private val defaultCanvasHeight = 467.0 + + override def drawCircle(coordinates: Point, radius: Double, color: Color, lineWidth: Double): Unit = { + graphicsContext.beginPath() + graphicsContext.arc(coordinates.x, coordinates.y, radius, radius, 0, 360) + graphicsContext.setFill(ColorFx.rgb(color.r, color.g, color.b)) + graphicsContext.setStroke(ColorFx.Black) + graphicsContext.lineWidth = lineWidth + graphicsContext.fill() + graphicsContext.stroke() + } + + override def drawLine(from: Point, to: Point, color: Color, lineWidth: Double): Unit = { + graphicsContext.beginPath() + graphicsContext.moveTo(from.x, from.y) + graphicsContext.lineTo(to.x, to.y) + graphicsContext.lineWidth = lineWidth + graphicsContext.setStroke(ColorFx.rgb(color.r, color.g, color.b)) + graphicsContext.stroke() + } + + override def clear(): Unit = graphicsContext.clearRect(0, 0, canvas.getWidth, canvas.getHeight) + + override def width: Double = if canvas.getWidth == 0.0 then defaultCanvasWidth else canvas.getWidth + + override def height: Double = if canvas.getHeight == 0.0 then defaultCanvasHeight else canvas.getHeight + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/ECScalaDemo.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/ECScalaDemo.scala index f059119d..f8d86b52 100644 --- a/demo/src/main/scala/dev/atedeg/ecscalademo/ECScalaDemo.scala +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/ECScalaDemo.scala @@ -2,15 +2,14 @@ package dev.atedeg.ecscalademo import javafx.fxml.FXMLLoader import javafx.scene.Parent -import scalafx.Includes.* import scalafx.application.JFXApp3 import scalafx.application.JFXApp3.PrimaryStage +import scalafx.Includes.* import scalafx.scene.Scene object ECScalaDemo extends JFXApp3 { override def start(): Unit = { - val root: Parent = FXMLLoader.load(getClass.getResource("/MainView.fxml")) stage = new JFXApp3.PrimaryStage() { diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/Math.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/Math.scala index f391958b..7bb405bf 100644 --- a/demo/src/main/scala/dev/atedeg/ecscalademo/Math.scala +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/Math.scala @@ -6,6 +6,14 @@ case class Point(x: Double, y: Double) { def -(point: Point) = Vector(x - point.x, y - point.y) } +extension (point: Point) { + + def isOverlappedWith(otherPoint: Point, thisRadius: Double, otherRadius: Double): Boolean = + (point - otherPoint).squaredNorm < Math.pow(thisRadius + otherRadius, 2) +} + +given Conversion[(Double, Double), Point] = tuple => Point(tuple._1, tuple._2) + case class Vector(x: Double, y: Double) { def +(vector: Vector) = Vector(x + vector.x, y + vector.y) def -(vector: Vector) = Vector(x - vector.x, y - vector.y) @@ -18,12 +26,15 @@ case class Vector(x: Double, y: Double) { def normalized = this / norm } +given Conversion[(Double, Double), Vector] = tuple => Vector(tuple._1, tuple._2) + extension (scalar: Double) { def *(vector: Vector) = vector * scalar } extension [T](element: T)(using ord: Ordering[T]) { - def clamped(lowerBound: T, upperBound: T) = + def clamped(lowerBound: T, upperBound: T): T = if ord.gt(element, upperBound) then upperBound else if ord.lt(element, lowerBound) then lowerBound else element + def clamped(bounds: (T, T)): T = clamped(bounds._1, bounds._2) } diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/SimulationStatus.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/SimulationStatus.scala index 1c0e6b83..997674f8 100644 --- a/demo/src/main/scala/dev/atedeg/ecscalademo/SimulationStatus.scala +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/SimulationStatus.scala @@ -1,13 +1,77 @@ package dev.atedeg.ecscalademo -object MouseState { - var coordinates = Point(0, 0) - var clicked = false - var down = false - var up = false +import scalafx.beans.property.DoubleProperty +import dev.atedeg.ecscala.Entity + +enum State { + case Pause, Play, AddBalls, SelectBall, ChangeVelocity, Dragging +} + +case class MouseState( + var coordinates: Point = Point(0, 0), + var clicked: Boolean = false, + var down: Boolean = false, + var up: Boolean = false, +) + +case class PlayState(var gameState: State = State.Pause, var selectedBall: Option[Entity] = None) + +trait StartingState { + val startingRadius: Double = 20.0 + val startingColor: Color = Color(255, 255, 0) + val startingMass: Double = 1 + val startingVelocity: Vector = Vector(0.0, 0.0) + val startingPosition: Seq[Position] + + val startingVelocities = List( + Velocity(1000, 0), + Velocity(0, 0), + Velocity(0, 0), + Velocity(0, 0), + Velocity(0, 0), + Velocity(0, 0), + Velocity(0, 0), + ) + + val startingColors = List( + Color(255, 255, 255), + Color(255, 215, 0), + Color(0, 0, 255), + Color(255, 0, 0), + Color(75, 0, 130), + Color(255, 69, 0), + Color(34, 139, 34), + ) } -object PlayState { - var playing = false - var selectedBall = Option.empty +object StartingState { + + def apply(canvas: ECSCanvas): StartingState = new StartingState { + + override val startingPosition = Seq( + Position(canvas.width / 3, canvas.height / 2), + Position(0.66 * canvas.width, canvas.height / 2), + Position(0.66 * canvas.width, canvas.height / 2 - (2 * startingRadius + 4)), + Position(0.66 * canvas.width, canvas.height / 2 + (2 * startingRadius + 4)), + Position(0.66 * canvas.width - 2 * startingRadius, canvas.height / 2 - (startingRadius + 2)), + Position(0.66 * canvas.width - 2 * startingRadius, canvas.height / 2 + (startingRadius + 2)), + Position(0.66 * canvas.width - 4 * startingRadius, canvas.height / 2), + ) + } +} + +trait EnvironmentState { + def frictionCoefficient: Double + def wallRestitution: Double + val gravity: Double = 9.81 +} + +object EnvironmentState { + + def apply(frictionCoefficentProperty: DoubleProperty, wallRestitutionProperty: DoubleProperty): EnvironmentState = + new EnvironmentState { + override def frictionCoefficient: Double = frictionCoefficentProperty.value + + override def wallRestitution: Double = wallRestitutionProperty.value + } } diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/controller/GameLoop.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/controller/GameLoop.scala index 8b8dc9f2..c0f76db2 100644 --- a/demo/src/main/scala/dev/atedeg/ecscalademo/controller/GameLoop.scala +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/controller/GameLoop.scala @@ -1,7 +1,6 @@ package dev.atedeg.ecscalademo.controller import javafx.animation.AnimationTimer as JfxAnimationTimer -import scalafx.animation.AnimationTimer import scalafx.beans.property.IntegerProperty trait GameLoop { @@ -11,16 +10,16 @@ trait GameLoop { } object GameLoop { - def apply(handler: Long => Unit): GameLoop = GameLoopImpl(handler) + def apply(handler: Double => Unit): GameLoop = GameLoopImpl(handler) - private class GameLoopImpl(handler: Long => Unit) extends GameLoop { + private class GameLoopImpl(handler: Double => Unit) extends GameLoop { private val animationTimer = new JfxAnimationTimer() { private var prevFrameTime = 0L private var count = 0 override def handle(now: Long): Unit = { - val delta = now - prevFrameTime + val delta = (now - prevFrameTime) / 1e9 count += 1 if (count >= 20) { fpsCount(delta) @@ -30,8 +29,8 @@ object GameLoop { prevFrameTime = now } - private def fpsCount(delta: Long): Int = { - val currentFps = (1e9 / delta).toInt + private def fpsCount(delta: Double): Int = { + val currentFps = (1 / delta).toInt fps.value = currentFps currentFps } diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/controller/MainViewController.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/controller/MainViewController.scala index 33c1484e..366459a7 100644 --- a/demo/src/main/scala/dev/atedeg/ecscalademo/controller/MainViewController.scala +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/controller/MainViewController.scala @@ -1,94 +1,270 @@ package dev.atedeg.ecscalademo.controller -import dev.atedeg.ecscala.World -import dev.atedeg.ecscalademo.{ECSCanvas, MouseState, PlayState, Point, ScalaFXCanvas} -import javafx.fxml.{FXML, Initializable} -import javafx.scene.control.Label as JfxLabel -import javafx.scene.control.Button as JfxButton -import javafx.scene.layout as jfx -import javafx.scene.canvas.Canvas as JfxCanvas -import javafx.scene.layout.Pane as JfxPane -import scalafx.scene.control.{Button, Label} -import scalafx.scene.canvas.{Canvas, GraphicsContext} -import scalafx.scene.paint.Color -import scalafx.scene.layout.Pane -import javafx.scene.input.MouseEvent -import scalafx.animation.AnimationTimer -import scalafx.util.converter.NumberStringConverter - import java.net.URL +import java.text.DecimalFormat import java.util.ResourceBundle import scala.language.postfixOps +import javafx.fxml.{ FXML, Initializable } +import javafx.scene.canvas.Canvas as JfxCanvas +import javafx.scene.control.{ Button as JfxButton, Label as JfxLabel, Slider as JfxSlider } +import javafx.scene.input.MouseEvent +import scalafx.beans.property.DoubleProperty +import scalafx.scene.canvas.Canvas +import scalafx.scene.control.{ Button, Label, Slider } +import scalafx.util.converter.NumberStringConverter +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, World } +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ + Circle, + Color, + ECSCanvas, + EnvironmentState, + Mass, + MouseState, + PlayState, + Point, + Position, + ScalaFXCanvas, + StartingState, + State, + Velocity, +} +import dev.atedeg.ecscalademo.systems.* +import dev.atedeg.ecscalademo.util.WritableSpacePartitionContainer -class MainViewController extends Initializable { +class MainViewController extends Initializable with ECScalaDSL { @FXML private var playPauseBtnDelegate: JfxButton = _ - private var playPauseBtn: Button = _ - - @FXML - private var addBallBtn: Button = _ + private lazy val playPauseBtn: Button = new Button(playPauseBtnDelegate) @FXML - private var selectBallBtn: Button = _ + private var addBallBtnDelegate: JfxButton = _ + private lazy val addBallBtn: Button = new Button(addBallBtnDelegate) @FXML - private var moveBtn: Button = _ + private var changeVelBtnDelegate: JfxButton = _ + private lazy val changeVelBtn: Button = new Button(changeVelBtnDelegate) @FXML - private var changeVelBtn: Button = _ + private var resetBtnDelegate: JfxButton = _ + private lazy val resetBtn = new Button(resetBtnDelegate) @FXML private var canvasDelegate: JfxCanvas = _ - private var canvas: Canvas = _ + private lazy val canvas: Canvas = new Canvas(canvasDelegate) @FXML private var fpsDelegate: JfxLabel = _ - private var fps: Label = _ + private lazy val fps: Label = new Label(fpsDelegate) + @FXML + private var wallRestitutionSliderDelegate: JfxSlider = _ + private lazy val wallRestitutionSlider = new Slider(wallRestitutionSliderDelegate) + + @FXML + private var frictionCoefficientSliderDelegate: JfxSlider = _ + private lazy val frictionCoefficientSlider = new Slider(frictionCoefficientSliderDelegate) + + @FXML + private var wallRestitutionLabelDelegate: JfxLabel = _ + private lazy val wallRestitutionLabel = new Label(wallRestitutionLabelDelegate) + + @FXML + private var frictionCoefficientLabelDelegate: JfxLabel = _ + private lazy val frictionCoefficientLabel = new Label(frictionCoefficientLabelDelegate) + + private lazy val ecsCanvas = ScalaFXCanvas(canvas) private val world: World = World() private var loop: GameLoop = _ + private val mouseState: MouseState = MouseState() + val playState: PlayState = PlayState() + private var environmentState: EnvironmentState = _ + private var startingState: StartingState = _ private var isRunning = false + private val addBallButtonLabel = "Add Ball" + private val stopAddingButtonLabel = "Stop Adding" + override def initialize(url: URL, resourceBundle: ResourceBundle): Unit = { - loop = GameLoop(f => { - world.update(f.toFloat) + startingState = StartingState(ecsCanvas) + val frictionCoefficentProperty = DoubleProperty(0.05) + val wallRestitutionProperty = DoubleProperty(0.5) + environmentState = EnvironmentState(frictionCoefficentProperty, wallRestitutionProperty) + + canvas.widthProperty().addListener(e => startingState = StartingState(ecsCanvas)) + canvas.heightProperty().addListener(e => startingState = StartingState(ecsCanvas)) + + createEntitiesWithComponents() + addSystemsToWorld() + + loop = GameLoop(dt => { + world.update(dt) + mouseState.down = false + mouseState.up = false + refreshUiElements() }) - playPauseBtn = new Button(playPauseBtnDelegate) - canvas = new Canvas(canvasDelegate) - fps = new Label(fpsDelegate) fps.text.bindBidirectional(loop.fps, new NumberStringConverter("FPS: ")) + frictionCoefficentProperty <== frictionCoefficientSlider.value + wallRestitutionProperty <== wallRestitutionSlider.value + val decimalFormat = new DecimalFormat() + decimalFormat.setMaximumFractionDigits(2) + decimalFormat.setMinimumFractionDigits(2) + frictionCoefficientLabel.text + .bindBidirectional(frictionCoefficientSlider.value, new NumberStringConverter(decimalFormat)) + wallRestitutionLabel.text.bindBidirectional(wallRestitutionSlider.value, new NumberStringConverter(decimalFormat)) - ScalaFXCanvas(canvas) + loop.start } - def onMouseMovedHandler(event: MouseEvent): Unit = { - MouseState.coordinates = Point(event.getX, event.getY) + private def refreshUiElements(): Unit = { + playState.gameState match { + case State.Play => { + isRunning = true + playPauseBtn.text = "Pause" + addBallBtn.text = addBallButtonLabel + frictionCoefficientSlider.disable = true + wallRestitutionSlider.disable = true + playState.selectedBall = None + setButtonState( + isPlayPauseDisable = false, + isAddBallDiasable = true, + isChangeVelDisable = true, + isResetDisable = true, + ) + } + case State.Pause => { + isRunning = false + playPauseBtn.text = "Play" + addBallBtn.text = addBallButtonLabel + frictionCoefficientSlider.disable = false + wallRestitutionSlider.disable = false + setButtonState( + isPlayPauseDisable = false, + isAddBallDiasable = false, + isChangeVelDisable = true, + isResetDisable = false, + ) + } + case State.AddBalls => { + addBallBtn.text = stopAddingButtonLabel + playState.selectedBall = None + setButtonState( + isPlayPauseDisable = false, + isAddBallDiasable = false, + isChangeVelDisable = true, + isResetDisable = false, + ) + } + case State.ChangeVelocity => { + setButtonState( + isPlayPauseDisable = false, + isAddBallDiasable = true, + isChangeVelDisable = false, + isResetDisable = false, + ) + } + case State.Dragging => { + setButtonState( + isPlayPauseDisable = true, + isAddBallDiasable = true, + isChangeVelDisable = true, + isResetDisable = true, + ) + } + case State.SelectBall => { + setButtonState( + isPlayPauseDisable = false, + isAddBallDiasable = false, + isChangeVelDisable = false, + isResetDisable = false, + ) + } + } } + private def setButtonState( + isPlayPauseDisable: Boolean, + isAddBallDiasable: Boolean, + isChangeVelDisable: Boolean, + isResetDisable: Boolean, + ): Unit = { + playPauseBtn.disable = isPlayPauseDisable + addBallBtn.disable = isAddBallDiasable + changeVelBtn.disable = isChangeVelDisable + resetBtn.disable = isResetDisable + } + + def onMouseMovedHandler(event: MouseEvent): Unit = mouseState.coordinates = Point(event.getX, event.getY) + def onMousePressedHandler(event: MouseEvent): Unit = { - MouseState.down = true - MouseState.clicked = true + mouseState.down = true + mouseState.clicked = true } def onMouseReleasedHandler(event: MouseEvent): Unit = { - MouseState.up = true - MouseState.clicked = false + mouseState.up = true + mouseState.clicked = false + playState.gameState = if playState.gameState == State.Dragging then State.SelectBall else playState.gameState + } + + def onDragDetectedHandler(event: MouseEvent): Unit = { + mouseState.coordinates = Point(event.getX, event.getY) + playState.gameState = if playState.gameState == State.SelectBall then State.Dragging else playState.gameState } def onPlayPauseClickHandler(): Unit = { - if (isRunning) { - PlayState.playing = false - isRunning = false - playPauseBtn.text = "Play" - loop.stop - } else { - PlayState.playing = true - isRunning = true - playPauseBtn.text = "Pause" - loop.start + isRunning = !isRunning + playState.gameState = if isRunning then State.Play else State.Pause + } + + def onAddBallButtonHandler(): Unit = playState.gameState = + if playState.gameState == State.AddBalls then State.Pause else State.AddBalls + + def onChangeVelocityButtonHandler(): Unit = playState.gameState = + if playState.gameState == State.SelectBall then State.ChangeVelocity else State.Pause + + def onResetClickHandler(): Unit = { + playState.gameState match { + case State.Play | State.Dragging => () + case _ => { + playState.selectedBall = None + playState.gameState = State.Pause + clearAllEntities from world + createEntitiesWithComponents() + } } } + + private def createEntitiesWithComponents() = { + import dev.atedeg.ecscalademo.StartingState.* + import dev.atedeg.ecscalademo.EnvironmentState.* + for { + ((position, color), velocity) <- + startingState.startingPosition zip startingState.startingColors zip startingState.startingVelocities + } world hasAn entity withComponents { + Circle(startingState.startingRadius, color) &: position &: velocity &: Mass(startingState.startingMass) + } + } + + private def addSystemsToWorld() = { + val container = WritableSpacePartitionContainer() + world hasA system(ClearCanvasSystem(ecsCanvas)) + world hasA system(BallCreationSystem(playState, mouseState, startingState)) + world hasA system(BallCreationRenderingSystem(playState, mouseState, startingState, ecsCanvas)) + world hasA system(VelocityEditingSystem(playState, mouseState)) + world hasA system(VelocityArrowSystem(playState, mouseState, ecsCanvas)) + world hasA system(BallSelectionSystem(playState, mouseState)) + world hasA system(DragBallSystem(playState, mouseState)) + world hasA system(FrictionSystem(playState, environmentState)) + world hasA system(MovementSystem(playState)) + world hasA system(RegionAssignmentSystem(playState, container)) + world hasA system(CollisionSystem(playState, container)) + world hasA system(WallCollisionSystem(playState, environmentState, ecsCanvas)) + world hasA system(RenderSystem(playState, ecsCanvas)) + world hasA system(AutoPauseSystem(playState)) + } } diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/AutoPauseSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/AutoPauseSystem.scala new file mode 100644 index 00000000..bdd36d6a --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/AutoPauseSystem.scala @@ -0,0 +1,26 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, Deletable, DeltaTime, Entity, IteratingSystem, View, World } +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ PlayState, State, Vector, Velocity } + +/** + * Pause the simulation when the system's energy is zero (all the balls have velocity = 0). + */ +class AutoPauseSystem(private val playState: PlayState) extends IteratingSystem[Velocity &: CNil] { + private val epsilon = 0.001 + + override def shouldRun: Boolean = playState.gameState == State.Play + + override def update( + entity: Entity, + components: Velocity &: CNil, + )(deltaTime: DeltaTime, world: World, view: View[Velocity &: CNil]): Deletable[Velocity &: CNil] = { + val systemEnergy = view.map(_._2.h).foldLeft(0.0)(_ + _.velocity.squaredNorm) + if (systemEnergy <= epsilon) { + playState.gameState = State.Pause + } + components + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallCreationRenderingSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallCreationRenderingSystem.scala new file mode 100644 index 00000000..317ff8f2 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallCreationRenderingSystem.scala @@ -0,0 +1,24 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ DeltaTime, System, World } +import dev.atedeg.ecscalademo.{ ECSCanvas, MouseState, PlayState, StartingState, State } + +/** + * This [[System]] is used to render the ball that is about to be added to the [[World]]. + * @param canvas + * the canvas to draw in. + */ +class BallCreationRenderingSystem( + private val playState: PlayState, + private val mouseState: MouseState, + private val startingState: StartingState, + private val canvas: ECSCanvas, +) extends System { + + override def shouldRun: Boolean = playState.gameState == State.AddBalls + + override def update(deltaTime: DeltaTime, world: World): Unit = { + canvas.drawCircle(mouseState.coordinates, startingState.startingRadius, startingState.startingColor, 1) + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallCreationSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallCreationSystem.scala new file mode 100644 index 00000000..9514d253 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallCreationSystem.scala @@ -0,0 +1,45 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, DeltaTime, System, World } +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ + isOverlappedWith, + Circle, + Mass, + MouseState, + PlayState, + Position, + StartingState, + State, + Velocity, +} + +/** + * This [[System]] is used to add a new ball into the [[World]]. If the mouse pointer is in the area of another ball, no + * ball will be added. + */ +class BallCreationSystem( + private val playState: PlayState, + private val mouseState: MouseState, + private val startingState: StartingState, +) extends System + with ECScalaDSL { + + override def shouldRun: Boolean = mouseState.clicked && playState.gameState == State.AddBalls + + override def update(deltaTime: DeltaTime, world: World): Unit = { + val canBeCreated = world.getView[Position &: Circle &: CNil] map (_._2) forall { cl => + val Position(point) &: Circle(radius, _) &: CNil = cl + !point.isOverlappedWith(mouseState.coordinates, radius, startingState.startingRadius) + } + if (canBeCreated) { + world hasAn entity withComponents { + Position(mouseState.coordinates) &: + Circle(startingState.startingRadius, startingState.startingColor) &: + Velocity(startingState.startingVelocity) &: + Mass(startingState.startingMass) + } + } + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallSelectionSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallSelectionSystem.scala new file mode 100644 index 00000000..07a7d8a2 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/BallSelectionSystem.scala @@ -0,0 +1,30 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, DeltaTime, Entity, System, World } +import dev.atedeg.ecscalademo.{ isOverlappedWith, Circle, MouseState, PlayState, Position, State } + +/** + * This [[System]] is used to identify the selected ball. If a ball were selected, the [[PlayState.selectedBall]] + * contains the [[Entity]] associated to the selected ball. + */ +class BallSelectionSystem(private val playState: PlayState, private val mouseState: MouseState) extends System { + + override def shouldRun: Boolean = + (playState.gameState == State.Pause || playState.gameState == State.SelectBall) && mouseState.down + + override def update(deltaTime: DeltaTime, world: World): Unit = { + val selectedEntity: Option[Entity] = world.getView[Position &: Circle &: CNil] find { e => + val Position(point) &: Circle(radius, _) &: CNil = e._2 + mouseState.coordinates.isOverlappedWith(point, 0, radius) + } map (_._1) + + if (selectedEntity.isEmpty) { + playState.selectedBall = None + playState.gameState = State.Pause + } else { + playState.selectedBall = Some(selectedEntity.get) + playState.gameState = State.SelectBall + } + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/ClearCanvasSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/ClearCanvasSystem.scala new file mode 100644 index 00000000..83d54928 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/ClearCanvasSystem.scala @@ -0,0 +1,8 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.{ DeltaTime, System, World } +import dev.atedeg.ecscalademo.ECSCanvas + +class ClearCanvasSystem(private val ecsCanvas: ECSCanvas) extends System { + override def update(deltaTime: DeltaTime, world: World): Unit = ecsCanvas.clear() +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/CollisionSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/CollisionSystem.scala new file mode 100644 index 00000000..562149a9 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/CollisionSystem.scala @@ -0,0 +1,95 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ DeltaTime, Entity, System, World } +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ Circle, Mass, PlayState, Point, Position, State, Vector, Velocity } +import dev.atedeg.ecscalademo.util.SpacePartitionContainer + +class CollisionSystem(private val playState: PlayState, private val regions: SpacePartitionContainer) extends System { + override def shouldRun: Boolean = playState.gameState == State.Play + + override def update(deltaTime: DeltaTime, world: World): Unit = { + for { + region <- regions.regionsIterator + candidateColliders <- combinations2(entitiesInNeighborRegions(region)) + } { + val (candidateAEntity, candidateBEntity) = candidateColliders + // We are sure we have those components because we checked for them when adding these entities to the space partition container + var positionA = candidateAEntity.getComponent[Position].get + val velocityA = candidateAEntity.getComponent[Velocity].get + val circleA = candidateAEntity.getComponent[Circle].get + val massA = candidateAEntity.getComponent[Mass].get + var positionB = candidateBEntity.getComponent[Position].get + val velocityB = candidateBEntity.getComponent[Velocity].get + val circleB = candidateBEntity.getComponent[Circle].get + val massB = candidateBEntity.getComponent[Mass].get + if (isColliding((positionA, positionB), (circleA.radius, circleB.radius))) { + if (isStuck((positionA, positionB), (circleA.radius, circleB.radius))) { + val (newPositionA, newPositionB) = unstuck((positionA, positionB), (circleA.radius, circleB.radius)) + candidateAEntity setComponent newPositionA + candidateBEntity setComponent newPositionB + // Update the positions for correctly calculating the collision velocities + positionA = newPositionA + positionB = newPositionB + } + val (newVelocityA, newVelocityB) = + newVelocities((positionA, positionB), (velocityA, velocityB), (circleA.radius, circleB.radius)) + candidateAEntity setComponent newVelocityA + candidateBEntity setComponent newVelocityB + } + } + } + + private def getComponents(entity: Entity): (Position, Velocity, Circle, Mass) = + ( + entity.getComponent[Position].get, + entity.getComponent[Velocity].get, + entity.getComponent[Circle].get, + entity.getComponent[Mass].get, + ) + + private def isColliding(positions: (Point, Point), radii: (Double, Double)) = + compareDistances(positions, radii)(_ <= _) + + private def isStuck(positions: (Point, Point), radii: (Double, Double)) = + compareDistances(positions, radii)(_ - _ < 0.001) + + private def compareDistances(positions: (Point, Point), radii: (Double, Double))( + comparer: (Double, Double) => Boolean, + ) = comparer((positions._1 - positions._2).norm, math.pow(radii._1 + radii._2, 1)) + + private def unstuck(positions: (Point, Point), radii: (Double, Double)) = { + val distanceVector = positions._1 - positions._2 + val distanceDirection = distanceVector.normalized + val moveFactor = radii._1 + radii._2 - distanceVector.norm + val deltaPosition = distanceDirection * moveFactor / 2 + (Position(positions._1 + deltaPosition), Position(positions._2 - deltaPosition)) + } + + private def newVelocities(positions: (Point, Point), velocities: (Vector, Vector), masses: (Double, Double)) = { + val (posA, posB) = positions + val (velA, velB) = velocities + val (massA, massB) = masses + val deltaPositions = posA - posB + val deltaVelocities = velA - velB + val projectedVelocity = deltaPositions * (deltaVelocities dot deltaPositions) / deltaPositions.squaredNorm + ( + Velocity(velA - projectedVelocity * (2 * massB / (massA + massB))), + Velocity(velB + projectedVelocity * (2 * massA / (massA + massB))), + ) + } + + private def entitiesInNeighborRegions(region: (Int, Int)): Seq[Entity] = for { + x <- -1 to 0 + y <- -1 to 1 + entity <- regions get (region._1 + x, region._2 + y) if x != 0 || y != 1 + } yield entity + + private def combinations2[T](seq: Seq[T]): Iterator[(T, T)] = + seq.tails flatMap { + case h +: t => t.iterator map ((h, _)) + case Nil => Iterator.empty + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/DragBallSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/DragBallSystem.scala new file mode 100644 index 00000000..c414bb47 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/DragBallSystem.scala @@ -0,0 +1,21 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ DeltaTime, System, World } +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ MouseState, PlayState, Position, State } + +/** + * This [[System]] is used to update the selected ball's [[Position]] according to the mouse pointer. + */ +class DragBallSystem(private val playState: PlayState, private val mouseState: MouseState) extends System { + + override def shouldRun: Boolean = playState.gameState == State.Dragging + + override def update(deltaTime: DeltaTime, world: World): Unit = { + playState.selectedBall match { + case Some(entity) => entity setComponent Position(mouseState.coordinates) + case _ => () + } + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/FrictionSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/FrictionSystem.scala new file mode 100644 index 00000000..4c54c374 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/FrictionSystem.scala @@ -0,0 +1,29 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, Deletable, DeltaTime, Entity, IteratingSystem, View, World } +import dev.atedeg.ecscalademo.{ EnvironmentState, PlayState, State, Velocity } + +/** + * The [[System]] that applies the friction to the balls that have a Velocity. + */ +class FrictionSystem(private val playState: PlayState, private val environmentState: EnvironmentState) + extends IteratingSystem[Velocity &: CNil] { + + override def shouldRun: Boolean = playState.gameState == State.Play + + override def update( + entity: Entity, + components: Velocity &: CNil, + )(deltaTime: DeltaTime, world: World, view: View[Velocity &: CNil]): Deletable[Velocity &: CNil] = { + val Velocity(velocity) &: CNil = components + if (velocity.norm > 0) { + val frictionDirection = velocity.normalized * -1 + val friction = frictionDirection * (environmentState.frictionCoefficient * environmentState.gravity) + val newVelocity = velocity + friction + if (velocity dot newVelocity) < 0 then Velocity(0, 0) &: CNil else Velocity(newVelocity) &: CNil + } else { + components + } + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/MovementSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/MovementSystem.scala new file mode 100644 index 00000000..6ed4648d --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/MovementSystem.scala @@ -0,0 +1,22 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, Deletable, DeltaTime, Entity, IteratingSystem, View, World } +import dev.atedeg.ecscalademo.{ PlayState, Position, State, Velocity } + +/** + * The [[System]] that updates the balls Positions given the updated Velocities + */ +class MovementSystem(private val playState: PlayState) extends IteratingSystem[Position &: Velocity &: CNil] { + override def shouldRun: Boolean = playState.gameState == State.Play + + override def update(entity: Entity, components: Position &: Velocity &: CNil)( + deltaTime: DeltaTime, + world: World, + view: View[Position &: Velocity &: CNil], + ): Deletable[Position &: Velocity &: CNil] = { + val Position(position) &: Velocity(velocity) &: CNil = components + val newPosition = position + (velocity * deltaTime) + Position(newPosition) &: Velocity(velocity) &: CNil + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/RegionAssignmentSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/RegionAssignmentSystem.scala new file mode 100644 index 00000000..06c02d25 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/RegionAssignmentSystem.scala @@ -0,0 +1,42 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, Deletable, DeltaTime, Entity, IteratingSystem, View, World } +import dev.atedeg.ecscalademo.{ Circle, Mass, PlayState, Position, State, Velocity } +import dev.atedeg.ecscalademo.util.WritableSpacePartitionContainer + +/** + * This system populates the [[SpacePartitionContainer]] with all the required entities. This system is to be run before + * any collision system. + * @param regions + * the [[WritableSpacePartitionContainer]] that will be populated. + */ +class RegionAssignmentSystem(private val playState: PlayState, val regions: WritableSpacePartitionContainer) + extends IteratingSystem[Position &: Velocity &: Circle &: Mass &: CNil] { + + override def shouldRun = playState.gameState == State.Play + + override def before( + deltaTime: DeltaTime, + world: World, + view: View[Position &: Velocity &: Circle &: Mass &: CNil], + ): Unit = regions.clear() + + override def update( + entity: Entity, + components: Position &: Velocity &: Circle &: Mass &: CNil, + )( + deltaTime: DeltaTime, + world: World, + view: View[Position &: Velocity &: Circle &: Mass &: CNil], + ): Deletable[Position &: Velocity &: Circle &: Mass &: CNil] = { + regions add (entity, components) + components + } + + override def after( + deltaTime: DeltaTime, + world: World, + view: View[Position &: Velocity &: Circle &: Mass &: CNil], + ): Unit = regions.build() +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/RenderSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/RenderSystem.scala new file mode 100644 index 00000000..37461dda --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/RenderSystem.scala @@ -0,0 +1,28 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, Deletable, DeltaTime, Entity, IteratingSystem, View, World } +import dev.atedeg.ecscalademo.{ Circle, ECSCanvas, PlayState, Position } + +/** + * The [[System]] that renders the balls on their updated Positions. + * @param ecsCanvas + */ +class RenderSystem(private val playState: PlayState, private val ecsCanvas: ECSCanvas) + extends IteratingSystem[Circle &: Position &: CNil] { + private val selectedBallLineWidth = 3 + private val regularBallLineWidth = 1 + + override def update(entity: Entity, components: Circle &: Position &: CNil)( + deltaTime: DeltaTime, + world: World, + view: View[Circle &: Position &: CNil], + ): Deletable[Circle &: Position &: CNil] = { + val lineWidth = playState.selectedBall match { + case Some(`entity`) => selectedBallLineWidth; case _ => regularBallLineWidth + } + val Circle(radius, color) &: Position(point) &: CNil = components + ecsCanvas.drawCircle(point, radius, color, lineWidth) + components + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/VelocityArrowSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/VelocityArrowSystem.scala new file mode 100644 index 00000000..57ddad89 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/VelocityArrowSystem.scala @@ -0,0 +1,24 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ DeltaTime, System, World } +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ Color, ECSCanvas, MouseState, PlayState, Position, State } + +class VelocityArrowSystem( + private val playState: PlayState, + private val mouseState: MouseState, + private val canvas: ECSCanvas, +) extends System { + private val arrowColor = Color(255, 0, 0) + private val arrowWidth = 2 + + override def shouldRun = playState.gameState == State.ChangeVelocity + + override def update(deltaTime: DeltaTime, world: World): Unit = { + val ballPosition = playState.selectedBall.get.getComponent[Position].get + canvas.drawLine(ballPosition, mouseState.coordinates, arrowColor, arrowWidth) + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/VelocityEditingSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/VelocityEditingSystem.scala new file mode 100644 index 00000000..a5f45a30 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/VelocityEditingSystem.scala @@ -0,0 +1,25 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ DeltaTime, System, World } +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ clamped, MouseState, PlayState, Position, State, Velocity } + +class VelocityEditingSystem(private val playState: PlayState, private val mouseState: MouseState) extends System { + val minVelocityIntensity = 0 + val maxVelocityIntensity = 1000 + val intensityMultiplier = 2 + + override def shouldRun = playState.gameState == State.ChangeVelocity && mouseState.clicked + + override def update(deltaTime: DeltaTime, world: World): Unit = { + val selectedBall = playState.selectedBall.get + val selectedBallPosition = selectedBall.getComponent[Position].get + val newVelocity = mouseState.coordinates - selectedBallPosition + val newDirection = newVelocity.normalized + val newIntensity = newVelocity.norm clamped (minVelocityIntensity, maxVelocityIntensity) + selectedBall setComponent Velocity(newDirection * newIntensity * intensityMultiplier) + playState.gameState = State.Pause + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/systems/WallCollisionSystem.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/WallCollisionSystem.scala new file mode 100644 index 00000000..3f12cd5f --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/systems/WallCollisionSystem.scala @@ -0,0 +1,56 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, Deletable, DeltaTime, Entity, IteratingSystem, View, World } +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ + clamped, + Circle, + ECSCanvas, + EnvironmentState, + PlayState, + Point, + Position, + State, + Vector, + Velocity, +} +import dev.atedeg.ecscalademo.util.WritableSpacePartitionContainer + +/** + * This system handles the collisions of balls on the walls. It should be run after the [[RegionAssignmentSystem]]. + * @param canvas + * the [[SpacePartitionContainer]] that will be read. + */ +class WallCollisionSystem( + private val playState: PlayState, + private val environmentState: EnvironmentState, + private val canvas: ECSCanvas, +) extends IteratingSystem[Position &: Velocity &: Circle &: CNil] { + + override def shouldRun: Boolean = playState.gameState == State.Play + + override def update(entity: Entity, components: Position &: Velocity &: Circle &: CNil)( + deltaTime: DeltaTime, + world: World, + view: View[Position &: Velocity &: Circle &: CNil], + ): Deletable[Position &: Velocity &: Circle &: CNil] = { + val Position(Point(x, y)) &: Velocity(Vector(vx, vy)) &: Circle(radius, color) &: CNil = components + val collidesLeft = x < radius + val collidesRight = x > canvas.width - radius + val collidesTop = y < radius + val collidesBottom = y > canvas.height - radius + lazy val mirroredHorizontalVelocity = -vx * environmentState.wallRestitution + lazy val mirroredVerticalVelocity = -vy * environmentState.wallRestitution + val newVelocity = Velocity( + if (collidesLeft && vx < 0) || (collidesRight && vx > 0) then mirroredHorizontalVelocity else vx, + if (collidesTop && vy < 0) || (collidesBottom && vy > 0) then mirroredVerticalVelocity else vy, + ) + val newPosition = Position( + x clamped (radius, canvas.width - radius), + y clamped (radius, canvas.height - radius), + ) + newPosition &: newVelocity &: Circle(radius, color) &: CNil + } +} diff --git a/demo/src/main/scala/dev/atedeg/ecscalademo/util/SpacePartitionContainer.scala b/demo/src/main/scala/dev/atedeg/ecscalademo/util/SpacePartitionContainer.scala new file mode 100644 index 00000000..f7ebb2b8 --- /dev/null +++ b/demo/src/main/scala/dev/atedeg/ecscalademo/util/SpacePartitionContainer.scala @@ -0,0 +1,114 @@ +package dev.atedeg.ecscalademo.util + +import scala.collection.mutable +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, Entity } +import dev.atedeg.ecscalademo.{ Circle, Mass, Position, Velocity } + +/** + * This trait represents a read-only version of a space partition container that assigns each added entity to a region + * according to its position. + */ +trait SpacePartitionContainer extends Iterable[((Int, Int), Iterable[Entity])] { + + /** + * Get the size of each region. + * @return + * the size of each region. + */ + def regionSize: Double + + /** + * Get all entities that belong to the specified region, if present. + * @param region + * the specified region. + * @return + * the entities that belong the the specified region. + */ + def get(region: (Int, Int)): Iterable[Entity] + + /** + * Return an iterator that iterates over the non-empty regions. + * @return + * the iterator. + */ + def regionsIterator: Iterator[(Int, Int)] +} + +/** + * This trait represents a writable version of the space partition container. + */ +trait WritableSpacePartitionContainer extends SpacePartitionContainer { + + type SpacePartitionComponents = Position &: Velocity &: Circle &: Mass &: CNil + + /** + * Add an entity to this space partition container. The entity must have the [[Position]], [[Velocity]], [[Mass]] and + * [[Circle]] components. + * @param entity + * the entity to be added. + */ + def add(entityComponentsPair: (Entity, SpacePartitionComponents)): Unit + + /** + * Build the space partition container so that it can be used by other systems. + */ + def build(): Unit + + /** + * Clear the contents of the space partition container. + */ + def clear(): Unit +} + +object WritableSpacePartitionContainer { + def apply(): WritableSpacePartitionContainer = new WritableSpacePartitionContainerImpl() + + private class WritableSpacePartitionContainerImpl() extends WritableSpacePartitionContainer { + private val regions: mutable.Map[(Int, Int), mutable.Set[Entity]] = mutable.Map.empty + private val entities: mutable.Map[Entity, SpacePartitionComponents] = mutable.Map.empty + private var _regionSize: Double = 0 + private val regionSizeMultiplier = 2 + + override def regionSize: Double = _regionSize + + override def add(entityComponentsPair: (Entity, SpacePartitionComponents)): Unit = { + val (_, components) = entityComponentsPair + val _ &: _ &: Circle(radius, _) &: _ &: CNil = components + entities += entityComponentsPair + _regionSize = math.max(_regionSize, radius * regionSizeMultiplier) + } + + override def build(): Unit = { + regions.clear() + for ((entity, components) <- entities) { + val position &: _ &: Circle(_, color) &: _ &: CNil = components + val region = getRegionFromPosition(position) + val regionEntities = regions get region + val regionNewEntities = regionEntities match { + case Some(entitiesInRegion) => entitiesInRegion += entity + case None => mutable.Set(entity) + } + regions += region -> regionNewEntities + } + } + + override def clear(): Unit = { + regions.clear() + entities.clear() + _regionSize = 0 + } + + override def get(region: (Int, Int)): Iterable[Entity] = regions getOrElse (region, mutable.Set()) + + override def iterator: Iterator[((Int, Int), Iterable[Entity])] = regions.iterator + + override def regionsIterator: Iterator[(Int, Int)] = regions.keysIterator + + private def getRegionFromPosition(positionComponent: Position): (Int, Int) = + ( + math.floor(positionComponent.position.x / _regionSize).toInt, + math.floor(positionComponent.position.y / _regionSize).toInt, + ) + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/MathTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/MathTest.scala index 198234bf..885a0f66 100644 --- a/demo/src/test/scala/dev/atedeg/ecscalademo/MathTest.scala +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/MathTest.scala @@ -6,6 +6,16 @@ import org.scalatest.wordspec.AnyWordSpec class MathTest extends AnyWordSpec with Matchers { "A point" when { + "inside a radius of another point" should { + "overlapped" in { + Point(1, 1).isOverlappedWith(Point(2, 2), 10, 10) shouldBe true + } + } + "outside a radius of another point" should { + "not overlapped" in { + Point(1, 1).isOverlappedWith(Point(20, 20), 5, 5) shouldBe false + } + } "adding a vector" should { "return a point with summed components" in { Point(1, 1) + Vector(2, 3) shouldBe Point(3, 4) @@ -28,17 +38,17 @@ class MathTest extends AnyWordSpec with Matchers { "return the correct result" in { Vector(1, 1) + Vector(2, 2) shouldBe Vector(3, 3) } - "subtracting another vector" should { - "return the correct result" in { - Vector(1, 1) - Vector(2, 2) shouldBe Vector(-1, -1) + "subtracting another vector" should { + "return the correct result" in { + Vector(1, 1) - Vector(2, 2) shouldBe Vector(-1, -1) + } } - } - "computing the dot product" should { - "return the correct result" in { - Vector(1, 2) dot Vector(3, 4) shouldBe 11 + "computing the dot product" should { + "return the correct result" in { + Vector(1, 2) dot Vector(3, 4) shouldBe 11 + } } } - } "inverted" should { "return the opposite vector" in { -Vector(1, 1) shouldBe Vector(-1, -1) @@ -75,9 +85,9 @@ class MathTest extends AnyWordSpec with Matchers { "A number" can { "be clamped between a minimum and a maximum" in { - 5.clamped(1, 10) shouldBe 5 - 10.clamped(2, 5) shouldBe 5 - 0.clamped(10, 20) shouldBe 10 + 5 clamped (1, 10) shouldBe 5 + 10 clamped (2, 5) shouldBe 5 + 0 clamped (10, 20) shouldBe 10 } } } diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/AutoPauseSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/AutoPauseSystemFixture.scala new file mode 100644 index 00000000..45702485 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/AutoPauseSystemFixture.scala @@ -0,0 +1,10 @@ +package dev.atedeg.ecscalademo.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscalademo.systems.AutoPauseSystem +import dev.atedeg.ecscala.dsl.ECScalaDSL + +trait AutoPauseSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val autoPauseSystem = AutoPauseSystem(playState) + world hasA system(autoPauseSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallCreationRenderingSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallCreationRenderingSystemFixture.scala new file mode 100644 index 00000000..60c2baea --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallCreationRenderingSystemFixture.scala @@ -0,0 +1,10 @@ +package dev.atedeg.ecscalademo.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.systems.BallCreationRenderingSystem + +trait BallCreationRenderingSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val ballCreationRenderingSystem = BallCreationRenderingSystem(playState, mouseState, startingState, canvas) + world hasA system(ballCreationRenderingSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallCreationSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallCreationSystemFixture.scala new file mode 100644 index 00000000..d42f4f14 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallCreationSystemFixture.scala @@ -0,0 +1,11 @@ +package dev.atedeg.ecscalademo.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.systems.BallCreationSystem + +trait BallCreationSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val entity1 = world hasAn entity + val ballCreationSystem = BallCreationSystem(playState, mouseState, startingState) + world hasA system(ballCreationSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallSelectionSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallSelectionSystemFixture.scala new file mode 100644 index 00000000..6978fc0d --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/BallSelectionSystemFixture.scala @@ -0,0 +1,10 @@ +package dev.atedeg.ecscalademo.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.systems.BallSelectionSystem + +trait BallSelectionSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val ballSelectionSystem = BallSelectionSystem(playState, mouseState) + world hasA system(ballSelectionSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/CollisionsFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/CollisionsFixture.scala new file mode 100644 index 00000000..5290b3c8 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/CollisionsFixture.scala @@ -0,0 +1,16 @@ +package dev.atedeg.ecscalademo.fixtures + +import scala.language.implicitConversions +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.systems.{ CollisionSystem, RegionAssignmentSystem } +import dev.atedeg.ecscalademo.util.WritableSpacePartitionContainer + +trait CollisionsFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + private val spacePartition = WritableSpacePartitionContainer() + val regionAssignmentSystem = RegionAssignmentSystem(playState, spacePartition) + val collisionSystem = CollisionSystem(playState, spacePartition) + + world hasA system(regionAssignmentSystem) + world hasA system(collisionSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/DragBallSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/DragBallSystemFixture.scala new file mode 100644 index 00000000..4d776460 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/DragBallSystemFixture.scala @@ -0,0 +1,12 @@ +package dev.atedeg.ecscalademo.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.Position +import dev.atedeg.ecscalademo.systems.DragBallSystem + +trait DragBallSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val entity1 = world hasAn entity withComponent Position(0, 0) + val dragBallSystem = DragBallSystem(playState, mouseState) + world hasA system(dragBallSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/FrictionSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/FrictionSystemFixture.scala new file mode 100644 index 00000000..aba25701 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/FrictionSystemFixture.scala @@ -0,0 +1,17 @@ +package dev.atedeg.ecscalademo.fixtures + +import org.mockito.Mockito.when +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.Velocity +import dev.atedeg.ecscalademo.systems.FrictionSystem + +trait FrictionSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val initialVelocity = Velocity(300, 0) + val ball = world hasAn entity withComponent initialVelocity + val frictionSystem = FrictionSystem(playState, environmentState) + world hasA system(frictionSystem) + when(environmentState.frictionCoefficient) thenReturn 1.0 + when(environmentState.wallRestitution) thenReturn 0.5 + when(environmentState.gravity) thenReturn 9.81 +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/MovementSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/MovementSystemFixture.scala new file mode 100644 index 00000000..7789b8e6 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/MovementSystemFixture.scala @@ -0,0 +1,15 @@ +package dev.atedeg.ecscalademo.fixtures + +import org.mockito.Mockito.when +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Position, Velocity } +import dev.atedeg.ecscalademo.systems.MovementSystem + +trait MovementSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val ball = world hasAn entity withComponents { Position(0, 0) &: Velocity(300, 0) } + val movementSystem = MovementSystem(playState) + world hasA system(movementSystem) + when(environmentState.frictionCoefficient) thenReturn 0.05 + when(environmentState.wallRestitution) thenReturn 0.5 +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/RegionAssignmentFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/RegionAssignmentFixture.scala new file mode 100644 index 00000000..566bafc2 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/RegionAssignmentFixture.scala @@ -0,0 +1,47 @@ +package dev.atedeg.ecscalademo.fixtures + +import scala.language.implicitConversions +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, World } +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Circle, Color, Mass, Position, Velocity } +import dev.atedeg.ecscalademo.systems.RegionAssignmentSystem +import dev.atedeg.ecscalademo.util.WritableSpacePartitionContainer + +trait RegionAssignmentFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + private val color = Color(0, 0, 0) + + val entity1 = world hasAn entity withComponents { + Position(0, 0) &: Velocity(0, 0) &: Circle(2, color) &: Mass(1) + } + + val entity1Components = entity1.getComponent[Position].get + &: entity1.getComponent[Velocity].get + &: entity1.getComponent[Circle].get + &: entity1.getComponent[Mass].get + &: CNil + + val entity2 = world hasAn entity withComponents { + Position(19, 19) &: Velocity(0, 0) &: Circle(10, color) &: Mass(1) + } + + val entity2Components = entity2.getComponent[Position].get + &: entity2.getComponent[Velocity].get + &: entity2.getComponent[Circle].get + &: entity2.getComponent[Mass].get + &: CNil + + val entity3 = world hasAn entity withComponents { + Position(20, 20) &: Velocity(0, 0) &: Circle(5, color) &: Mass(1) + } + + val entity3Components = entity3.getComponent[Position].get + &: entity3.getComponent[Velocity].get + &: entity3.getComponent[Circle].get + &: entity3.getComponent[Mass].get + &: CNil + + val spacePartition = WritableSpacePartitionContainer() + val regionAssignmentSystem = RegionAssignmentSystem(playState, spacePartition) + world hasA system(regionAssignmentSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/RenderSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/RenderSystemFixture.scala new file mode 100644 index 00000000..04f3cbd4 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/RenderSystemFixture.scala @@ -0,0 +1,15 @@ +package dev.atedeg.ecscalademo.fixtures + +import org.scalatestplus.mockito.MockitoSugar.mock +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Circle, Color, Position } +import dev.atedeg.ecscalademo.systems.RenderSystem + +trait RenderSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val position = Position(0, 0) + val circle = Circle(20, Color(255, 0, 0)) + val ball = world hasAn entity withComponents { circle &: position } + val renderSystem = RenderSystem(playState, canvas) + world hasA system(renderSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/VelocityArrowSystemFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/VelocityArrowSystemFixture.scala new file mode 100644 index 00000000..8469f9ac --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/VelocityArrowSystemFixture.scala @@ -0,0 +1,12 @@ +package dev.atedeg.ecscalademo.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Position, Velocity } +import dev.atedeg.ecscalademo.systems.VelocityArrowSystem + +trait VelocityArrowSystemFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val entity1 = world hasAn entity withComponents { Position(0, 0) &: Velocity(10, 10) } + val arrowSystem = VelocityArrowSystem(playState, mouseState, canvas) + world hasA system(arrowSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/VelocityFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/VelocityFixture.scala new file mode 100644 index 00000000..fe22ef9f --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/VelocityFixture.scala @@ -0,0 +1,12 @@ +package dev.atedeg.ecscalademo.fixtures + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Position, Velocity } +import dev.atedeg.ecscalademo.systems.VelocityEditingSystem + +trait VelocityFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val velocityEditingSystem = VelocityEditingSystem(playState, mouseState) + val entity1 = world hasAn entity withComponents { Position(0, 0) &: Velocity(0, 0) } + world hasA system(velocityEditingSystem) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WallCollisionsFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WallCollisionsFixture.scala new file mode 100644 index 00000000..9a32cf56 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WallCollisionsFixture.scala @@ -0,0 +1,26 @@ +package dev.atedeg.ecscalademo.fixtures + +import scala.language.implicitConversions +import org.mockito.Mockito.when +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Circle, Color, Mass, Position, Velocity } +import dev.atedeg.ecscalademo.systems.WallCollisionSystem + +trait WallCollisionsFixture extends ECScalaDSL with WorldFixture with WorldStateFixture { + val wallCollisionSystem = WallCollisionSystem(playState, environmentState, canvas) + world hasA system(wallCollisionSystem) + + val entities = for { + x <- Seq(-1.0, 50.0, 101.0) + y <- Seq(-1.0, 50.0, 101.0) + } yield { + world hasAn entity withComponents { + Position(x, y) &: Velocity(1, 1) &: Circle(10, Color(0, 0, 0)) &: Mass(1) + } + } + + when(environmentState.frictionCoefficient) thenReturn 0.05 + when(environmentState.wallRestitution) thenReturn 1.0 + when(environmentState.gravity) thenReturn 9.81 +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WorldFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WorldFixture.scala new file mode 100644 index 00000000..992cbc60 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WorldFixture.scala @@ -0,0 +1,7 @@ +package dev.atedeg.ecscalademo.fixtures + +import dev.atedeg.ecscala.World + +trait WorldFixture { + val world: World = World() +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WorldStateFixture.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WorldStateFixture.scala new file mode 100644 index 00000000..9d62a867 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/fixtures/WorldStateFixture.scala @@ -0,0 +1,12 @@ +package dev.atedeg.ecscalademo.fixtures + +import org.scalatestplus.mockito.MockitoSugar.mock +import dev.atedeg.ecscalademo.{ ECSCanvas, EnvironmentState, MouseState, PlayState, StartingState } + +trait WorldStateFixture { + val playState = PlayState() + val mouseState = MouseState() + val environmentState = mock[EnvironmentState] + val canvas = mock[ECSCanvas] + val startingState = StartingState(canvas) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/gui/GUITest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/gui/GUITest.scala new file mode 100644 index 00000000..47ddb651 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/gui/GUITest.scala @@ -0,0 +1,196 @@ +package dev.atedeg.ecscalademo.gui + +import dev.atedeg.ecscalademo.State +import dev.atedeg.ecscalademo.controller.MainViewController +import dev.atedeg.ecscalademo.gui.TestData.* +import javafx.fxml.FXMLLoader +import javafx.scene.Parent +import javafx.scene.control.Button +import javafx.stage.Stage +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.{ Arguments, MethodSource } +import org.testfx.api.FxRobot +import org.testfx.assertions.api.Assertions.assertThat +import org.testfx.framework.junit5.{ ApplicationExtension, Start } +import scala.jdk.javaapi.StreamConverters +import scalafx.Includes.* +import scalafx.scene.Scene + +object TestData { + val playPauseButtonId = "#playPauseBtnDelegate" + val addBallButtonId = "#addBallBtnDelegate" + val changeVelocityButtonId = "#changeVelBtnDelegate" + val resetButtonId = "#resetBtnDelegate" + val canvasId = "#canvasDelegate" + + type ButtonName = String + type Disabled = Boolean + type ButtonState = (ButtonName, Disabled) + + private def buttonsState( + playPause: Boolean, + addBall: Boolean, + changeVelocity: Boolean, + reset: Boolean, + ): Seq[ButtonState] = Seq( + (playPauseButtonId, playPause), + (addBallButtonId, addBall), + (changeVelocityButtonId, changeVelocity), + (resetButtonId, reset), + ) + + type EnabledTransitions = Seq[(State, FxRobot => Unit)] + + private val pauseEnabledTransitions: EnabledTransitions = Seq( + State.AddBalls -> reachAddBallState, + State.SelectBall -> reachSelectBallState, + State.Play -> reachPlayState, + State.Pause -> (_.clickOn(resetButtonId)), + ) + + private val playEnabledTransitions: EnabledTransitions = Seq( + State.Pause -> (_.clickOn(playPauseButtonId)), + ) + + private val addBallsEnabledTransitions: EnabledTransitions = Seq( + State.Pause -> (_.clickOn(addBallButtonId)), + State.AddBalls -> (_.clickOn(canvasId)), + State.Pause -> (_.clickOn(resetButtonId)), + ) + + private val selectBallEnabledTransitions: EnabledTransitions = Seq( + State.Play -> (_.clickOn(playPauseButtonId)), + State.SelectBall -> reachSelectBallState, + State.ChangeVelocity -> (_.clickOn(changeVelocityButtonId)), + State.AddBalls -> (_.clickOn(addBallButtonId)), + State.Pause -> (_.clickOn(canvasId)), + State.Pause -> (_.clickOn(resetButtonId)), + ) + + private val changeVelocityEnabledTransitions: EnabledTransitions = Seq( + State.Play -> (_.clickOn(playPauseButtonId)), + State.Pause -> (_.clickOn(resetButtonId)), + State.Pause -> (_.clickOn(changeVelocityButtonId)), + ) + + private def reachPlayState(fxRobot: FxRobot) = fxRobot.clickOn(playPauseButtonId) + + private def reachAddBallState(fxRobot: FxRobot) = fxRobot.clickOn(addBallButtonId) + + private def reachSelectBallState(fxRobot: FxRobot) = { + fxRobot.moveTo(mainScene.lookup(canvasId).get) + fxRobot.moveBy(50, 0) + fxRobot.clickOn() + } + + private def reachChangeVelocityState(fxRobot: FxRobot) = { + reachSelectBallState(fxRobot) + fxRobot.clickOn(changeVelocityButtonId) + } + + type StateDescription = (FxRobot => Unit, EnabledTransitions, Seq[ButtonState]) + + private val stateDescriptions: Map[State, StateDescription] = Map( + State.Pause -> (_ => (), pauseEnabledTransitions, buttonsState(false, false, true, false)), + State.Play -> (reachPlayState, playEnabledTransitions, buttonsState(false, true, true, true)), + State.AddBalls -> (reachAddBallState, addBallsEnabledTransitions, buttonsState(false, false, true, false)), + State.SelectBall -> (reachSelectBallState, selectBallEnabledTransitions, buttonsState(false, false, false, false)), + State.ChangeVelocity -> + (reachChangeVelocityState, changeVelocityEnabledTransitions, buttonsState(false, true, false, false)), + ) + + def buttonsTestArguments = StreamConverters.asJavaSeqStream( + for { + (state, (reachState, _, expectedButtonsConfiguration)) <- stateDescriptions + } yield Arguments.of(state, reachState, expectedButtonsConfiguration), + ) + + def transitionsTestArguments = StreamConverters.asJavaSeqStream( + for { + (state, (reachState, transitions, _)) <- stateDescriptions + (expectedState, transition) <- transitions + } yield Arguments.of(state, reachState, transition, expectedState), + ) +} + +private var mainScene: Scene = _ +private var controller: MainViewController = _ + +@ExtendWith(Array(classOf[ApplicationExtension])) +class GUITest { + + // Necessary in order to test the GUI in the CI headless environemnt + private def setupHeadlessTesting(): Unit = { + System.setProperty("testfx.robot", "glass") + System.setProperty("testfx.headless", "true") + System.setProperty("prism.order", "sw") + System.setProperty("prism.text", "t2k") + System.setProperty("monocle.platform", "Headless") + System.setProperty("glass.platform", "Monocle") + } + setupHeadlessTesting() + + @Start def start(stage: Stage): Unit = { + val loader: FXMLLoader = FXMLLoader() + val root: Parent = loader.load(getClass.getResource("/MainView.fxml").openStream) + controller = loader.getController[MainViewController] + mainScene = new Scene(root) + stage.setScene(mainScene) + stage.setMinHeight(540) + stage.setMinWidth(960) + stage.show() + } + + @ParameterizedTest(name = "The {0} state should respects its button configuration") + @MethodSource(Array("dev.atedeg.ecscalademo.gui.TestData#buttonsTestArguments")) + def checkStatesButtons( + testedState: State, + reachState: FxRobot => Unit, + expectedButtonsConfiguration: Seq[ButtonState], + ): Unit = { + val robot = new FxRobot() + reachState(robot) + robot.checkAllButtons(expectedButtonsConfiguration) + } + + @ParameterizedTest(name = "It should be possible to go from the {0} state to the {3} state") + @MethodSource(Array("dev.atedeg.ecscalademo.gui.TestData#transitionsTestArguments")) + def checkStateTransitions( + testedState: State, + reachState: FxRobot => Unit, + reachExpectedState: FxRobot => Unit, + expectedState: State, + ): Unit = { + val robot = new FxRobot() + reachState(robot) + reachExpectedState(robot) + assertEquals(expectedState, controller.playState.gameState) + } + + @Test + def twoResetsInARowShouldNotThrowAnException(fxRobot: FxRobot): Unit = { + (1 to 2) foreach { _ => + fxRobot.clickOn(playPauseButtonId) + fxRobot.sleep(100) + fxRobot.clickOn(playPauseButtonId) + fxRobot.clickOn(resetButtonId) + } + } +} + +extension (fxRobot: FxRobot) { + + def checkAllButtons(buttonsExpectedConfiguration: Seq[ButtonState]): Unit = + buttonsExpectedConfiguration foreach { fxRobot.findButton(_).checkEnabled(_) } + def findButton(buttonId: String): Button = fxRobot.lookup(buttonId).queryButton() +} + +extension (button: Button) { + + def checkEnabled(shouldBeEnabled: Boolean): Unit = + if shouldBeEnabled then assertThat(button).isDisabled + else assertThat(button).isEnabled +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/AutoPauseSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/AutoPauseSystemTest.scala new file mode 100644 index 00000000..cb65bfa8 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/AutoPauseSystemTest.scala @@ -0,0 +1,40 @@ +package dev.atedeg.ecscalademo.systems + +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscalademo.{ State, Velocity } +import dev.atedeg.ecscalademo.fixtures.AutoPauseSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class AutoPauseSystemTest extends AnyWordSpec with Matchers with ECScalaDSL { + + "An AutoPauseSystem" should { + "run" when { + "in an enabled state" in { + checkAllStates((playState, _) => AutoPauseSystem(playState))( + (State.Play, AnyValue, AnyValue, AnyValue), + ) + } + } + "pause the game" when { + "the energy of the system is 0" in new AutoPauseSystemFixture { + playState.gameState = State.Play + world hasAn entity withComponent Velocity(0.0, 0.0) + world hasAn entity withComponent Velocity(0.0, 0.0) + world.update(10) + playState.gameState shouldBe State.Pause + } + } + "do nothing" when { + "the energy of the system is not 0" in new AutoPauseSystemFixture { + playState.gameState = State.Play + world hasAn entity withComponent Velocity(10.0, 10.0) + world hasAn entity withComponent Velocity(0.0, 0.0) + world.update(10) + playState.gameState shouldBe State.Play + } + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallCreationRenderingSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallCreationRenderingSystemTest.scala new file mode 100644 index 00000000..7cbb9ede --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallCreationRenderingSystemTest.scala @@ -0,0 +1,36 @@ +package dev.atedeg.ecscalademo.systems + +import scalafx.scene.canvas.Canvas +import org.mockito.ArgumentMatchers.{ any, anyDouble } +import org.mockito.Mockito.verify +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.mockito.MockitoSugar +import dev.atedeg.ecscala.given +import dev.atedeg.ecscalademo.{ ECSCanvas, PlayState, StartingState, State } +import dev.atedeg.ecscalademo.fixtures.BallCreationRenderingSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class BallCreationRenderingSystemTest extends AnyWordSpec with Matchers with MockitoSugar { + + "A BallCreationRenderingSystem" should { + "run" when { + "in an enabled state" in + checkAllStates(BallCreationRenderingSystem(_, _, mock[StartingState], mock[ECSCanvas]))( + (State.AddBalls, AnyValue, AnyValue, AnyValue), + ) + } + } + + "A RenderingCreationBallSystem" when { + "enabled" should { + "render the ball" in new BallCreationRenderingSystemFixture { + enableSystemCondition(playState) + world.update(10) + verify(canvas).drawCircle(any(), anyDouble(), any(), anyDouble()) + } + } + } + + private def enableSystemCondition(playState: PlayState): Unit = playState.gameState = State.AddBalls +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallCreationSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallCreationSystemTest.scala new file mode 100644 index 00000000..ef8fbdc0 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallCreationSystemTest.scala @@ -0,0 +1,89 @@ +package dev.atedeg.ecscalademo.systems + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.mockito.MockitoSugar.mock +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ Entity, World } +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Circle, MouseState, PlayState, Point, Position, StartingState, State } +import dev.atedeg.ecscalademo.fixtures.BallCreationSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class BallCreationSystemTest extends AnyWordSpec with Matchers with ECScalaDSL { + + "A BallCreationSystem" should { + "run" when { + "in an enabled state" in + checkAllStates(BallCreationSystem(_, _, mock[StartingState]))( + (State.AddBalls, true, AnyValue, AnyValue), + ) + } + } + + "A BallCreationSystem" when { + "enabled" should { + "create a ball in a free position" in new BallCreationSystemFixture { + enableSystemCondition(playState, mouseState) + simulateCreateBall( + world, + entity1, + ballCreationSystem, + Point(0.0, 0.0), + Point(100.0, 100.0), + mouseState, + startingState, + ) + world.entitiesCount shouldBe 2 + } + "not create a ball over another one" in new BallCreationSystemFixture { + enableSystemCondition(playState, mouseState) + simulateCreateBall( + world, + entity1, + ballCreationSystem, + Point(10.0, 10.0), + Point(10.0, 10.0), + mouseState, + startingState, + ) + world.entitiesCount shouldBe 1 + } + "not create a ball when the mouse is inside another ball" in new BallCreationSystemFixture { + enableSystemCondition(playState, mouseState) + simulateCreateBall( + world, + entity1, + ballCreationSystem, + Point(10.0, 10.0), + Point(15.0, 15.0), + mouseState, + startingState, + ) + world.entitiesCount shouldBe 1 + } + } + } + + private def enableSystemCondition(playState: PlayState, mouseState: MouseState): Unit = { + playState.gameState = State.AddBalls + mouseState.clicked = true + } + + private def simulateCreateBall( + world: World, + existingEntity: Entity, + ballCreationSystem: BallCreationSystem, + existingPosition: Point, + mousePosition: Point, + mouseState: MouseState, + startingState: StartingState, + ): Unit = { + existingEntity withComponents { + Position(existingPosition) &: Circle(startingState.startingRadius, startingState.startingColor) + } + mouseState.coordinates = mousePosition + world hasA system(ballCreationSystem) + world.update(10) + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallSelectionSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallSelectionSystemTest.scala new file mode 100644 index 00000000..5526df66 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/BallSelectionSystemTest.scala @@ -0,0 +1,57 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Circle, MouseState, PlayState, Point, Position, State } +import dev.atedeg.ecscalademo.fixtures.BallSelectionSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class BallSelectionSystemTest extends AnyWordSpec with Matchers with ECScalaDSL { + + "A BallSelectionSystem" should { + "run" when { + "in an enabled state" in + checkAllStates(BallSelectionSystem(_, _))( + (State.Pause, AnyValue, true, AnyValue), + (State.SelectBall, AnyValue, true, AnyValue), + ) + } + } + + "A BallSelectionSystem" when { + "a ball is selected" should { + "set the ball as currently selected" in new BallSelectionSystemFixture { + enableSystemCondition(playState, mouseState) + playState.selectedBall = None + + val entity1 = world hasAn entity withComponents { + Position(10.0, 10.0) &: Circle(startingState.startingRadius, startingState.startingColor) + } + val entity2 = world hasAn entity withComponents { + Position(70.0, 70.0) &: Circle(startingState.startingRadius, startingState.startingColor) + } + + mouseState.coordinates = Point(10.0, 10.0) + world.update(10) + playState.selectedBall shouldBe Some(entity1) + + mouseState.coordinates = Point(65.0, 65.0) + world.update(10) + playState.selectedBall shouldBe Some(entity2) + } + } + } + + private def enableSystemCondition(playState: PlayState, mouseState: MouseState): Unit = { + playState.gameState = State.SelectBall + mouseState.down = true + } + + private def disableSystemCondition(playState: PlayState, mouseState: MouseState): Unit = { + playState.gameState = State.Pause + mouseState.down = false + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/CollisionSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/CollisionSystemTest.scala new file mode 100644 index 00000000..9783fc47 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/CollisionSystemTest.scala @@ -0,0 +1,62 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.mockito.MockitoSugar.mock +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ Circle, Color, Mass, Position, State, Vector, Velocity } +import dev.atedeg.ecscalademo.fixtures.CollisionsFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue, WritableSpacePartitionContainer } + +class CollisionSystemTest extends AnyWordSpec with Matchers with ECScalaDSL { + private val black = Color(0, 0, 0) + + "A CollisionSystem" should { + "run" when { + "in an enabled state" in + checkAllStates((playState, _) => CollisionSystem(playState, mock[WritableSpacePartitionContainer]))( + (State.Play, AnyValue, AnyValue, AnyValue), + ) + } + } + + "The CollisionSystem" should { + "keep entities separated" in new CollisionsFixture { + val stuckEntity1 = world hasAn entity withComponents { + Position(0, 0) &: Velocity(0, 0) &: Circle(10, black) &: Mass(1) + } + val stuckEntity2 = world hasAn entity withComponents { + Position(5, 0) &: Velocity(0, 0) &: Circle(10, black) &: Mass(1) + } + + playState.gameState = State.Play + world.update(1) + val stuckPosition1 = stuckEntity1.getComponent[Position].get + val stuckPosition2 = stuckEntity2.getComponent[Position].get + val stuckRadius1 = stuckEntity1.getComponent[Circle].get.radius + val stuckRadius2 = stuckEntity2.getComponent[Circle].get.radius + + val distanceBetweenStuckBalls = (stuckPosition1.position - stuckPosition2.position).norm + distanceBetweenStuckBalls shouldBe (stuckRadius1 + stuckRadius2) +- 0.001 + } + "compute the new velocities" in new CollisionsFixture { + val collidingEntity1 = world hasAn entity withComponents { + Position(20, 20) &: Velocity(100, 0) &: Circle(10, black) &: Mass(1) + } + val collidingEntity2 = world hasAn entity withComponents { + Position(40, 20) &: Velocity(0, 0) &: Circle(10, black) &: Mass(1) + } + + playState.gameState = State.Play + world.update(1) + val velocity1 = collidingEntity1.getComponent[Velocity].get + val velocity2 = collidingEntity2.getComponent[Velocity].get + + velocity1.velocity shouldBe Vector(0, 0) + velocity2.velocity shouldBe Vector(100, 0) + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/DragBallSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/DragBallSystemTest.scala new file mode 100644 index 00000000..ceb4ff1a --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/DragBallSystemTest.scala @@ -0,0 +1,39 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Point, Position, State } +import dev.atedeg.ecscalademo.fixtures.DragBallSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class DragBallSystemTest extends AnyWordSpec with Matchers with ECScalaDSL { + + "A DragBallSystem" should { + "run" when { + "in an enabled state" in + checkAllStates(DragBallSystem(_, _))( + (State.Dragging, AnyValue, AnyValue, AnyValue), + ) + } + } + + "A DragBallSystem" when { + "the game is in drag mode" should { + "update the selectes entity's position" in new DragBallSystemFixture { + playState.gameState = State.Dragging + playState.selectedBall = Some(entity1) + mouseState.coordinates = Point(10.0, 10.0) + + world.update(10) + + entity1.getComponent[Position] match { + case Some(position) => position + case _ => fail("A component should be defined") + } shouldBe Position(10.0, 10.0) + } + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/FrictionSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/FrictionSystemTest.scala new file mode 100644 index 00000000..ed367cd7 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/FrictionSystemTest.scala @@ -0,0 +1,51 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import org.mockito.Mockito.when +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.mockito.MockitoSugar +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil, View } +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ EnvironmentState, State, Velocity } +import dev.atedeg.ecscalademo.fixtures.FrictionSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class FrictionSystemTest extends AnyWordSpec with Matchers with ECScalaDSL with MockitoSugar { + + "A FrictionSystem" should { + "run" when { + "in an enabled state" in + checkAllStates((playState, _) => FrictionSystem(playState, mock[EnvironmentState]))( + (State.Play, AnyValue, AnyValue, AnyValue), + ) + } + } + + "A FrictionSystem" when { + "the simulation is playing" should { + "update a ball's Velocity considering the friction" in new FrictionSystemFixture { + playState.gameState = State.Play + (0 to 2) foreach { _ => world.update(10) } + val view: View[Velocity &: CNil] = getView[Velocity &: CNil] from world + val Velocity(vector) &: CNil = view.head._2 + vector.x should be < initialVelocity.velocity.x + } + "not update the component's Velocity if its initial Velocity is 0" in new FrictionSystemFixture { + ball setComponent Velocity(0, 0) + playState.gameState = State.Play + world.update(10) + getView[Velocity &: CNil] from world should contain theSameElementsAs List((ball, Velocity(0, 0) &: CNil)) + } + } + "the simulation is not playing" should { + "not update the components" in new FrictionSystemFixture { + playState.gameState = State.Pause + world.update(10) + getView[Velocity &: CNil] from world should contain theSameElementsAs List((ball, Velocity(300, 0) &: CNil)) + } + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/MovementSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/MovementSystemTest.scala new file mode 100644 index 00000000..3d6cb633 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/MovementSystemTest.scala @@ -0,0 +1,35 @@ +package dev.atedeg.ecscalademo.systems + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.mockito.Mockito.when +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil } +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Position, State, Velocity } +import dev.atedeg.ecscalademo.fixtures.MovementSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class MovementSystemTest extends AnyWordSpec with Matchers with ECScalaDSL { + + "A MovementSystem" should { + "run" when { + "in an enabled state" in + checkAllStates((playState, _) => MovementSystem(playState))( + (State.Play, AnyValue, AnyValue, AnyValue), + ) + } + } + + "A MovementSystem" should { + "update an entity Position" when { + "the game is playing" in new MovementSystemFixture { + playState.gameState = State.Play + world.update(10) + getView[Position &: Velocity &: CNil] from world should contain theSameElementsAs List( + (ball, Position(3000, 0) &: Velocity(300, 0) &: CNil), + ) + } + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/RegionAssignmentSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/RegionAssignmentSystemTest.scala new file mode 100644 index 00000000..86bfa9a6 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/RegionAssignmentSystemTest.scala @@ -0,0 +1,31 @@ +package dev.atedeg.ecscalademo.systems + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.mockito.MockitoSugar.mock +import dev.atedeg.ecscala.given +import dev.atedeg.ecscalademo.State +import dev.atedeg.ecscalademo.fixtures.RegionAssignmentFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue, WritableSpacePartitionContainer } + +class RegionAssignmentSystemTest extends AnyWordSpec with Matchers { + + "A RegionAssignmentSystem" should { + "run" when { + "in an enabled state" in + checkAllStates((playState, _) => RegionAssignmentSystem(playState, mock[WritableSpacePartitionContainer]))( + (State.Play, AnyValue, AnyValue, AnyValue), + ) + } + } + + "A RegionAssignmentSystem" should { + "assign a region to each entity" in new RegionAssignmentFixture { + playState.gameState = State.Play + world.update(0) + spacePartition get (0, 0) should contain theSameElementsAs List(entity1, entity2) + spacePartition get (1, 1) should contain theSameElementsAs List(entity3) + spacePartition get (2, 2) shouldBe empty + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/RenderSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/RenderSystemTest.scala new file mode 100644 index 00000000..c0c84e31 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/RenderSystemTest.scala @@ -0,0 +1,29 @@ +package dev.atedeg.ecscalademo.systems + +import org.mockito.Mockito.verify +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.mockito.MockitoSugar.mock +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ Circle, ECSCanvas } +import dev.atedeg.ecscalademo.fixtures.RenderSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class RenderSystemTest extends AnyWordSpec with Matchers with ECScalaDSL { + + "A RenderSystem" should { + "always run" in { + checkAllStates((playState, _) => RenderSystem(playState, mock[ECSCanvas]))( + (AnyValue, AnyValue, AnyValue, AnyValue), + ) + } + + "call the drawCircle method with the correct parameters" in new RenderSystemFixture { + world.update(10) + verify(canvas).drawCircle(position.position, circle.radius, circle.color, 1) + playState.selectedBall = Some(ball) + world.update(10) + verify(canvas).drawCircle(position.position, circle.radius, circle.color, 3) + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/VelocityArrowSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/VelocityArrowSystemTest.scala new file mode 100644 index 00000000..16996392 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/VelocityArrowSystemTest.scala @@ -0,0 +1,34 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import org.mockito.ArgumentMatchers.{ any, anyDouble, eq as is } +import org.mockito.Mockito.verify +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.mockito.MockitoSugar.mock +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.given +import dev.atedeg.ecscalademo.{ ECSCanvas, Point, State, Velocity } +import dev.atedeg.ecscalademo.fixtures.VelocityArrowSystemFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class VelocityArrowSystemTest extends AnyWordSpec with Matchers with ECScalaDSL { + + "A VelocityArrowSystem" should { + "run" when { + "in an enabled state" in + checkAllStates(VelocityArrowSystem(_, _, mock[ECSCanvas]))( + (State.ChangeVelocity, AnyValue, AnyValue, AnyValue), + ) + } + + "draw an arrow in the canvas" in new VelocityArrowSystemFixture { + playState.gameState = State.ChangeVelocity + playState.selectedBall = Some(entity1) + mouseState.coordinates = (10.0, 10.0) + world.update(10) + verify(canvas).drawLine(is(Point(0, 0)), is(Point(10, 10)), any(), anyDouble()) + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/VelocityEditingSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/VelocityEditingSystemTest.scala new file mode 100644 index 00000000..6211a2a0 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/VelocityEditingSystemTest.scala @@ -0,0 +1,33 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscala.given +import dev.atedeg.ecscalademo.{ Point, State, Velocity } +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } +import dev.atedeg.ecscalademo.fixtures.VelocityFixture + +class VelocityEditingSystemTest extends AnyWordSpec with Matchers { + + "A VelocityEditingSystem" should { + "run" when { + "in an enabled state" in + checkAllStates(VelocityEditingSystem(_, _))( + (State.ChangeVelocity, true, AnyValue, AnyValue), + ) + } + "correctly update the velocity" in testNewExpectedVelocity(Point(1, 2), Velocity(2, 4)) + "limit the maximum velocity" in testNewExpectedVelocity(Point(3000, 0), Velocity(2000, 0)) + } + + private def testNewExpectedVelocity(mouseCoordinates: Point, expectedVelocity: Velocity): Unit = new VelocityFixture { + playState.gameState = State.ChangeVelocity + playState.selectedBall = Some(entity1) + mouseState.clicked = true + mouseState.coordinates = mouseCoordinates + velocityEditingSystem.shouldRun shouldBe true + world.update(10) + entity1.getComponent[Velocity].get shouldBe expectedVelocity + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/systems/WallCollisionSystemTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/WallCollisionSystemTest.scala new file mode 100644 index 00000000..8171093c --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/systems/WallCollisionSystemTest.scala @@ -0,0 +1,57 @@ +package dev.atedeg.ecscalademo.systems + +import scala.language.implicitConversions +import org.mockito.Mockito.when +import org.scalatest.BeforeAndAfterEach +import org.scalatest.Inspectors.forAll +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.mockito.MockitoSugar.mock +import dev.atedeg.ecscala.given +import dev.atedeg.ecscala.{ &:, CNil } +import dev.atedeg.ecscala.dsl.ECScalaDSL +import dev.atedeg.ecscalademo.{ ECSCanvas, EnvironmentState, Position, State, Velocity } +import dev.atedeg.ecscalademo.fixtures.WallCollisionsFixture +import dev.atedeg.ecscalademo.util.{ checkAllStates, AnyValue } + +class WallCollisionSystemTest + extends AnyWordSpec + with BeforeAndAfterEach + with Matchers + with ECScalaDSL + with WallCollisionsFixture { + + override protected def beforeEach(): Unit = { + playState.gameState = State.Play + when(canvas.width) thenReturn 100.0 + when(canvas.height) thenReturn 100.0 + world.update(1) + } + + "A WallCollisionSystem" should { + "run" when { + "in an enabled state" in + checkAllStates((playState, _) => WallCollisionSystem(playState, mock[EnvironmentState], mock[ECSCanvas]))( + (State.Play, AnyValue, AnyValue, AnyValue), + ) + } + + "keep entities inside the canvas's borders" in + checkViewElements { (position, _) => + position.x should (be >= 10.0 and be <= 90.0) + position.y should (be >= 10.0 and be <= 90.0) + } + "change velocities to entities that collide with the canvas's borders" in + checkViewElements { (position, velocity) => + velocity shouldBe Velocity(if position.x == 90.0 then -1 else 1, if position.y == 90.0 then -1 else 1) + } + } + + private def checkViewElements(f: (Position, Velocity) => Unit): Unit = { + val view = getView[Position &: Velocity &: CNil] from world + forAll(view map (_._2)) { comps => + val position &: velocity &: CNil = comps + f(position, velocity) + } + } +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/util/PreconditionChecks.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/util/PreconditionChecks.scala new file mode 100644 index 00000000..eecae468 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/util/PreconditionChecks.scala @@ -0,0 +1,63 @@ +package dev.atedeg.ecscalademo.util + +import org.scalatest.Assertions.withClue +import org.scalatest.matchers.should.Matchers.shouldBe +import org.scalatest.prop.TableDrivenPropertyChecks.* +import dev.atedeg.ecscala.System +import dev.atedeg.ecscalademo.{ MouseState, PlayState, State } + +sealed trait AnyValue +case object AnyValue extends AnyValue +type TestState[T] = T | AnyValue +type ClickedState = TestState[Boolean] +type DownState = TestState[Boolean] +type UpState = TestState[Boolean] +type StateDescription = (TestState[State], ClickedState, DownState, UpState) + +private given defaultBooleanValues: Set[Boolean] = Set(true, false) +private given defaultStateValues: Set[State] = Set.from(State.values) + +extension [T](state: TestState[T]) { + + def values(using defaultValues: Set[T]): Set[T] = state match { + case AnyValue => defaultValues + case t => Set(t.asInstanceOf[T]) + } +} + +def checkAllStates(systemBuilder: (PlayState, MouseState) => System)(enabled: StateDescription*): Unit = { + import StateUtils.* + val enabledStates = expandStates(enabled*) + val disabledStates = allStates -- enabledStates + checkStates(systemBuilder)(enabledStates)(true) + checkStates(systemBuilder)(disabledStates)(false) +} + +private object StateUtils { + + def checkStates( + systemBuilder: (PlayState, MouseState) => System, + )(states: Set[(PlayState, MouseState)])(shouldRun: Boolean) = { + val table = Table(("playState", "mouseState"), states.toSeq*) + forAll(table) { (playState, mouseState) => + val errorClue = + s"System expected to be ${if shouldRun then "enabled, instead was disabled" else "disabled, instead was enabled"}." + withClue(errorClue) { systemBuilder(playState, mouseState).shouldRun shouldBe shouldRun } + } + } + + def expandStates(states: StateDescription*): Set[(PlayState, MouseState)] = for { + (stateValue, clickedValue, downValue, upValue) <- Set.from(states) + state <- stateValue.values + clicked <- clickedValue.values + down <- downValue.values + up <- upValue.values + } yield (PlayState(state), MouseState(clicked = clicked, down = down, up = up)) + + def allStates: Set[(PlayState, MouseState)] = for { + clicked <- Set(true, false) + down <- Set(true, false) + up <- Set(true, false) + state <- Set.from(State.values) + } yield (PlayState(state), MouseState(clicked = clicked, down = down, up = up)) +} diff --git a/demo/src/test/scala/dev/atedeg/ecscalademo/util/SpacePartitionContainerTest.scala b/demo/src/test/scala/dev/atedeg/ecscalademo/util/SpacePartitionContainerTest.scala new file mode 100644 index 00000000..69b32823 --- /dev/null +++ b/demo/src/test/scala/dev/atedeg/ecscalademo/util/SpacePartitionContainerTest.scala @@ -0,0 +1,30 @@ +package dev.atedeg.ecscalademo.util + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import dev.atedeg.ecscalademo.fixtures.RegionAssignmentFixture +import dev.atedeg.ecscalademo.util.WritableSpacePartitionContainer + +class SpacePartitionContainerTest extends AnyWordSpec with Matchers { + + "The space partition container" should { + "add entities with the required components" in new RegionAssignmentFixture { + val container = WritableSpacePartitionContainer() + container add (entity1, entity1Components) + container add (entity2, entity2Components) + container add (entity3, entity3Components) + noException should be thrownBy container.build() + } + "get added entities by their region" in new RegionAssignmentFixture { + val container = WritableSpacePartitionContainer() + container add (entity1, entity1Components) + container add (entity2, entity2Components) + container add (entity3, entity3Components) + container.build() + container.regionSize shouldBe 20 + container get (0, 0) should contain theSameElementsAs List(entity1, entity2) + container get (1, 1) should contain theSameElementsAs List(entity3) + container get (2, 2) shouldBe empty + } + } +} diff --git a/doc/0-introduction.tex b/doc/0-introduction.tex index 4c646497..447b60af 100644 --- a/doc/0-introduction.tex +++ b/doc/0-introduction.tex @@ -1,3 +1,31 @@ \chapter*{Introduzione} \addcontentsline{toc}{chapter}{Introduzione} -% TODO: descrivere stato dell'arte e applicazioni di ECS \ No newline at end of file +Il progetto ha come obiettivo la realizzazione di un framework che consenta l'implementazione del pattern +architetturale \ECS (Entity Component System). +Questo è un pattern tipicamente usato nel settore videoludico, che favorisce i principi di +\textit{composition over inheritance} e \textit{data-oriented design}. +Due esempi significativi di uso del pattern ECS sono i videogiochi \textit{Overwatch} (2016)~\cite{gdc:overwatch} +e \textit{Minecraft} (2011)~\cite{minecraft}. + +I tre concetti chiave di ECS sono: +\begin{itemize} + \item \Entity: un oggetto distinto che esiste nella simulazione, che non ha dati né comportamento, + \eg una palla da biliardo, un nemico di un videogioco, un proiettile, eccetera. + \item \Component: un elemento che descrive una particolare caratteristica di una \Entity senza descriverne + l'effettivo comportamento, \eg posizione, velocità, salute, informazioni per il rendering, eccetera. + \item \System: una funzione che viene eseguita su ogni \Entity che possiede tutti i \Component richiesti e ne + legge o modifica i loro valori; + tramite questa si dà l'effettivo comportamento alle \Entity. + Alcuni esempi di \System possono essere un sistema di rendering che richiede i componenti posizione e immagine, + un sistema di calcolo dei danni che richiede il componente salute, eccetera. +\end{itemize} + +Esistono diverse librerie open source che permettono l'implementazione del pattern \ECS; fra le più importanti risulta +EnTT~\cite{entt}, libreria scritta in \CC\ usata dal videogioco \textit{Minecraft}. +Nell'ambiente JVM troviamo invece Artemis~\cite{artemis} e Ashley~\cite{ashley}, entrambe scritte in +Java, che però non possono vantare un uso in applicazioni di rilievo. + +Il nostro obiettivo è quello di creare una libreria che faccia della type safety il suo maggior punto di forza, +alla quale si aggiunge un comodo DSL per scrivere codice idiomatico e compatto. +Sebbene le prestazioni siano normalmente d'importanza spesso critica, abbiamo deciso di non realizzare tutte le +ottimizzazioni implementate dalle altre liberie~\cite{entt:optimizations}, in quanto esulano dall'obiettivo del corso. diff --git a/doc/1-development-process.tex b/doc/1-development-process.tex index 063fe660..50d2ba78 100644 --- a/doc/1-development-process.tex +++ b/doc/1-development-process.tex @@ -1 +1,46 @@ -\chapter{Processo di sviluppo}\label{ch:processo-di-sviluppo} \ No newline at end of file +\chapter{Processo di sviluppo}\label{ch:processo-di-sviluppo} +\section{Metodologia di lavoro}\label{sec:metodologia-di-lavoro} +Il processo di sviluppo adottato dal team si basa sulla versione semplificata di \textit{SCRUM} consigliata dal docente: +sono presenti le figure di \textit{product owner} e di \textit{domain expert}, sono stati svolti sprint a cadenza +settimanale e si sono redatti \textit{product backlog} e \textit{sprint backlog}. +Il team ha applicato il più possibile la tecnica di sviluppo \textit{test-driven} e largamente sfruttato la modalità +collaborativa di \textit{pair programming} che ha permesso di ottimizzare e rendere più veloce l'implementazione del +codice, nonché d'individuare rapidamente eventuali bug. + +\subsection{Organizzazione degli Sprint}\label{subsec:organizzazione-sprint} +Il primo sprint è stato organizzativo: sono stati identificati gli elementi di base del processo di sviluppo, è stata +preparata la build del progetto ed è stata prodotta la prima versione del product backlog secondo i requisiti +identificati per il progetto. +È stato inoltre necessario concordare la \textit{definition of done} per capire quando uno sprint item potesse +considerarsi concluso; +ne è emerso che ciò avviene solo se il codice che ne realizza le funzionalità soddisfa i seguenti punti: +\begin{itemize} + \item i test vengono eseguiti con successo + \item il codice è ben formattato + \item è presente la Scaladoc + \item la coverage viene, eventualmente, decrementata al più del 5\% + \item il codice prodotto viene controllato e approvato dagli altri membri del gruppo +\end{itemize} +Per quanto riguarda gli sprint successivi, a inizio settimana il team si è incontrato di persona per la fase di +\textit{sprint planning} durante la quale, a partire dagli item del product backlog, è stato prodotto lo +sprint backlog e sono stati assegnati gli item ai membri. +Al termine di ogni sprint è stata scritta la retrospettiva per verificare l'attuale stato di avanzamento del progetto +ed, eventualmente, posporre alla settimana seguente gli sprint item non conclusi. +Inoltre, ogni membro ha opportunamente aggiornato lo sprint backlog con l'effort rimanente al completamento del +proprio item. + +\section{Strumenti utilizzati}\label{sec:strumenti-utilizzati} +A supporto del processo sopra descritto, il team ha principalmente adottato gli strumenti messi a disposizione da +GitHub: sono state utilizzate le issue per tenere traccia degli item degli sprint backlog e assegnarli ai singoli +membri; +inoltre, si è ricorso a pull request da \textit{feature branch} per permettere la code review. +Per avere una visione globale e chiara dell'andamento dello sviluppo, sono stati tracciati e tenuti in versione nel +repository del progetto - su file .csv - tutti gli sprint backlog e il product backlog. + +È stato verificato in modo automatico che il codice prodotto rispettasse i requisiti prestabiliti nella +definition of done tramite le \textit{GitHub Actions} configurate opportunamente. + +Per le release su \textit{Sonatype} è stato utilizzato il plugin \texttt{sbt-ci-release}~\cite{sbt-ci-release} +opportunamente configurato per eseguire il rilascio direttamente dalla CI\@. + +In ultimo, si è utilizzato il \textit{Semantic Versioning} per le release. diff --git a/doc/2-requirements.tex b/doc/2-requirements.tex new file mode 100644 index 00000000..e3c04e1f --- /dev/null +++ b/doc/2-requirements.tex @@ -0,0 +1,92 @@ +\chapter{Requisiti}\label{ch:requisiti} +Per l'individuazione dei requisiti è stato innanzitutto analizzato il pattern ECS e la terminologia adottata. +In Tabella~\ref{tab:glossario} è riportato un glossario con i principali concetti del pattern. +\begin{table}[H] + \begin{tabular}{p{0.17\linewidth}p{0.76\linewidth}} + \toprule + \textbf{World} & Contiene più \Entity e i rispettivi \Component. + Permette la registrazione di più \System che utilizza per aggiornare lo stato dei \Component \\ + \textbf{View} & Rappresenta il sottoinsieme delle \Entity di un \World con i soli \Component specificati \\ + \textbf{Entity} & Oggetto definito dai rispettivi \Component\\ + \textbf{Component} & Rappresenta una particolare caratteristica da modellare per una \Entity\\ + \textbf{System} & Aggiorna i \Component di tutte le \Entity di una determinata \View secondo una logica + definita dall'utilizzatore\\ + \bottomrule + \end{tabular}\caption{\label{tab:glossario}Glossario dei termini del dominio.} +\end{table} + +\section{Business}\label{sec:business} +L'obiettivo è quello di realizzare un framework che permetta di applicare in maniera semplice il pattern ECS\@. +I requisiti di business individuati sono: +\begin{enumerate}[label=\textbf{\ref{sec:business}.\arabic*}] + \item \label{itm:b1} Dev'essere possibile utilizzare in maniera semplice ed efficiente il pattern ECS + \item \label{itm:b2} Il framework dev'essere sufficientemente flessibile da poter realizzare simulazioni e videogiochi. + In particolare dev' essere possibile: + \begin{enumerate}[label=\textbf{\ref{itm:b2}.\arabic*}] + \item \label{itm:bb3} Realizzare una simulazione del moto di palle da biliardo in un tavolo da gioco + \end{enumerate} +\end{enumerate} + +\section{Utente}\label{sec:utente} +I requisiti utente sono sviluppati considerando il punto di vista dello sviluppatore che dovrà utilizzare il framework. +In particolare: +\begin{enumerate}[label=\textbf{\ref{sec:utente}.\arabic*}] + \item \label{itm:u1} Dev'essere possibile creare il \World che contiene tutte le \Entity + \item \label{itm:u2} Dev'essere possibile creare e rimuovere \Component + \item \label{itm:u3} Dev'essere possibile creare e rimuovere \Entity + \item \label{itm:u4} Dev'essere possibile creare \System + \item \label{itm:u5} Dev'essere possibile utilizzare un DSL per effettuare le operazioni sopra elencate + \item \label{itm:u6} Per l'utente è importante avere un esempio di utilizzo del framework +\end{enumerate} + +\section{Funzionali}\label{sec:funzionali} +I requisiti funzionali, ricavati da quelli utente, sono: +\begin{enumerate}[label=\textbf{\ref{sec:funzionali}.\arabic*}] + \item \label{itm:f1} Definire uno o più \World + \begin{enumerate}[label=\textbf{\ref{itm:f1}.\arabic*}] + \item \label{itm:ff2} Far avanzare lo stato del \World, comportando l'aggiornamento delle sue \Entity + \end{enumerate} + \item \label{itm:f2} Definire \Component + \item \label{itm:f3} Creare \Entity all'interno di un \World + \item \label{itm:f4} Rimuovere \Entity dal \World in cui si trovano + \item \label{itm:f5} Manipolare lo stato delle \Entity + \begin{enumerate}[label=\textbf{\ref{itm:f5}.\arabic*}] + \item \label{itm:ff3} Aggiungere \Component alle \Entity + \item \label{itm:ff4} Rimuovere \Component dalle \Entity + \end{enumerate} + \item \label{itm:f6} Creare diverse tipologie di \View che selezionino alcune \Entity del \World + \begin{enumerate}[label=\textbf{\ref{itm:f6}.\arabic*}] + \item \label{itm:ff5} \View per ottenere tutte le \Entity del \World che possiedono i \Component specificati + \item \label{itm:ff6} \View per ottenere tutte le \Entity del \World che non possiedono nessuno dei \Component + specificati + \end{enumerate} + \item \label{itm:f7} Creare diverse tipologie di \System + \begin{enumerate}[label=\textbf{\ref{itm:f7}.\arabic*}] + \item \label{itm:ff7} \System per manipolare gli specifici \Component delle \Entity + \item \label{itm:ff10} \System che non operano sui \Component delle \Entity ma permettono di eseguire operazioni + a ogni aggiornamento dello stato del \World + \item \label{itm:ff11} \System che consentono di escludere alcune \Entity sulla base dei \Component specificati + \end{enumerate} + \item \label{itm:f8} Registrare \System nel \World + \item \label{itm:f9} Fornire un DSL per + \begin{enumerate}[label=\textbf{\ref{itm:f9}.\arabic*}] + \item \label{itm:ff12} Definire \System + \item \label{itm:ff13} Manipolare \Entity + \item \label{itm:ff14} Manipolare lo stato del \World + \end{enumerate} +\end{enumerate} + + +\section{Non funzionali}\label{sec:non-funzionali} +Considerando gli scenari d'uso elencati al punto~\ref{itm:b2}, il \System deve rispettare il seguente requisito: +\begin{enumerate}[label=\textbf{\ref{sec:non-funzionali}.\arabic*}] + \item \label{itm:nf1} Aggiornare velocità e posizione di $10\;000$ \Entity in non più di 10ms +\end{enumerate} + + +\section{Implementativi}\label{sec:implementativi} +Per la realizzazione del framework verrano utilizzati: +\begin{enumerate}[label=\textbf{\ref{sec:implementativi}.\arabic*}] + \item \label{itm:i1} Scala 3 come linguaggio principale + \item \label{itm:i2} ScalaTest~\cite{scalatest} per la realizzazione di unit test +\end{enumerate} diff --git a/doc/2-requirments.tex b/doc/2-requirments.tex deleted file mode 100644 index d3f0ea25..00000000 --- a/doc/2-requirments.tex +++ /dev/null @@ -1,82 +0,0 @@ -\chapter{Requisiti}\label{ch:requisiti} -Per l'individuazione dei requisiti è stato innanzitutto analizzato il pattern ECS e la terminologia adottata. -In Tabella~\ref{tab:glossario} è riportato un gloassario con i principali concetti del pattern: -\begin{table}[H] - \begin{tabular}{p{0.17\linewidth}p{0.76\linewidth}} - \toprule - \textbf{World} & Contiene più \textit{entity} e i rispettivi \textit{component}. - Permette la registrazione di più \textit{system} che utilizza per aggiornare lo stato dei \textit{component} \\ - \textbf{View} & Rappresenta il sottoinsieme delle \textit{entity} di un \textit{world} con i soli \textit{component} specificati \\ - \textbf{Entity} & Contiene più \textit{entity} e i rispettivi \textit{component} \\ - \textbf{Component} & Rappresenta una particolare caratteristica da modellare per una \textit{entity} \\ - \textbf{System} & Aggiorna lo stato dei \textit{component} di tutte le \textit{entity} di una determinata \textit{view} secondo una logica definita dall'utilizzatore \\ - \bottomrule - \end{tabular}\caption{\label{tab:glossario}Glossario dei termini del dominio.} -\end{table} - -\section{Business}\label{sec:business} -L'obiettivo è quello di realizzare un framework che permetta di applicare in maniera semplice il pattern ECS\@. -I requisiti di business individuati sono: -\begin{enumerate}[label=\textbf{\ref{sec:business}.\arabic*}] - \item \label{itm:b1} Deve essere possibile utilizzare in maniera semplice ed efficiente il pattern ECS - \item \label{itm:b2} Il framework deve essere sufficientemente flessibile da poter realizzare simulazioni e videogiochi. - In particolare deve essere possibile: - \begin{enumerate}[label=\textbf{\ref{itm:b2}.\arabic*}] - \item \label{itm:bb3} Realizzare una simulazione del moto di palle da biliardo in un tavolo da gioco - \end{enumerate} -\end{enumerate} - -\section{Utente}\label{sec:utente} -I requisiti utente sono sviluppati considerando il punto di vista dello sviluppatore che dovrà utilizzare il framework. -In particolare: -\begin{enumerate}[label=\textbf{\ref{sec:utente}.\arabic*}] - \item \label{itm:u1} Deve essere possibile creare l'universo che contiene tutte le \textit{entità} - \item \label{itm:u2} Deve essere possibile creare e rimuovere \textit{componenti} - \item \label{itm:u3} Deve essere possibile creare e rimuovere \textit{entità} - \item \label{itm:u4} Deve essere possibile creare \textit{sistemi} - \item \label{itm:u5} Deve essere possibile utilizzare un DSL per effettuare le operazioni sopra elencate - \item \label{itm:u6} Per l'utente è importante avere un esempio di utilizzo del framework -\end{enumerate} - -\section{Funzionali}\label{sec:funzionali} -I requisiti funzionali, ricavati da quelli utente, sono: -\begin{enumerate}[label=\textbf{\ref{sec:funzionali}.\arabic*}] - \item \label{itm:f1} Definire uno o più \textit{world} - \begin{enumerate}[label=\textbf{\ref{itm:f1}.\arabic*}] - \item \label{itm:ff1} Definire delle \textit{viste} che selezionino alcune \textit{entità} del \textit{mondo} - \item \label{itm:ff2} Far avanzare lo stato del \textit{mondo}, comportando l'aggiornamento delle sue \textit{entità} - \end{enumerate} - \item \label{itm:f2} Definire \textit{componenti} - \item \label{itm:f3} Creare \textit{entità} all'interno di un \textit{mondo} - \item \label{itm:f4} Rimuovere \textit{entità} dal \textit{mondo} in cui si trovano - \item \label{itm:f5} Manipolare lo stato delle \textit{entità} - \begin{enumerate}[label=\textbf{\ref{itm:f5}.\arabic*}] - \item \label{itm:ff3} Aggiungere \textit{componenti} alle \textit{entità} - \item \label{itm:ff4} Rimuovere \textit{componenti} dalle \textit{entità} - \end{enumerate} - \item \label{itm:f6} Creare \textit{sistemi} per manipolare i \textit{componenti} delle \textit{entità} - \item \label{itm:f7} Registrare \textit{sistemi} nel \textit{mondo} - \item \label{itm:f8} Fornire un DSL - \begin{enumerate}[label=\textbf{\ref{itm:f8}.\arabic*}] - \item \label{itm:ff5} Definire \textit{sistemi} - \item \label{itm:ff6} Manipolare \textit{entità} - \item \label{itm:ff7} Manipolare lo stato del \textit{mondo} - \end{enumerate} - \item TODO: demo %TODO: demo progetto -\end{enumerate} - - -\section{Non funzionali}\label{sec:non-funzionali} -Considerando gli scenari d'uso elencati al punto~\ref{itm:b2}, il sistema deve rispettare il seguente requisito: -\begin{enumerate}[label=\textbf{\ref{sec:non-funzionali}.\arabic*}] - \item \label{itm:nf1} Aggiornare velocità e posizione di 10'000 \textit{entità} in non più di 10ms -\end{enumerate} - - -\section{Implementativi}\label{sec:implementativi} -\begin{enumerate}[label=\textbf{\ref{sec:implementativi}.\arabic*}] - \item \label{itm:i1} Scala 3 - \item \label{itm:i2} Scalatest - \item \label{itm:i3} JaCoCo per code coverage - \item TODO %TODO citare eventuali librerie esterne -\end{enumerate} \ No newline at end of file diff --git a/doc/3-architectural-design.tex b/doc/3-architectural-design.tex index ae5cdf22..bb0afe5f 100644 --- a/doc/3-architectural-design.tex +++ b/doc/3-architectural-design.tex @@ -1,35 +1,49 @@ \chapter{Design architetturale}\label{ch:design-architetturale} A seguito dell'analisi dei requisiti definiti nel capitolo precedente, si è realizzato il design architetturale -di massima riportato in Figura. - -\begin{figure}[H] - \centering - \includegraphics[width=\textwidth]{./img/Architechture} - \caption{Hello}\label{fig:architecture} -\end{figure} +di massima riportato in Figura~\ref{fig:architecture}. I principali componenti individuati sono: \begin{itemize} \item \texttt{World}: permette la registrazione e rimozione di \texttt{Entity} e \texttt{System}. - Il metodo \texttt{update} rappresenta la principale modalità di aggiornamento dello stato di un \texttt{World}: infatti, comporta la modifica dei \texttt{Component} delle \texttt{Entity} registrate secondo la logica descritta dai \texttt{System}. - Inoltre, è possibile ottenere dal \texttt{World} delle \texttt{View} sulle \texttt{Entity} registrate - \item \texttt{View}: permette di selezionare le \texttt{Entity} di un \texttt{World} che abbiano tutti i \texttt{Component} specificati - \item \texttt{ExcludingView}: rappresenta una specializzazione di una \texttt{View} che permette di specificare un ulteriore filtro andando ad indicare i \texttt{Component} che una \texttt{Entity} non deve avere per essere parte della \texttt{View} - \item \texttt{System}: è un wrapper di una \texttt{View} che, indicando una specifica logica di aggiornamento, si occupa di iterare tutte le \texttt{Entity} selezionate aggiornandone i componenti - \item \texttt{ExcludingSystem}: in maniera analoga a \texttt{System}, è un wrapper di una \texttt{ExcludingView} + Il metodo \texttt{update} rappresenta la principale modalità di aggiornamento dello stato di un~\texttt{World}: + infatti, comporta la modifica dei \texttt{Component} delle \texttt{Entity} secondo la logica descritta dai + \texttt{System}. + Inoltre, è possibile ottenere dal \texttt{World} delle \texttt{View} sulle sue \texttt{Entity} + \item \texttt{View}: permette di selezionare le \texttt{Entity} di un \texttt{World} che abbiano tutti i + \texttt{Component} specificati + \item \texttt{ExcludingView}: rappresenta una specializzazione di una \texttt{View} che permette di specificare un + ulteriore filtro andando a indicare i \texttt{Component} che una \texttt{Entity} non deve avere per essere parte + della \texttt{View} + \item \texttt{System}: descrive un'operazione che viene eseguita ogni volta che viene effettuato l'\texttt{update} + del \texttt{World} in cui è registrato + \item \texttt{IteratingSystem}: è un wrapper di una \texttt{View} che, indicando una specifica logica di + aggiornamento, si occupa d'iterare tutte le \texttt{Entity} selezionate aggiornandone i \texttt{Component} + \item \texttt{ExcludingSystem}: in maniera analoga a \texttt{IteratingSystem}, è un wrapper di una + \texttt{ExcludingView} \item \texttt{Entity}: permette l'aggiunta e rimozione di \texttt{Component} e il loro aggiornamento. - Non può trovarsi in più \texttt{World} contemporaneamente; - mantiene un riferimento al \texttt{World} di appartenenza + Non può trovarsi in più \texttt{World} contemporaneamente \item \texttt{Component}: descrive una particolare caratteristica di un'\texttt{Entity} alla quale viene aggiunto. Non può trovarsi in più di un'\texttt{Entity} contemporaneamente; mantiene un riferimento all'\texttt{Entity} di appartenenza \end{itemize} -In Figura è riportato il diagramma di sequenza che descrive le principali interazioni che si verificano quando viene effettuato l'\texttt{update} di un \texttt{World}. +\begin{figure}[H] + \centering + \includegraphics[width=0.95\textwidth]{./img/Architechture} + \caption{Diagramma delle classi rappresentante l'architettura del framework.}\label{fig:architecture} +\end{figure} + +In Figura~\ref{fig:sequence} è riportato il diagramma di sequenza che descrive le principali interazioni che si +verificano quando viene effettuato l'\texttt{update} di un~\texttt{World}. \begin{figure}[H] \centering \includegraphics[width=\textwidth]{./img/Sequence} - \caption{HH}\label{fig:figure} + \caption{Diagramma di sequenza che mostra il processo di aggiornamento dei componenti nel world.}\label{fig:sequence} \end{figure} +Una volta aggiunti i sistemi al mondo, è possibile eseguirli affinché modifichino i componenti +su cui devono operare mediante la chiamata al metodo~\texttt{update}. +Per ogni \texttt{System} del \texttt{World} si verifica, tramite il metodo \texttt{shouldRun}, che questo possa essere +eseguito. +In caso affermativo, il sistema viene eseguito chiamandone il metodo \texttt{update}. diff --git a/doc/4-detailed-design.tex b/doc/4-detailed-design.tex index bc636c1c..52858e9e 100644 --- a/doc/4-detailed-design.tex +++ b/doc/4-detailed-design.tex @@ -1 +1,45 @@ -\chapter{Design di dettaglio}\label{ch:design-di-dettaglio} \ No newline at end of file +\chapter{Design di dettaglio}\label{ch:design-di-dettaglio} +In seguito alla realizzazione del design architetturale di massima sono state effettuate scelte rilevanti +ai fini della progettazione di alcune parti del sistema. + +\section{Lista di componenti}\label{sec:lista-di-componenti} +Come emerge dal design architetturale, i sistemi e le viste indicano, a livello del proprio tipo, su quali +componenti andranno ad operare. +Per indicare queste liste di tipi si è scelto di utilizzare le \texttt{CList} (abbreviazione di \textit{Components List}) +che sono essenzialmente liste di elementi eterogenei che preservano informazioni sui tipi dei propri elementi in maniera +simile alle tuple. + +L’idea alla base di questa soluzione è ispirata dalle \textit{Heterogeneous List} della libreria +Shapeless~\cite{shapeless}. + +\section{Container di componenti}\label{sec:container-di-componenti} +Come è possibile osservare in Figura~\ref{fig:world-detail}, dal design architetturale emerge come +non siano le entità stesse a possedere i componenti che vengono loro assegnati. +Infatti, la gestione dei componenti è demandata a un container di componenti; +questo permette di aggiungere o rimuovere coppie entità-componente oppure di ottenere tutte le entità con uno specifico +tipo di componente. +In questo modo è possibile introdurre in maniera semplice ottimizzazioni nella gestione dei +componenti per rendere la loro iterazione (fondamentale per i sistemi) quanto più veloce possibile. + +Grazie a questa scelta è stato piuttosto semplice modificare l'implementazione del container per attuare ottimizzazioni +necessarie a rispettare il requisito non funzionale~\ref{itm:nf1}. +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{./img/WorldDetail} + \caption{Design di dettaglio di \texttt{World} e \texttt{Entities}.} + \label{fig:world-detail} +\end{figure} + +\section{Builder dei sistemi}\label{sec:builder-dei-sistemi} +Si è scelto di realizzare il pattern Builder per permettere una creazione di sistemi quanto più semplice possibile. +Come mostrato nel diagramma riportato in Figura~\ref{fig:system-builder} il builder dispone di diversi +metodi per specificare l'implementazione di alcuni dei metodi del sistema che verrà costruito. +Per completare la costruzione tramite il builder e ottenere il nuovo sistema bisogna specificare +(tramite il metodo \texttt{withUpdate}) l'implementazione del suo metodo \texttt{update}. + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{./img/SystemBuilder} + \caption{Design di dettaglio del \texttt{SystemBuilder}.} + \label{fig:system-builder} +\end{figure} diff --git a/doc/5-implementation.tex b/doc/5-implementation.tex index c118a858..b43c11b7 100644 --- a/doc/5-implementation.tex +++ b/doc/5-implementation.tex @@ -1 +1,441 @@ -\chapter{Implementazione}\label{ch:implementazione} \ No newline at end of file +\chapter{Implementazione}\label{ch:implementazione} + +\section{Tecnologie utilizzate}\label{sec:tecnologie-utilizzate} +Per la realizzazione del framework non sono state utilizzate librerie esterne se non ScalaTest e +Scalafmt~\cite{scalafmt} - opportunamente configurato - per la formattazione del codice. +Si segnala inoltre che, a causa dell'incompatibilità con Scala 3, è stata utilizzata la libreria JaCoCo~\cite{jacoco} +invece di Scoverage. +Infine, non avendo individuato alcuna alternativa, non è stato possibile utilizzare Scalafix. + +\section{Suddivisione del lavoro}\label{sec:suddivisione-del-lavoro} +In questa sezione viene illustrata la suddivisione del lavoro e le parti di progetto realizzate da ciascun membro del +gruppo. + +\subsection{Cavalieri}\label{subsec:giacomo-cavalieri} +Il mio compito principale è stato quello di realizzare i \texttt{ComponentTag}, \texttt{CListTag}, +e il \texttt{ComponentsContainer} descritto precedentemente alla Sezione~\ref{sec:container-di-componenti}. +Inoltre ho collaborato con i miei colleghi alla realizzazione delle \texttt{CList}. + +\subsubsection{CList} +Nelle prime fasi di sviluppo ho cercato di risolvere il problema del garantire la type safety dei sistemi. +Mi sono inizialmente documentato su possibili meccanismi forniti dal linguaggio individuando nell'utilizzo delle +tuple una possibile soluzione. +Infatti, in Scala 3 le tuple possono fungere da meccanismo per ottenere liste eterogenee di elementi +preservando informazioni sul loro tipo~\cite{tuples}. +Tuttavia, questo ha comportato alcuni problemi come l'impossibilità di garantire a tempo di compilazione che le tuple +fossero composte di soli elementi sottotipi di \texttt{Component} +(\textit{i.e.} data la tupla $(T_1,\dots,T_n)$ garantire che $T_i <: \text{Component } \forall i=1,\dots,n$). +Per questo, prendendo ispirazione dall'approccio utilizzato nella libreria Shapeless~\cite{shapeless}, +ho individuato una possibile soluzione nell'adozione delle \texttt{CList}, realizzate in seguito +da Farabegoli con il mio aiuto. + +\subsubsection{ComponentTag} +Il framework realizzato utilizza in maniera pervasiva informazioni sui tipi dei componenti, necessarie +per la loro memorizzazione e manipolazione. +Per questo è stato realizzato il \texttt{ComponentTag}, ovvero un oggetto che mantiene informazioni riguardo +al tipo a tempo di compilazione di un componente; +in questo modo è stato possibile raggruppare componenti con lo stesso tipo inferito all'interno del +\texttt{ComponentsContainer}. + +Un altro aspetto fondamentale tenuto in considerazione è stato quello di garantire una certa semplicità di +utilizzo della libreria. +Infatti, sarebbe stato poco pratico per un utente dover specificare manualmente i \texttt{ComponentTag} +come argomenti dei metodi che ne necessitano la conoscenza. +Per ovviare a tale problema si sono sfruttati alcuni meccanismi avanzati offerti da Scala 3: +in particolare l'uso di \textit{macro}~\cite{macros}, \textit{inlining}~\cite{inline} +e \textit{given instances}~\cite{given-instances}. + +Tramite un semplice import (\texttt{import dev.atedeg.ecscala.given}) l'utente non deve preoccuparsi +della presenza dei \texttt{ComponentTag} che saranno generati automaticamente dal compilatore tramite +un'apposita macro riportata nel Listato~\ref{lst:component-tag}. + +\lstinputlisting[label={lst:component-tag}, caption=Macro per la generazione di un \texttt{ComponentTag}.] +{code/component-tag.sc} + +\subsubsection{CListTag} +In maniera analoga a quanto discusso per i \texttt{ComponentTag}, è stato definito un tag generato dal +compilatore tramite macro per le \texttt{CList}. +Infatti, è risultato fondamentale sfruttare la metaprogrammazione per effettuare controlli aggiuntivi +a livello di compilazione sulla correttezza delle \texttt{CList}. +Per esempio, non dev'essere possibile specificare una lista di +componenti con tipi ripetuti nella definizione di un sistema; +ciò non avrebbe senso dato che un'entità può avere al più un componente per tipo e si vuole impedire tale situazione +al momento della compilazione. + +L'implementazione di tali controlli è riportata al Listato~\ref{lst:clist-tag}. +\lstinputlisting[label={lst:clist-tag}, caption=Macro e controlli per la generazione di un \texttt{CListTag}.] +{code/clist-tag.sc} + +\subsubsection{Deletable CLists}\label{subsubsec:deletable} +Un sistema definito per alcuni tipi di componenti $T_{C1},\dots,T_{Cn}$ deve ritornare nel proprio metodo +\texttt{update} una \texttt{CList} di componenti dello stesso tipo che verranno usati per aggiornare lo stato +delle entità su cui il sistema può essere applicato. +Durante il processo di sviluppo è sorta la necessità di poter indicare la rimozione di un particolare componente +dall'entità: per esempio, il sistema di un videogioco che opera su entità dotate del componente \texttt{LifePoints} +potrebbe voler rimuovere tale componente una volta che questo scende a 0. + +La prima soluzione ideata avrebbe comportato la riscrittura delle \texttt{CList} in modo da utilizzare valori +opzionali per indicare la rimozione di un componente (\eg \texttt{Some(???)~\&:~None~\&:~CNil}). + +Una soluzione, a mio avviso più elegante, ha sfruttato due nuovi meccanismi introdotti in Scala 3: +i \textit{match types}~\cite{match-types} e gli \textit{union types}~\cite{union-types}. +Come mostrato nel Listato~\ref{lst:deletable} una versione ``deletable'' di una \texttt{CList} +\texttt{T1~\&:~...~\&:~TN~\&:~CNil} non è altro +che la lista stessa dove ogni elemento \texttt{Ti} viene sostituito da uno union type \texttt{(Ti | Deleted)}. +Dato che un tipo \texttt{T} è sottotipo di \texttt{T | Other} una \texttt{CList} sarà sottotipo della sua +equivalente versione \texttt{Deletable}. + +Così facendo l'utente può continuare a specificare una lista di componenti come valore di ritorno del metodo +\texttt{update} dei sistemi; +una sostanziale differenza sta nel fatto che, al posto di un qualunque componente, potrà specificare +il componente speciale \texttt{Deleted} ad indicare che il componente in tale posizione è +stato cancellato (\eg \texttt{C1~\&:~Deleted~\&:~CNil} indica che il secondo componente deve essere eliminato +durante l'aggiornamento di stato dell'entità). + +\lstinputlisting[label={lst:deletable}, caption=Implementazione del tipo \texttt{Deletable[L~<:~CList]}.] +{./code/deletable.scala} + +\subsection{Di Domenico}\label{subsec:nicolò-di-domenico} + +Il mio ruolo nel progetto è stato principalmente quello d'implementare le \texttt{View} e i \texttt{System}, nonché +applicare ove necessario eventuali ottimizzazioni per rispettare il requisito non funzionale~\ref{itm:nf1}. + +\subsubsection{View} + +Essendo le \texttt{View} ed \texttt{ExcludingView} progettate come indicato in Figura~\ref{fig:view}, si è rivelato +utile costruire un iteratore astratto che permettesse di fattorizzare tutto il codice comune. +In particolare si noti come la \texttt{ExcludingView} itera su un sottoinsieme delle entità ritornate dalla stessa +\texttt{View}, che invece non esprime vincoli di esclusione di componenti. +Per questo motivo è stato creato il \texttt{BaseViewIterator}, che si occupa di recuperare dal +\texttt{ComponentsContainer} tutte le mappe che associano ciascuna entità all'istanza (se presente) del componente di +ciascun tipo. +Infine, partendo da tali mappe, si occupa di testare l'appartenenza alla view di ciascuna entità e, in caso affermativo, +estrarne tutti i componenti richiesti. + +Una semplice ottimizzazione utilizzata per rendere più veloce l'iterazione di una \texttt{View} consiste +nell'individuare la mappa di componenti con meno elementi; +una volta trovata, si iterano tutte le entità contenute al suo interno e per ognuna si controlla che sia presente in +tutte le altre mappe. +In caso affermativo, si procede all'estrazione di tutti i suoi componenti richiesti. + +\begin{figure} + \includegraphics{./img/View} + \caption{Design di dettaglio di \texttt{View} ed \texttt{ExcludingView}.} + \label{fig:view} +\end{figure} + +\subsubsection{System} + +Un \texttt{System} è un blocco di codice che può essere aggiunto al \texttt{World} e viene chiamato a ogni aggiornamento +di stato della simulazione. +Ogni \texttt{System} ha due metodi: +\begin{itemize} + \item \texttt{shouldRun}: metodo booleano che indica se il \texttt{System} dev'essere eseguito + \item \texttt{update}: metodo che contiene il codice arbitrario da eseguire +\end{itemize} + +Su di esso sono stati costruiti \texttt{IteratingSystem} ed \texttt{ExcludingSystem}, due wrapper type-safe +rispettivamente per \texttt{View} ed \texttt{ExcludingView}. +Questi due sistemi definiscono i seguenti metodi: +\begin{itemize} + \item \texttt{shouldRun}: metodo booleano che indica se l'\texttt{IteratingSystem} dev'essere eseguito + \item \texttt{before}: metodo eseguito prima di iterare su tutte le entità con i componenti richiesti + \item \texttt{update}: metodo eseguito per ciascuna entità contenente le operazioni da effettuare sui suoi + componenti richiesti + \item \texttt{after}: metodo eseguito dopo aver iterato su tutte le entità con i componenti richiesti +\end{itemize} + +Il metodo \texttt{update} deve ritornare una \texttt{CList} dei nuovi componenti; +grazie all'utilizzo delle \texttt{CList} (descritte in dettaglio nella Sottosezione~\ref{subsec:farabegoli}) +verrà verificato a tempo di compilazione che i nuovi componenti abbiano lo stesso tipo di quelli su cui opera il +sistema. +Per permettere la cancellazione di alcuni dei componenti, è stato implementato un match type chiamato +\texttt{Deletable[L~<:~CList]} descritto nella Sottosezione~\ref{subsubsec:deletable}. + +L'\texttt{ExcludingSystem} è completamente analogo all'\texttt{IteratingSystem}, in quanto cambia solo la \texttt{View} +usata per ottenere le entità sulle quali iterare. + +\subsection{Farabegoli}\label{subsec:farabegoli} +Il contributo apportato al progetto ha toccato buona parte del core del framework, nonché lo sviluppo dei benchmark. +Mi sono infine occupato della gestione del repository, della CI, dei rilasci del framework e della qualità del codice. + +\subsubsection{CList} +La parte che mi ha conivolto in prima persona è stata la realizzazione delle \texttt{CList}. + +Una caratteristica importante della libreria è permettere di specificare nel tipo di un sistema (o di una vista) +su quali componenti questi operano, così che le stesse firme dei metodi possano guidare il programmatore indicando i +tipi dei componenti trattati. +Così facendo si elimina la necessità di specificare a tempo di esecuzione il tipo di componenti richiesto (come per +esempio è necessario fare nella libreria Ashely che ricorre al passaggio di oggetti \texttt{Class}) +permettendo d'intercettare diversi errori a tempo di compilazione. + +Come indicato nella Sezione~\ref{sec:lista-di-componenti}, l’idea alla base di questa soluzione è stata ispirata dalla +libreria Shapeless; +tuttavia, non si è potuto utilizzarla perché era fondamentale avere un vincolo aggiuntivo sul tipo degli +elementi della lista. +Infatti, tutti gli elementi di una \texttt{CList} devono essere sottotipi di \texttt{Component}. +Parte dell’implementazione è riportata al Listato~\ref{lst:lstinputlisting}. + +\lstinputlisting[label={lst:lstinputlisting}, caption={Esempio di codice per implementare \texttt{CList}.}]{code/clist.scala} + +Nella scrittura dei test delle \texttt{CList} è stato trovato un bug nella suite ScalaTest; +per una trattazione dettagliata del problema si veda la Sezione~\ref{sec:problemi-riscontrati}. + +\subsubsection{World ed Entity} +Una delle parti che ho seguito nelle prime fasi di sviluppo è stata l'implementazione del \texttt{World} e delle +\texttt{Entity}. +In particolare mi sono occupato di definire l'interfaccia di entrambe le classi e di fornire una prima implementazione +di base. +Ho quindi implementato il codice necessario affinché ogni entità avesse un identificativo univoco all'interno del mondo. +Infine, mi sono occupato dello sviluppo dei test per la verifica delle classi oggetto d'implementazione. + +\subsubsection{View} +Ho definito e implementato parzialmente la classe \texttt{View}: in particolare, ne ho realizzato l'interfaccia e +fornito una prima implementazione. +Sempre seguendo un approccio test-driven, ho realizzato anche i test necessari alla verifica del corretto funzionamento +delle classi sopra descritte. +Nell'ambito dello sviluppo delle view, Cavalieri e Di Domenico hanno sviluppato una macro per costruire la +view in modo che operi sui componenti effettivi passati nel generico; +in questa fase ho contribuito fornendo consigli e suggerimenti per una migliore implementazione del codice. + +\subsubsection{Benchmark} +Il requisito non funzionale~\ref{itm:nf1} fornisce una linea di base delle prestazioni che il framework deve rispettare; +a tal proposito ho definito una serie di benchmark per misurare le prestazioni di \texttt{View}, \texttt{System} e +dell'aggiornamento del \texttt{World}. +Mediante questi benchmark è stato possibile validare il requisito non funzionale~\ref{itm:nf1} sulla base di dati oggettivi. +Per una descrizione più approfondita dei benchmark si faccia riferimento alla Sezione~\ref{sec:benchmark}. + +\subsection{Vitali}\label{subsec:linda-vitali} +All'interno del team, oltre a quello di sviluppatrice, ho svolto anche il ruolo di product owner. +Dunque, mi sono occupata di supervisionare l'organizzazione del processo di sviluppo e di redigere +product backlog e sprint backlog al termine dei meeting, riportando quanto accordato insieme agli +altri membri. +Per quanto riguarda la parte di sviluppo del codice, mi sono occupata di una prima implementazione della classe +\texttt{Component}, del \texttt{ComponentsContainer} in collaborazione con Cavalieri e dell'\texttt{ECScalaDSL}. + +\subsubsection{Component}\label{subsubsec:component-desc} +\texttt{Component} è il trait che un utilizzatore del framework deve estendere per implementare le caratteristiche delle +proprie \texttt{Entity}. +Contiene il riferimento alla \texttt{Entity} a cui è stato aggiunto e un +\textit{extension method}~\cite{extensionmethods} per permettere la conversione in \texttt{CList}. + +\subsubsection{ComponentsContainer}\label{subsubsec:components-container} +Il \texttt{ComponentsContainer} descritto nella Sezione~\ref{sec:container-di-componenti} fornisce metodi per: +\begin{itemize} + \item Aggiungere \texttt{Component} a una \texttt{Entity} + \item Rimuovere \texttt{Component} da una \texttt{Entity} + \item Rimuovere \texttt{Entity} + \item Ottenere tutte le \texttt{Entity} e i rispettivi \texttt{Component} +\end{itemize} +Sebbene inizialmente fosse stata utilizzata una \texttt{HashMap} come struttura dati interna, in seguito si è optato per +una \texttt{AnyRefMap}, la quale, come descritto nella documentazione ufficiale~\cite{anyRefMap}, +è ``\textit{notevolmente più veloce di una HashMap}''. +Infatti, come si può osservare in Tabella~\ref{tab:componentscontainer-benchmark}, ha contribuito nel rispettare il +requisito non funzionale~\ref{itm:nf1}. + +\subsubsection{ECScalaDSL}\label{subsubsec:dsl-impl} +La realizzazione del DSL si è basata sulla necessità di rendere l'utilizzo del framework il più intuitivo possibile, +permettendo d'implementare le funzionalità di base del framework in un linguaggio che appaia simile alla lingua +inglese, come mostrato nel Listato~\ref{lst:dsl-withComp} e nel Listato~\ref{lst:dsl-view}. +Per farlo, ci si è ispirati al DSL \texttt{Matchers}~\cite{matchers} di ScalaTest. + +Per utilizzare la sintassi specifica e le parole chiave del DSL, l'utente deve estendere il trait \texttt{ECScalaDSL}, +abilitare le conversioni implicite (tramite \texttt{import scala.language.implicitConversions}) e importare i given del +framework\\(con \texttt{import dev.atedeg.ecscala.given}). + +\lstinputlisting[ + label={lst:dsl-withComp}, + caption=Esempio scritto con \texttt{ECScalaDSL} di creazione di un \texttt{World} che contiene una \texttt{Entity} + con i rispettivi \texttt{Component}. +]{code/dsl-withComp.scala} + +\lstinputlisting[ + label={lst:dsl-view}, caption=Esempio scritto con \texttt{ECScalaDSL} di come ottenere una \texttt{View} dal + \texttt{World} con uno specifico \texttt{Component} escludendone un altro. +]{code/dsl-view.scala} + +Le funzionalità del DSL sono state implementate facendo largo uso dei metodi come operatori infissi in modo tale +da rendere il codice simile a una frase. +Inoltre, sono stati utilizzati i seguenti meccanismi di Scala 3: +\begin{itemize} + \item \textbf{Extension methods:} utilizzato per abilitare sulla classe \texttt{Entity} i metodi + \texttt{withComponents} e sulla classe \texttt{World} i metodi \texttt{hasAn} e \texttt{hasA}. + Inoltre, è stato applicato il pattern \textit{Pimp My Library} per il metodo \texttt{withComponent} di + \texttt{Entity} e per abilitare metodi di aggiunta e rimozione con operatori a entrambe le classi sopracitate + \item \textbf{Context functions~\cite{contextfunctions}:} la funzionalità si è rivelata particolarmente utile per il + metodo \texttt{hasA}, usato per aggiungere un \texttt{System} al \texttt{World}. + Come si può notare nel Listato~\ref{lst:dsl-ctxf}, il metodo prende in ingresso una \textit{context function} che va + da \texttt{World} a \texttt{Unit}. + In questo modo il \texttt{World} viene passato implicitamente alla funzione che lo utilizza permettendo l'aggiunta + del \texttt{System} + \item \textbf{Conversioni implicite:} sono state implementate due conversioni implicite\\ + \texttt{componentToClist[C~<:~Component:~ComponentTag]:\\Conversion[C,~C~\&:~CNil]} + e \texttt{Conversion[Entity,~Seq[Entity]]} per evitare overloading di metodi +\end{itemize} + +\lstinputlisting[ + label={lst:dsl-ctxf}, + caption=Esempio di utilizzo di una context function nel metodo \texttt{hasA}. +]{code/dsl-ctxf.scala} + +Si è utilizzata una \textit{Type Class} \texttt{From} per realizzare la parte di sintassi che permette di effettuare +arbitrarie operazioni su \texttt{World} e \texttt{Entity} con il metodo \texttt{from} (parola chiave del DSL). +Come si può vedere nel diagramma in Figura~\ref{fig:from} è possibile specificare il tipo al quale si applica il metodo +\texttt{from} e il suo tipo di ritorno. +In questo modo, si può implementare la classe specifica per abilitare la sintassi necessaria di caso in caso. + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{./img/From} + \caption{Diagramma delle classi che mostra l'implementazione della type class \texttt{From}.} + \label{fig:from} +\end{figure} + +\section{Benchmark}\label{sec:benchmark} +Il framework deve rispettare il requisito non funzionale~\ref{itm:nf1}; +per questo motivo è stato necessario quantificare oggettivamente quali fossero le effettive prestazioni raggiunte. +I benchmark sono uno strumento piuttosto efficace per valutare i tempi di esecuzione (e non solo), fornendo +una stima delle prestazioni in gioco. + +Con il termine benchmark si intende un insieme di test specifici per misurare le prestazioni di un software o computer. +Al termine dell'esecuzione del benchmark si ottiene un indice indicativo delle prestazioni che il sistema in oggetto ha +raggiunto. +I benchmark possono essere raggruppati in due categorie: +\begin{itemize} + \item Sintetici (o microbenckmark): vanno a misurare le prestazioni di alcune parti specifiche di un sistema + \item Applicativi: misurano le prestazioni complessive di un sistema, ad esempio di un'applicazione +\end{itemize} + +Scrivere benchmark che misurano correttamente le prestazioni di solo una piccola parte di software è difficile: ci sono +diverse ottimizzazioni che la JVM e l'hardware sottostante sono in grado di fare quando il benchmark +esegue solo il componente~\cite{jmh:details}, ma tali ottimizzazioni non possono essere effettuate quando il componente +è eseguito come parte dell'intera applicazione, producendo dati falsati. +Implementazioni errate di benchmark possono far credere che le prestazioni dei componenti siano migliori di quanto non +siano in realtà. + +È quindi necessario ricorrere a un framework di benchmarking apposito per ottenere misurazioni affidabili. +Si è scelto di utilizzare Jmh~\cite{jmh} per implementare i microbenchmark necessari alla verifica del +requisito non funzionale~\ref{itm:nf1}. + +Il framework consente di definire in modo piuttosto semplice ma altamente configurabile i benchmark, come mostrato nel +Listato~\ref{lst:lstinputlisting4}. + +\lstinputlisting[label={lst:lstinputlisting4}, caption=Codice per eseguire il setup di un benchmark.] +{code/benchmark.scala} + +Alcuni parametri rilevanti nella configurazione dei benchmark sono: +\begin{itemize} + \item \texttt{@Warmup}: si specifica quante iterazioni devono essere eseguite ``a vuoto'' prima di effettuare i + test effettivi; + questa procedura risulta necessaria dal momento che, quando si esegue per la prima volta un programma sulla JVM, la + cache risulta vuota e quindi il caricamento iniziale delle classi è più lento. + Eseguendo più volte la stessa porzione di codice si ``stabilizza'' la cache, quindi gli accessi successivi saranno + più veloci e uniformi. + Inoltre, nelle JVM HotSpot, l'interprete tiene traccia del numero di volte che un metodo viene eseguito: se tale + numero supera una certa soglia allora viene identificato come \textit{hot method} (metodo che tipicamente ha dei + loop) e quindi è \textit{JIT compiled}~\cite{jmh:details}. + Chiamate successive all'ottimizzazione risulteranno quindi più veloci ed efficienti. + In questo modo si garantisce che le misurazioni successive alla fase di warm up abbiano valori simili senza essere + influenzate da condizioni esterne. + \item \texttt{@Measurement}: si specifica quante volte il benchmark debba essere ripetuto. + Per ogni esecuzione viene annotato il tempo impiegato e al termine dell'esecuzione viene riportato il tempo medio + che impiega il test. +\end{itemize} + +\subsection{Risultati}\label{subsec:risultati} +In Tabella~\ref{tab:system-benchmark} sono riportati i risultati riguardanti i \textit{System}, in cui si può osservare +che con $10\;000$ entità un sistema impiega mediamente cinque millisecondi a effettuarne l'aggiornamento, quindi il +requisito~\ref{itm:nf1} è ampiamente rispettato. +In Tabella~\ref{tab:componentscontainer-benchmark} sono riportati invece i risultati riguardanti il +\texttt{ComponentsContainer}, sia nella sua versione mutabile che immutabile. + +\begin{table}[htp] + \centering + \begin{tabular}{c c} + \toprule + Numero entità & Tempo (ms) \\ \midrule + $1024$ & $0.502 \pm 0.007$ \\ + $2048$ & $1.013 \pm 0.018$ \\ + $4096$ & $2.258 \pm 0.054$ \\ + $10\;000$ & $5.413 \pm 0.074$ \\ + \bottomrule + \end{tabular} + \caption{Risultati benchmark sui \texttt{System}.}\label{tab:system-benchmark} +\end{table} + +\begin{table}[htp] + \centering + \begin{tabular}{c c c c} + \toprule + Numero entità & Tempo (ms) (imm.) & Tempo (ms) (mut.) & Speedup \\ \midrule + $1024$ & $0.771 \pm 0.003$ & $0.498 \pm 0.002$ & $1.548 \pm 0.012$ \\ + $2048$ & $1.603 \pm 0.007$ & $0.969 \pm 0.004$ & $1.654 \pm 0.014$ \\ + $4096$ & $3.341 \pm 0.015$ & $2.224 \pm 0.014$ & $1.502 \pm 0.016$ \\ + $10\;000$ & $8.216 \pm 0.047$ & $5.416 \pm 0.034$ & $1.517 \pm 0.018$ \\ + \bottomrule + \end{tabular} + \caption{Risultati benchmark sul \texttt{ComponentsContainer}.}\label{tab:componentscontainer-benchmark} +\end{table} + +A fronte dei risultati ottenuti dai benchmark si può affermare che il framework fornisce buone prestazioni con un +discreto numero di entità. + +\section{Problemi riscontrati}\label{sec:problemi-riscontrati} + +\subsection{Scalatest}\label{subsec:scalatest} +Nella libreria ScalaTest è stato riscontrato un bug nella sintassi \texttt{shouldNot typeCheck}. +Tramite questa espressione, dovrebbe essere possibile verificare che una porzione di codice, specificata come stringa, +non compili a causa di un errore nel processo di type checking. +Questo controllo risulta utile nel verificare la corretta destrutturazione delle~\texttt{CList} tramite +pattern matching. +In particolare si è verificato, tramite il codice riportato nel Listato~\ref{lst:lstinputlisting22}, che la +destrutturazione di una \texttt{CList} di dimensione diversa da quanto atteso porti ad un errore di compilazione. +A tal proposito si è definito il test indicato nel Listato~\ref{lst:lstinputlisting22}: +\lstinputlisting[ + label={lst:lstinputlisting22}, + caption=Test per la verifica dell'unpacking delle \texttt{CList}. +] +{./code/scalatest-bug.scala} +La prima asserzione verifica che la destrutturazione fallisca se si specificano meno elementi di quanti siano +effettivamente presenti nella lista; +nella seconda si testa lo scenario opposto, ovvero che la destrutturazione fallisca se la lista contiene meno elementi +di quanti ne sono stati specificati nel pattern matching. +Sebbene in entrambi i casi ci si aspetta che le espressioni non compilino a causa di errori nella fase di +type checking, questo non accade e le espressioni vengono erroneamente valutate come valide. +Il bug è stato segnalato agli sviluppatori della libreria mediante una issue~\cite{scalatest-bug}. + +\subsection{Cross-building per Scala.js}\label{subsec:cross-building-per-scala.js} +Sin dalle prime fasi di sviluppo si è abilitata la modalità di \textit{cross-building}~\cite{cross-building} affinché il +framework venisse compilato anche per Scala.js~\cite{scalajs}. +Questo ha generato una serie di falsi errori all'interno dell'IDE (IntelliJ). +Infatti se si eseguivano i comandi di Sbt per la compilazione del progetto, quest'ultimo non sollevava alcun errore. +A tal proposito è stata aperta una issue~\cite{intellij-issue} sul bug tracker di Jetbrains. +Per una maggiore agilità nella scrittura del codice si è quindi scelto di rimuovere la cross-building dal progetto. + +\subsection{System Builder}\label{subsec:system-builder} +La funzione di \texttt{update} di un sistema specifica diversi parametri (il \texttt{World} in cui il sistema è +eseguito, la \texttt{View} contenente tutte le entità, i componenti dell'entità che sta venendo modificata, eccetera); +tuttavia, spesso l'implementazione del metodo \texttt{update} necessiterà di solo alcuni dei parametri elencati. +Per questo motivo, inizialmente si è cercato di realizzare un builder che permettesse di costruire dinamicamente la +firma della funzione richiesta per costruire il sistema, permettendo una sintassi simile a quella riportata al +Listato~\ref{lst:builder-syntax}. + +\lstinputlisting[label={lst:builder-syntax}, caption=Sintassi del builder per la creazione di sistemi.] +{./code/builder-syntax.sc} + +Questo ha portato a individuare un problema nel compilatore Dotty che ha impedito di portare a compimento un simile +builder. +Infatti, a causa del problema, sarebbe stato necessario indicare un'annotazione di tipo nei parametri della +funzione la cui firma è stata costruita dinamicamente (un esempio è riportato al Listato~\ref{lst:builder-syntax-bug}); +questo avrebbe comportato la scrittura di codice particolarmente verboso in contrasto con l'intento originale che aveva +portato a ideare tale builder. + +Il bug~\cite{dotty-bug} è stato segnalato nelle issue del repository GitHub del compilatore Dotty +ed è stato recentemente risolto. + +\lstinputlisting[ + label={lst:builder-syntax-bug}, + caption={Sintassi effettiva del builder, + si notino le annotazioni di tipo ridondanti ma necessarie per la compilazione del codice.} +] +{./code/builder-syntax-bug.sc} diff --git a/doc/6-demo.tex b/doc/6-demo.tex new file mode 100644 index 00000000..bf5317ba --- /dev/null +++ b/doc/6-demo.tex @@ -0,0 +1,348 @@ +\chapter{Demo}\label{ch:demo} + +\section{Requisiti}\label{sec:demo-requisiti} + +\subsection{Business}\label{subsec:demo-business} +L'obiettivo della demo è quello di permettere all'utente di avere una dimostrazione di applicazione del framework +ECScala. +Per farlo, si deve realizzare la simulazione del moto di palle da biliardo su un tavolo da gioco per la quale è +stato individuato il seguente requisito di business: +\begin{enumerate}[label=\textbf{\ref{subsec:demo-business}.\arabic*}] + \item \label{itm:db1} Deve essere messa a disposizione un'interfaccia grafica che mostri e permetta d'interagire + con la simulazione. +\end{enumerate} + +\subsection{Utente}\label{subsec:demo-utente} +I requisiti utente sono di seguito riportati sotto forma di \textit{user stories}, secondo lo schema +``\textit{As a [persona], I [want to], [so that]}''. +\begin{table}[H] + \begin{tabular}{p{0.18\linewidth}p{0.76\linewidth}} + \toprule + \textbf{User-story 1} & \\ + \textbf{Who} & Come utilizzatore della demo \\ + \textbf{What} & Vorrei avviare facilmente la simulazione senza dover inserire parametri \\ + \textbf{Why} & Per osservare il movimento delle palle da biliardo \\ + \bottomrule + \end{tabular}\label{tab:user-story-1} +\end{table} +\begin{table}[H] + \begin{tabular}{p{0.18\linewidth}p{0.76\linewidth}} + \toprule + \textbf{User-story 2} & \\ + \textbf{Who} & Come utilizzatore della demo \\ + \textbf{What} & Vorrei poter aggiungere più palle da biliardo sul tavolo \\ + \textbf{Why} & Per verificare l'interazione con quelle già presenti \\ + \bottomrule + \end{tabular}\label{tab:user-story-2} +\end{table} +\begin{table}[H] + \begin{tabular}{p{0.18\linewidth}p{0.76\linewidth}} + \toprule + \textbf{User-story 3} & \\ + \textbf{Who} & Come utilizzatore della demo \\ + \textbf{What} & Vorrei poter cambiare la velocità delle palle da biliardo \\ + \textbf{Why} & Per cambiarne la direzione e far muovere quelle ferme \\ + \bottomrule + \end{tabular}\label{tab:user-story-3} +\end{table} +\begin{table}[H] + \begin{tabular}{p{0.18\linewidth}p{0.76\linewidth}} + \toprule + \textbf{User-story 4} & \\ + \textbf{Who} & Come utilizzatore della demo \\ + \textbf{What} & Vorrei poter modificare i coefficienti di frizione e restituzione \\ + \textbf{Why} & Per osservare come cambia il movimento delle palle da biliardo \\ + \bottomrule + \end{tabular}\label{tab:user-story-4} +\end{table} +\begin{table}[H] + \begin{tabular}{p{0.18\linewidth}p{0.76\linewidth}} + \toprule + \textbf{User-story 5} & \\ + \textbf{Who} & Come utilizzatore della demo \\ + \textbf{What} & Vorrei un tasto reset \\ + \textbf{Why} & Per riavviare la simulazione \\ + \bottomrule + \end{tabular}\label{tab:user-story-5} +\end{table} + +\subsection{Funzionali}\label{subsec:demo-funzionali} +Di seguito si elencano i requisiti funzionali individuati per il funzionamento della demo: +\begin{enumerate}[label=\textbf{\ref{subsec:demo-funzionali}.\arabic*}] + \item \label{itm:df1} Gestire le collisioni tra le palle e i bordi dell'interfaccia grafica oltre che le collisioni + tra le stesse. + \item \label{itm:df2} Tenere conto della frizione nel calcolo della velocità + \item \label{itm:df3} Renderizzare le palle da biliardo iniziali + \item \label{itm:df4} Permettere cambio di velocità + \item \label{itm:df5} Permettere l'aggiunta di palle + \item \label{itm:df6} Permettere di spostare palle +\end{enumerate} + + +\section{Design architetturale}\label{sec:demo-design-architetturale} +A seguito dell'analisi dei requisiti definiti nella sezione precedente, si è realizzato il design architetturale di +massima riportato in Figura~\ref{fig:demo-architechture}. + +Il pattern architetturale scelto è ECS, poiché si presta bene a questo genere di applicazioni. +Come mostrato in Figura~\ref{fig:demo-architechture}, si possono individuare alcuni sistemi fondamentali: +\begin{itemize} + \item \textbf{RenderSystem:} per effettuare il rendering dei diversi elementi grafici + \item \textbf{FrictionSystem:} per considerare l'apporto dell'attrito nel movimento delle palle + \item \textbf{CollisionSystem:} per gestire le collisioni delle palle + \item \textbf{BallCreationSystem:} per aggiungere nuove palle + \item \textbf{BallEditingSystem:} per modificare velocità o posizione delle palle + \item \textbf{BallSelectionSystem:} per selezionare delle palle +\end{itemize} + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{./img/DemoArchitecture} + \caption{Design architetturale della demo.} + \label{fig:demo-architechture} +\end{figure} + +\section{Design di dettaglio}\label{sec:demo-design-di-dettaglio} +È stato ulteriormente approfondito il design architetturale dividendo i sistemi in sistemi più piccoli +dai compiti ben circoscritti. +Il design di dettaglio finale è riportato in Figura~\ref{fig:demo-detail}, +tutti i sistemi individuati sono: +\begin{itemize} + \item \textbf{AutoPauseSystem:} mette in automatico il gioco in pausa quando nessuna palla è più in movimento + \item \textbf{BallCreationRenderingSystem:} si occupa di renderizzare la fase di creazione di una nuova palla + \item \textbf{BallCreationSystem:} aggiunge una nuova palla al mondo + \item \textbf{BallSelectionSystem:} seleziona una palla quando viene cliccata + \item \textbf{ClearCanvasSystem:} pulisce il canvas a ogni frame + \item \textbf{CollisionSystem:} calcola le nuove velocità di eventuali entità che collidono fra loro + \item \textbf{FrictionSystem:} calcola le nuove velocità considerando il coefficente di frizione + \item \textbf{MovementSystem:} calcola le nuove posizioni delle palle + \item \textbf{RegionAssignmentSystem:} assegna le palle a specifiche regioni del canvas + \item \textbf{RenderSystem:} effettua il rendering delle palle + \item \textbf{VelocityArrowSystem:} disegna il vettore della velocità quando si modifica la velocità a una palla + \item \textbf{VelocityEditingSystem:} assegna il nuovo valore di velocità a una palla + \item \textbf{WallCollisionSystem:} gestisce le collisioni delle palle con i muri +\end{itemize} + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{./img/Demo} + \caption{Design di dettaglio della demo, i sistemi sono stati esplosi in sistemi più piccoli dai compiti ben circoscritti.} + \label{fig:demo-detail} +\end{figure} + +Inoltre, per ridurre la complessità nell'implementazione dei sistemi si è deciso di demandare la gestione della +posizione delle palle nello spazio bidimensionale allo \texttt{SpacePartitionContainer}. +Sono state realizzate due interfaccie che separano le operazioni di modifica da quelle di lettura dello stato; +in questo modo si può garantire che solo i sistemi che hanno bisogno di aggiungere elementi al container possano +effettivamente farlo. +Una trattazione più approfondita della logica di funzionamento del container si trova alla +Sottosezione~\ref{subsubsec:container}. + +\subsection{Macchina a stati finiti}\label{subsec:macchina-a-stati-finiti} +Le macchine a stati finiti (FSM) consentono di descrivere formalmente il comportamento di un sistema. +Si è quindi scelto tale formalismo per descrivere il funzionamento della simulazione. + +Sono stati identificati sei stati: \textit{Pause}, \textit{Play}, \textit{Add Balls}, \textit{Select Ball}, +\textit{Change Velocity} e \textit{Dragging}. +A seguito della definizione degli stati del sistema, sono stati definiti i loro eventi di transizione. +Di seguito viene riportata la descrizione di tali eventi: +\begin{itemize} + \item \texttt{PlayPauseBtn.clicked}: rappresenta la pressione del pulsante per eseguire o mettere in pausa la + simulazione + \item \texttt{AddBallBtn.clicked}: rappresenta la pressione del pulsante per l'aggiunta di palle alla simulazione + \item \texttt{ChangeVelBtn.clicked}: rappresenta la pressione del pulsante per cambiare la velocità a una palla + \item \texttt{Ball.selected}: rappresenta l'evento di selezione di una palla + \item \texttt{Mouse.clicked}: rappresenta il singolo click del mouse + \item \texttt{Mouse.dragging}: rappresenta l'evento di trascinamento del mouse + \item \texttt{Mouse.released}: rappresenta l'evento di rilascio del tasto del mouse +\end{itemize} + +In Figura~\ref{fig:fsm-demo} viene riportata la macchina a stati finiti utilizzata per descrivere il comportamento +della simulazione. + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{img/fsm-demo} + \caption{Macchina a stati finiti che modella il flusso di esecuzione della demo.}\label{fig:fsm-demo} +\end{figure} + +In una prima implementazione della demo si erano definiti oggetti globali che mantenessero lo stato della simulazione. +Ben presto ci si è resi conto della difficoltà nel gestire tutte le combinazioni dei campi dell'oggetto, oltre +ai vari bug che si verificavano durante l'implementazione della demo. +L'introduzione della macchina a stati ha portato diversi vantaggi: si è semplificata la gestione dello +stato della simulazione, le precondizioni di esecuzione dei sistemi fanno riferimento allo stato della FSM e non più +alla combinazione di più variabili booleane e la logica di aggiornamento dei componenti della GUI si è semplificata +notevolmente. +Grazie alla FSM è stato implementato un testing esaustivo delle precondizioni dei sistemi, esaminando tutte +le possibili configurazioni della FSM in unione agli eventi del mouse. +In questo modo è stato possibile individuare piccoli bug nell'implementazione dei sistemi. + +\subsection{ECSCanvas}\label{subsec:ecscanvas} +Per non legarsi ad una specifica libreria grafica, si è deciso di introdurre una classe che esponesse metodi di alto livello +per disegnare le primitive necessarie (in particolare cerchio e linea) e ottenere le dimensioni dell'aria di disegno. +È stato inoltre deciso di introdurre il pattern Façade, descritto in Figura~\ref{fig:facade}, per nascondere la complessità della libreria ScalaFX e, +in particolare, della classe \texttt{Canvas}. + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{img/Facade} + \caption{Utilizzo del pattern façade nella demo.}\label{fig:facade} +\end{figure} + +\section{Implementazione}\label{sec:demo-implementazione} +Di seguito si riportano gli aspetti implementativi che meritano una trattazione più approfondita. + +\subsection{Tecnologie utilizzate}\label{subsec:demo-tecnologie-utilizzate} +Anche per l'implementazione della demo ci sono stati problemi di incompatibilità con Scala 3: +in particolare è stata usata la libreria Mockito~\cite{mockito} invece di ScalaMock e non è stato possibile utilizzare +ScalaFXML che avrebbe fornito una sintassi idiomatica per usare JavaFX da Scala\@. +Per la realizzazione dell'interfaccia grafica è stata utilizzata la libreria ScalaFX~\cite{scalafx}\@. + +\subsection{Cavalieri}\label{subsec:demo-cavalieri} +\subsubsection{Test dei sistemi} +Ogni sistema descritto nella Sezione~\ref{sec:demo-design-di-dettaglio} ha una specifica precondizione d'esecuzione +che determina, in base allo stato del gioco e allo stato del mouse, se il sistema può essere eseguito. +Testare tutte le possibili combinazioni di stato del gioco e stato del mouse avrebbe comportato la scrittura di codice +molto ripetitivo. +Perciò mi sono occupato di realizzare dei test che verificassero automaticamente che ogni sistema +fosse abilitato unicamente negli stati indicati e disabilitato in tutti i rimanenti. + +La scrittura di un test delle precondizioni si limita quindi a indicare un costruttore del sistema in esame e +gli stati in cui questo dev'essere abilitato. +Un esempio di tale codice è riportato al Listato~\ref{lst:demo-prec-test} + +\lstinputlisting[label={lst:demo-prec-test}, + caption=Esempio di test della correttezza delle precondizioni di un sistema.] +{code/demo-precondition-test.scala} + +Il metodo \texttt{checkAllStates} utilizza un approccio di \textit{table-driven property testing} per effettuare +una scansione esaustiva di tutti i possibili stati e verificare che il sistema sia abilitato solo in quelli indicati. + +\subsubsection{Test della GUI} +Un altro aspetto importante è stato verificare che la GUI realizzata rispettasse gli stati e le transizioni indicate +dalla FSM riportata in Figura~\ref{fig:fsm-demo}; +per testare automaticamente la GUI è stata utilizzata la libreria TestFX~\cite{testfx}. + +Dato uno stato della FSM vengono specificati alcuni elementi: +\begin{itemize} + \item Le interazioni da svolgere con la GUI per raggiungere tale stato + \item Quali bottoni devono essere abilitati o disabilitati nello stato + \item Quali stati ulteriori possono essere raggiunti e, per ognuno di questi, quali interazioni devono essere svolte + con la GUI per raggiungerlo +\end{itemize} +Date queste informazioni, un test risulta essere piuttosto semplice: viene raggiunto lo stato in esame, si verifica che +i bottoni siano nella configurazione richiesta e si controlla che tutti gli altri stati indicati siano effettivamente +raggiungibili svolgendo le operazioni indicate. + +\subsection{Farabegoli}\label{subsec:demo-farabegoli} +\subsubsection{Game loop} +Il \textit{game loop} è il ciclo infinito che si occupa di eseguire tutti i sistemi dell'applicazione a ogni frame. + +Mi sono occupato della sua realizzazione facendo uso della classe \texttt{AnimationTimer} già presente in ScalaFX\@. +Tale classe consente di eseguire del codice implementandolo nel metodo \texttt{handle}. +Questo metodo viene chiamato a ogni frame: un frame è renderizzato ogni $\approx16.6$ millisecondi per garantire 60 FPS +(Frames Per Second). +Il limite di 60 FPS è automaticamente garantito dalla classe, quindi non è necessario implementare una logica +di limitazione degli FPS\@. + +La suddetta classe è stata concepita per essere utilizzata in un contesto OOP, per questa ragione è una classe astratta +che forza l'implementazione del metodo \texttt{handle}. +Ho quindi deciso di trasformare la classe affinché avesse un comportamento più funzionale. +A tal proposito ho creato un wrapper attorno alla classe per consentire di specificare l'handler del metodo direttamente +dal costruttore della classe mediante passaggio di funzione. + +Nel Listato~\ref{lst:lstinputlisting3} è illustrato come è stato effettuato il wrapping della classe +\texttt{AnimationTimer}; per semplicità è stata omessa la parte di calcolo degli FPS\@. + +\lstinputlisting[ + label={lst:lstinputlisting3}, + caption=Esempio d'implementazione del game loop mediante la classe \texttt{AnimationTimer}. +]{code/game-loop.scala} + +Con l'\texttt{apply} è possibile specificare, mediante una lambda, il codice che deve essere eseguito a ogni +frame. +Con i metodi \texttt{start} e \texttt{stop} è possibile rispettivamente eseguire il game loop e fermarlo. + +\subsubsection{FSM} +Mi sono occupato di realizzare la macchina a stati per gestire la logica del simulatore. +Per una trattazione dettagliata fare riferimento alla Sezione~\ref{subsec:macchina-a-stati-finiti} + +\subsubsection{Interfaccia utente} +Mi sono occupato della realizzazione del'interfaccia grafica del simulatore; +a tal proposito si è fatto uso della libreria ScalaFX, la quale offre un DSL per la creazione d'interfaccie grafiche. + +L'interfaccia si compone di una singola finestra che mostra una serie di bottoni per far interagire l'utente con la +simulazione, oltre a un pannello composto da due slider che consentono di configurare parametri di simulazione. +Al centro della finestra è presente un canvas che renderizza gli oggetti della simulazione. +L'interfaccia utente è stata sviluppata affinché risulti intuitiva e fornisca la massima semplicità d'uso all'utente. + +\subsection{Di Domenico}\label{subsec:demo-di-domenico} + +\subsubsection{Collision System}\label{subsubsec:container} +Il sistema principale che gestisce la simulazione è il \texttt{CollisionSystem}: questo implementa i calcoli necessari +per testare se c'è una collisione fra due corpi e, in caso affermativo, calcolarne le nuove velocità. + +Sarebbe necessario controllare tutte le possibili coppie di corpi, ma questo presenta due importanti problemi: +\begin{itemize} + \item ogni coppia di entità compare due volte anziché una + \item la gran parte delle coppie di entità non porterà a una collisione, essendo troppo distanti fra loro +\end{itemize} + +La soluzione a entrambi questi problemi è stata quella di applicare la tecnica di ottimizzazione detta +\textit{space partitioning}: si divide lo spazio (il piano in questo caso, essendo una simulazione 2D) in regioni +disgiunte affinché ogni entità appartenga a una e una sola di esse. + +\subsubsection{SpacePartitionContainer} +Per ottimizzare i test di collisione è stato creato lo \texttt{SpacePartitionContainer}, che prende in ingresso +un'entità con tutti i componenti richiesti e la salva in una mappa che associa ogni regione (identificata da una coppia +di numeri interi) alla lista di entità che ne fanno parte. +Inoltre, lo \texttt{SpacePartitionContainer} dispone di un metodo per ottenere tutte le entità facenti parte di una +regione specificata e uno per iterare su tutte le regioni non vuote. + +A questo punto, il \texttt{CollisionSystem} può diventare molto più efficiente: ora è sufficiente iterare su tutte le +regioni non vuote e testare le collisioni solo fra entità che fanno parte di un intorno bidimensionale di quelle +regioni, come mostrato in Figura~\ref{fig:space-partition}. +Per non processare due volte le coppie di entità, si costruiscono tutte le possibili combinazioni di lunghezza 2 e si +considera solo una metà dell'intorno, mentre l'altra verrà coperta nelle successive iterazioni delle regioni non vuote. + +\begin{figure}[H] + \centering + \begin{tikzpicture} + \fill[red!15!white] (1.5, 6) rectangle (3, 1.5); + \fill[red!15!white] (3, 6) rectangle (4.5, 4.5); + \fill[yellow!25!white] (3, 4.5) rectangle (4.5, 3); + \draw[step=1.5cm,gray,thin] (0, 0) grid (7.5, 7.5); + \draw[thick,->] (0, 7.5) -- (7.5, 7.5) node[above=2mm] {x}; + \draw[thick,->] (0, 7.5) -- (0, 0) node[left=2mm] {y}; + \foreach \x [count=\i from 0] in {0, 1.5, 3, 4.5, 6} + \draw (0.75+\x, 7.6) -- (0.75+\x, 7.4) node[above=2mm]{$\i$}; + \foreach \y [count=\i from 0] in {0, 1.5, 3, 4.5, 6} + \draw (-0.1, 6.75-\y) -- (0.1, 6.75-\y) node[left=2mm]{$\i$}; + \draw (3.75, 4.2) circle (0.75cm); + \filldraw[black] (3.75, 4.2) circle (2pt) node[anchor=west]{$C_1$}; + \draw (2.55, 5.1) circle (0.75cm); + \filldraw[black] (2.55, 5.1) circle (2pt) node[anchor=west]{$C_2$}; + \draw (2.1, 2.1) circle (0.75cm); + \filldraw[black] (2.1, 2.1) circle (2pt) node[anchor=west]{$C_3$}; + \draw (6.5, 6.5) circle (0.75cm); + \filldraw[black] (6.5, 6.5) circle (2pt) node[anchor=west]{$C_4$}; + \end{tikzpicture} + \caption{La regione in esame $(2, 2)$ controllerà solo se c'è collisione fra i cerchi con centro nelle regioni + limitrofe (l'area rossa); + si considera solo metà intorno per non contare due volte le coppie nelle iterazioni successive; + si testerà quindi la collisione fra $C_1$ e $C_2$ e fra $C_1$ e $C_3$, mentre $C_4$ non viene preso in + considerazione.} + \label{fig:space-partition} +\end{figure} + +\subsection{Vitali}\label{subsec:demo-vitali} +Nella parte di demo, oltre a \texttt{MovementSystem}, \texttt{FrictionSystem} e \texttt{RenderSystem}, +mi sono occupata di una prima implementazione del \texttt{SimulationStatus}, che in seguito è stato adattato da +Farabegoli alla FSM sopra descritta. +Inoltre, ho implementato il trait \texttt{ECSCanvas}, descritto in Sezione~\ref{subsec:ecscanvas} che fornisce metodi per: +\begin{itemize} + \item Disegnare un cerchio e una linea + \item Ottenere le dimensioni dell'area di disegno + \item Ripristinare l'area di disegno +\end{itemize} +Per il caso in esame, essendo stata scelta la libreria ScalaFX, ho realizzato anche la classe concreta +\texttt{ScalaFXCanvas} che estende il trait. diff --git a/doc/6-retrospective.tex b/doc/6-retrospective.tex deleted file mode 100644 index 00d50f04..00000000 --- a/doc/6-retrospective.tex +++ /dev/null @@ -1,49 +0,0 @@ -\chapter{Retrospettiva}\label{ch:retrospettiva} -\section{Sprint 1}\label{sec:sprint-1} -\begin{description} - \item [Svolgimento e sviluppo] Sfruttando il plugin \texttt{sbt-github-actions} sono state generati file per la configurazione della continuous integration. - I membri del gruppo hanno approfondito la conoscenza del pattern ECS, alcune caratteristiche distintive di Scala 3. - Si è configurato \texttt{scalafmt} per garantire uno stile uniforme nello sviluppo del progetto. - Infine, è stato realizzato un design architetturale di massima. - \item [Considerazioni finali] Lo sprint si è concluso nei tempi previsti e senza evidenziare particolari problematiche. -\end{description} -\section{Sprint 2}\label{sec:sprint-2} -\begin{description} - \item[Svolgimento e sviluppo] Il secondo sprint è stato incentrato sulla realizzazione del design di dettaglio di World ed Entity. - Sono stati implementati i principali metodi per l'aggiunta e rimozione dei componenti. - È stata anche implementata la struttura dati \texttt{IterableMap}. - \item[Considerazioni finali] Uno dei product backlog item (As a framework user I want to define World's views) non è stato concluso - in tempo e pertanto è stato rimandato allo sprint successivo. - I rimanenti product backlog item sono stati conclusi nei tempi prestabiliti. -\end{description} -\section{Sprint 3}\label{sec:sprint-3} -\begin{description} - \item[Svolgimento e sviluppo] Durante lo sprint è stata completata l'implementazione delle \texttt{View} e realizzata una prima versione del DSL\@. - Poiché grazie all'implementazione delle \texttt{View} il cuore della libreria può considerarsi concluso, sono stati realizzati dei benchmark - per verificare il rispetto del requisito non funzionale~\ref{itm:nf1} ottenendo discreti risultati preliminari. - \item[Considerazioni finali] Al termine dello sprint è emerso un problema implementativo che ha comportato un aumento significativo nello sforzo - stimato per completare due dei backlog item (As a framework user I want to define and use Systems e As a framework user I want to update the World's state); - perciò è stato spostato allo sprint successivo. -\end{description} -\section{Sprint 4}\label{sec:sprint-4} -\begin{description} - \item[Svolgimento e sviluppo] Il team si è focalizzato sulla realizzazione dei \texttt{System} i quali hanno richiesto uno sforzo condiviso e collaborazione fra i vari membri. - In questo modo - è stato possibile risolvere le problematiche emerse senza ulteriori ritardi. - Allo stesso tempo si è proseguito con la realizzazione del DSL\@. - \item[Considerazioni finali] Lo sprint si è concluso senza problemi da evidenziare. -\end{description} -\section{Sprint 5}\label{sec:sprint-5} -\begin{description} - \item[Svolgimento e sviluppo] Non avendo fin'ora riscontrato ritardi significativi nello sviluppo, il team ha deciso di aggiungere meno item allo sprint per poter conciliare impegni accademici. - Sono stati implementati \texttt{ExcludingView} ed \texttt{ExcludingSystem} ed è stato arricchito il DSL per permettere l'aggiunta di \texttt{System} e la rimozione di \texttt{Component}. - \item[Considerazioni finali] Lo sprint si è concluso evidenziando incosistenze nella sintassi del DSL che saranno corrette nel prossimo sprint. - Inoltre, intendiamo fare refactoring dell'interfaccia di \texttt{World} che secondo noi ha margini di miglioramento ma essendo una modifica consistente non poteva essere completata in questo sprint. -\end{description} -\section{Sprint 6}\label{sec:sprint-6} -\begin{description} - \item[Svolgimento e sviluppo] Lo sprint si è focalizzato principalmente sulla definizione dell'architettura per la demo. - Inoltre, sono state apportate migliorie alla sintassi del DSL ed è stata semplificata l'interfaccia del \texttt{World}. - Infine, è stato effettuato il primo rilascio della libreria dal momento che sono state implementate tutte le funzionalità minime necessarie. - \item[Considerazioni finali] Abbiamo deciso di spostare uno degli sprint item (Refactor World's interface) a quello successivo, in quanto ritenuto di bassa priorità. -\end{description} diff --git a/doc/7-retrospective.tex b/doc/7-retrospective.tex new file mode 100644 index 00000000..a1f21e4b --- /dev/null +++ b/doc/7-retrospective.tex @@ -0,0 +1,91 @@ +\chapter{Retrospettiva}\label{ch:retrospettiva} +\section{Sprint 1}\label{sec:sprint-1} +\begin{description} + \item [Svolgimento e sviluppo] Sfruttando il plugin \texttt{sbt-github-actions} sono stati generati i file per la + configurazione della CI\@. + I membri del gruppo hanno approfondito la conoscenza del pattern ECS, alcune caratteristiche distintive di Scala 3. + Si è configurato Scalafmt per garantire uno stile uniforme nello sviluppo del progetto. + Infine, è stato realizzato un design architetturale di massima. + \item [Considerazioni finali] Lo sprint si è concluso nei tempi previsti e senza evidenziare particolari + problematiche. +\end{description} +\section{Sprint 2}\label{sec:sprint-2} +\begin{description} + \item[Svolgimento e sviluppo] Il secondo sprint è stato incentrato sulla realizzazione del design di dettaglio di + \texttt{World} ed \texttt{Entity}. + Sono stati implementati i principali metodi per l'aggiunta e rimozione dei componenti. + \item[Considerazioni finali] Uno dei product backlog item + \textit{``As a framework user I want to define World's views''} non è stato concluso in tempo e pertanto è stato + rimandato allo sprint successivo. + I rimanenti product backlog item sono stati conclusi nei tempi prestabiliti. +\end{description} +\section{Sprint 3}\label{sec:sprint-3} +\begin{description} + \item[Svolgimento e sviluppo] Durante lo sprint è stata completata l'implementazione delle \texttt{View} e + realizzata una prima versione del DSL\@. + Poiché grazie all'implementazione delle \texttt{View} il cuore della libreria può considerarsi concluso, sono stati + realizzati dei benchmark per verificare il rispetto del requisito non funzionale~\ref{itm:nf1} ottenendo discreti + risultati preliminari. + \item[Considerazioni finali] Al termine dello sprint è emerso un problema implementativo che ha comportato un + aumento significativo nello sforzo stimato per completare due dei backlog item + \textit{``As a framework user I want to define and use Systems''} e + \textit{``As a framework user I want to update the World's state''}; + perciò sono stati spostati allo sprint successivo. +\end{description} +\section{Sprint 4}\label{sec:sprint-4} +\begin{description} + \item[Svolgimento e sviluppo] Il team si è focalizzato sulla realizzazione dei \texttt{System}, i quali hanno + richiesto uno sforzo condiviso e collaborazione fra i vari membri. + In questo modo è stato possibile risolvere le problematiche emerse senza ulteriori ritardi. + Allo stesso tempo si è proseguito con la realizzazione del DSL\@. + \item[Considerazioni finali] Lo sprint si è concluso senza problemi da evidenziare. +\end{description} +\section{Sprint 5}\label{sec:sprint-5} +\begin{description} + \item[Svolgimento e sviluppo] Non avendo fin'ora riscontrato ritardi significativi nello sviluppo, il team ha deciso + di aggiungere meno item allo sprint per poter conciliare impegni accademici. + Sono stati implementati \texttt{ExcludingView} ed \texttt{ExcludingSystem} ed è stato arricchito il DSL per + permettere l'aggiunta di \texttt{System} e la rimozione di \texttt{Component}. + \item[Considerazioni finali] Lo sprint si è concluso evidenziando incosistenze nella sintassi del DSL che saranno + corrette nello sprint successivo. + Inoltre, si intende effettuare il refactoring dell'interfaccia di \texttt{World} che presenta margini di + miglioramenti; + tuttavia, essendo una modifica consistente non poteva essere completata in questo sprint. +\end{description} +\section{Sprint 6}\label{sec:sprint-6} +\begin{description} + \item[Svolgimento e sviluppo] Lo sprint si è focalizzato principalmente sulla definizione dell'architettura per la + demo. + Inoltre, sono state apportate migliorie alla sintassi del DSL\@. + Infine, è stato effettuato il primo rilascio della libreria dal momento che sono state implementate tutte le + funzionalità minime necessarie. + \item[Considerazioni finali] Si è deciso che lo sprint item \textit{``Refactor World's interface''} avesse una + priorità minore rispetto ad altri item, per questo è stato rimandato a sprint successivi. +\end{description} +\section{Sprint 7}\label{sec:sprint-7} +\begin{description} + \item[Svolgimento e sviluppo] Lo sprint ha avuto come obiettivo principale la realizzazione della demo. + Inoltre è stato effettuato il refactoring della classe \texttt{World} e le corrispondenti parti nel DSL\@. + Anche alla fine di questo sprint è stato effettuato un rilascio che comprende il framework completo di tutte le + funzionalità e la prima versione della demo. + \item[Considerazioni finali] Dato che è stato completato in maniera parziale, lo sprint item + \textit{``Refactor World's interface''} è stato spostato allo sprint finale. +\end{description} +\section{Sprint 8}\label{sec:sprint-8} +\begin{description} + \item[Svolgimento e sviluppo] In questo sprint il team ha ultimato la demo e il DSL. In aggiunta, ha rifattorizzato + l'implementazione di alcune interfacce del framework. + \item[Considerazioni finali] Il progetto può dirsi concluso. +\end{description} + +\section{Conclusioni e sviluppi futuri}\label{sec:conclusioni-e-sviluppi-futuri} +La realizzazione del progetto è stata un'esperienza molto formativa soprattutto per quanto riguarda l'apprendimento di Scala 3; +infatti, è stato possibile sperimentare con alcuni nuovi meccanismi avanzati nonché prendere dimestichezza con le +piccole ma fondamentali differenze con Scala 2. +Tuttavia, l'assenza di alcuni strumenti fondamentali, come Scalafix, hanno reso lo sviluppo più complicato. +Ci siamo cimentati nell'applicazione di un processo di sviluppo agile con frequenti incontri e un approccio +test-driven allo sviluppo di codice, mai sperimentato prima di questo corso. +Riteniamo l'esperienza complessiva molto positiva anche grazie a un forte affiatamento del gruppo. + +Possibili sviluppi futuri potrebbero riguardare l'implementazione di ottimizzazioni per migliorare ulteriormente +le prestazioni della libreria. diff --git a/doc/code/benchmark.scala b/doc/code/benchmark.scala new file mode 100644 index 00000000..13654dd0 --- /dev/null +++ b/doc/code/benchmark.scala @@ -0,0 +1,21 @@ +@State(Scope.Thread) +@BenchmarkMode(Array(Mode.All)) +@Threads(1) +@Fork(1) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 50) +@Measurement(iterations = 100) +class JmhSettings { + + @Param(Array("1024", "2048", "4096", "10000")) + var nEntities: Int = _ + val world: World = World() + + @Setup + def setup: Unit = { + val entities = + (0 until nEntities) map (_ => world.createEntity()) + entities foreach (_ setComponent Position(1, 2)) + entities foreach (_ setComponent Velocity(3, 4)) + } +} \ No newline at end of file diff --git a/doc/code/builder-syntax-bug.sc b/doc/code/builder-syntax-bug.sc new file mode 100644 index 00000000..873c9973 --- /dev/null +++ b/doc/code/builder-syntax-bug.sc @@ -0,0 +1,5 @@ +// For the code to compile it is necessary to use redundant type +// annotations in the lambda parameters. +val system2 = BuildSystem + .withView + .withDeltaTime{ (view: View, deltaTime: DeltaTime) => ??? } diff --git a/doc/code/builder-syntax.sc b/doc/code/builder-syntax.sc new file mode 100644 index 00000000..4098f4fe --- /dev/null +++ b/doc/code/builder-syntax.sc @@ -0,0 +1,9 @@ +// The type of the lambda required to build a System changes +// depending on the specified elements. +val system1 = BuildSystem + .withWorld + .withDeltaTime + .withComponents{ (world, deltaTime, comps) => ??? } +val system2 = BuildSystem + .withView + .withComponents{ (view, comps) => ??? } diff --git a/doc/code/clist-tag.sc b/doc/code/clist-tag.sc new file mode 100644 index 00000000..7f310b51 --- /dev/null +++ b/doc/code/clist-tag.sc @@ -0,0 +1,21 @@ +inline given [L <: CList]: CListTag[L] = ${ deriveCListTagImpl[L] } +private def deriveCListTagImpl[L <: CList: Type](using quotes: Quotes): Expr[CListTag[L]] = { + import quotes.reflect.* + // Perform checks on the type... + if containsDuplicates[L] then + report.error("A CListTag cannot be derived from CLists with duplicate element types.") + // Tag code generation... +} + +private def containsDuplicates[L <: CList: Type](using quotes: Quotes): Boolean = + Type.of[L] match { // Pattern matching on the compile-time type T + case '[head &: tail] => countRepetitions[L, head] > 1 || containsDuplicates[tail] + case _ => false + } + +private def countRepetitions[L <: CList: Type, C <: Component: Type](using quotes: Quotes): Int = + Type.of[L] match { + case '[C &: tail] => 1 + countRepetitions[tail, C] + case '[_ &: tail] => countRepetitions[tail, C] + case _ => 0 + } diff --git a/doc/code/clist-usage.scala b/doc/code/clist-usage.scala new file mode 100644 index 00000000..5d22c32f --- /dev/null +++ b/doc/code/clist-usage.scala @@ -0,0 +1,6 @@ +import dev.atedeg.ecscala.{ &:, CNil, Component } + +case class Position(x: Int, y: Int) extends Component +case class Velocity(x: Int, y: Int) extends Component + +val view = View[Position &: Velocity &: CNil](world) diff --git a/doc/code/clist.scala b/doc/code/clist.scala new file mode 100644 index 00000000..3cdfbf93 --- /dev/null +++ b/doc/code/clist.scala @@ -0,0 +1,12 @@ +package dev.atedeg.ecscala + +trait Component + +sealed trait CList +sealed trait CNil extends CList +case object CNil extends CNil + +extension [H <: Component, T <: CList](head: H) + def &:(tail: T): H &: T = dev.atedeg.ecscala.&:(head, tail) + +final case class &:[+C <: Component, +L <: CList](h: C, t: L) diff --git a/doc/code/component-tag.sc b/doc/code/component-tag.sc new file mode 100644 index 00000000..2c28960d --- /dev/null +++ b/doc/code/component-tag.sc @@ -0,0 +1,22 @@ +sealed trait ComponentTag[C] +inline given [C]: ComponentTag[C] = ${ deriveComponentTagImpl[C] } + +private def deriveComponentTagImpl[C: Type](using quotes: Quotes): Expr[ComponentTag[C]] = { + import quotes.reflect.* + val typeReprOfC = TypeRepr.of[C] + // Perform checks on the type... + + val computedString = typeReprOfC.show + val computedHashCode = computedString.hashCode + '{ + new ComponentTag[C] { + override def toString: String = ${ Expr(computedString) } + override def hashCode: Int = ${ Expr(computedHashCode) } + override def equals(obj: Any) = obj match { + case that: ComponentTag[_] => + (this eq that) || (this.hashCode == that.hashCode && this.toString == that.toString) + case _ => false + } + } + } +} diff --git a/doc/code/deletable.scala b/doc/code/deletable.scala new file mode 100644 index 00000000..d3946925 --- /dev/null +++ b/doc/code/deletable.scala @@ -0,0 +1,4 @@ +type Deletable[L <: CList] <: CList = L match { + case h &: t => (h | Deleted) &: Deletable[t] + case CNil => CNil +} \ No newline at end of file diff --git a/doc/code/demo-precondition-test.scala b/doc/code/demo-precondition-test.scala new file mode 100644 index 00000000..18454a06 --- /dev/null +++ b/doc/code/demo-precondition-test.scala @@ -0,0 +1,9 @@ +"A BallSelectionSystem" should { + "run" when { + "in an enabled state" in + checkAllStates(BallSelectionSystem(_, _))( + (State.Pause, AnyValue, true, AnyValue), + (State.SelectBall, AnyValue, true, AnyValue), + ) + } +} diff --git a/doc/code/dsl-ctxf.scala b/doc/code/dsl-ctxf.scala new file mode 100644 index 00000000..907c05f2 --- /dev/null +++ b/doc/code/dsl-ctxf.scala @@ -0,0 +1,6 @@ +extension (world: World) { + def hasA(init: World ?=> Unit): Unit = { + given w: World = world + init + } +} diff --git a/doc/code/dsl-view.scala b/doc/code/dsl-view.scala new file mode 100644 index 00000000..f44a567e --- /dev/null +++ b/doc/code/dsl-view.scala @@ -0,0 +1 @@ +val view = getView[Position &: CNil].excluding[Velocity &: CNil] from world \ No newline at end of file diff --git a/doc/code/dsl-withComp.scala b/doc/code/dsl-withComp.scala new file mode 100644 index 00000000..a8bcfbdc --- /dev/null +++ b/doc/code/dsl-withComp.scala @@ -0,0 +1,4 @@ +val world = World() +val entity1 = world hasAn entity withComponents { + Position(1, 2) &: Velocity(3, 4) &: Gravity(9.8) +} \ No newline at end of file diff --git a/doc/code/game-loop.scala b/doc/code/game-loop.scala new file mode 100644 index 00000000..e40fbdd9 --- /dev/null +++ b/doc/code/game-loop.scala @@ -0,0 +1,19 @@ +trait GameLoop { + val fps = IntegerProperty(0) + def start: Unit + def stop: Unit +} + +object GameLoop { + def apply(handler: Double => Unit): GameLoop = GameLoopImpl(handler) + private class GameLoopImpl(handler: Double => Unit) extends GameLoop { + private val animationTimer = new JfxAnimationTimer() { + override def handle(now: Long): Unit = { + // calculate delta and FPS + handler(delta) + } + } + override def start: Unit = animationTimer.start() + override def stop: Unit = animationTimer.stop() + } +} \ No newline at end of file diff --git a/doc/code/scalatest-bug.scala b/doc/code/scalatest-bug.scala new file mode 100644 index 00000000..142a46be --- /dev/null +++ b/doc/code/scalatest-bug.scala @@ -0,0 +1,8 @@ +"A CList" must { + "fail to compile when trying to do an invalid unpacking" in new ComponentsFixture with { + "val a &: CNil = Position(1, 1) &: Velocity(1, 1) &: CNil" + shouldNot typeCheck + "val a &: b &: CNil = Position(1, 1) &: CNil" + shouldNot typeCheck + } +} \ No newline at end of file diff --git a/doc/ecscala-report.bib b/doc/ecscala-report.bib index 018fd8b3..d60e4274 100644 --- a/doc/ecscala-report.bib +++ b/doc/ecscala-report.bib @@ -1,7 +1,164 @@ %! Author = Giacomo Cavalieri, Nicolò Di Domenico, Nicolas Farabegoli, Linda Vitali %! Date = 8/5/21 -@book{knuth:art3, - author = {Knuth, Donald E.}, - title = {The Art of Computer Programming, Volume 3: (2nd Ed.) Sorting and Searching} -} \ No newline at end of file +@online {gdc:overwatch, + author = {Ford, Timothy}, + title = {``Overwatch'' Gameplay Architecture and Netcode}, + institution = {Blizzard Entertainment}, + organization = {Game Developers Conference}, + year = {2017}, + url = {https://www.gdcvault.com/play/1024001/-Overwatch-Gameplay-Architecture-and}, +} +@online {minecraft, + author = {Mojang Studios}, + title = {Minecraft attributions}, + url = {https://www.minecraft.net/en-us/attribution}, +} +@online {entt, + author = {Caini, Michele}, + title = {EnTT}, + url = {https://github.com/skypjack/entt/}, +} +@manual {entt:optimizations, + author = {Caini, Michele}, + title = {Entity component systems: groups}, + url = {https://github.com/skypjack/entt/wiki/Crash-Course:-entity-component-system#groups}, +} +@online {artemis, + author = {Papari, Adrian}, + title = {Artemis-odb}, + url = {https://github.com/junkdog/artemis-odb}, +} +@online {ashley, + author = {LibGDX}, + title = {Ashley}, + url = {https://github.com/libgdx/ashley}, +} + +@online{scalatest-bug, + title = {Bug report: "Type error not detected by scalatest"}, + url = {https://github.com/scalatest/scalatest/issues/2062} +} + +@manual{cross-building, + title = {Sbt Cross-building}, + url = {https://www.scala-sbt.org/1.x/docs/Cross-Build.html} +} + +@online{scalajs, + title = {Scala.js}, + url = {https://www.scala-js.org/}, +} + +@online{intellij-issue, + title = {Intellij report errors although sbt compiles correctly in cross build with Scala js}, + url = {https://youtrack.jetbrains.com/issue/SCL-19525}, +} + +@online{shapeless, + author = {milessabin}, + title = {shapeless}, + url = {https://github.com/milessabin/shapeless}, +} + +@online{jmh:details, + author = {Jenkov, Jakob}, + title = {JMH - Java Microbenchmark Harness}, + url = {http://tutorials.jenkov.com/java-performance/jmh.html}, +} + +@online{jmh, + title = {Java Microbenchmark Harness (JMH)}, + url = {https://github.com/openjdk/jmh}, +} + +@online{scalafx, + title = {ScalaFX}, + url = {https://github.com/scalafx/scalafx}, +} + +@manual {tuples, + author = {Bazzucchi, Vincenzo}, + title = {Tuple bring generic programming to Scala 3}, + url = {https://www.scala-lang.org/2021/02/26/tuples-bring-generic-programming-to-scala-3.html}, +} + +@manual {match-types, + title = {Match types - Scala 3 language reference}, + url = {https://docs.scala-lang.org/scala3/reference/new-types/match-types.html}, +} + +@manual {union-types, + title = {Union types - Scala 3 language reference}, + url = {https://docs.scala-lang.org/scala3/reference/new-types/union-types.html}, +} + +@manual {macros, + title = {Macros - Scala 3 language reference}, + url = {https://docs.scala-lang.org/scala3/guides/macros/macros.html}, +} + +@manual {inline, + title = {Inline - Scala 3 language reference}, + url = {https://docs.scala-lang.org/scala3/guides/macros/inline.html}, +} + +@manual {given-instances, + title = {Given instances - Scala 3 language reference}, + url = {https://docs.scala-lang.org/scala3/reference/contextual/givens.html}, +} + +@online {dotty-bug, + title = {Cannot infer type of tupled arguments}, + url = {https://github.com/lampepfl/dotty/issues/13526}, +} + +@manual{matchers, + title = {Matchers - ScalaTest}, + url = {https://www.scalatest.org/user_guide/using_matchers}, +} + +@manual{anyRefMap, + title = {AnyRefMap - Scala 3 language reference}, + url = {https://www.scala-lang.org/api/2.13.4/scala/collection/mutable/AnyRefMap.html} +} + +@online{scalatest, + title = {ScalaTest}, + url = {https://www.scalatest.org/scaladoc}, +} + +@online{scalafmt, + title = {Scalafmt}, + url = {https://scalameta.org/scalafmt/}, +} + +@online{jacoco, + title = {JaCoCo}, + url = {https://www.jacoco.org/}, +} + +@manual{contextfunctions, + title = {Context Functions - Scala 3 language reference}, + url = {https://docs.scala-lang.org/scala3/reference/contextual/context-functions.html}, +} + +@manual{extensionmethods, + title = {Extension Methods - Scala 3 language reference}, + url = {https://docs.scala-lang.org/scala3/reference/contextual/extension-methods.html}, +} + +@online{mockito, + title = {Mockito}, + url = {https://site.mockito.org/}, +} + +@online{testfx, + title = {TestFX}, + url = {https://github.com/TestFX/TestFX}, +} + +@online{sbt-ci-release, + title = {sbt-ci-release}, + url = {https://github.com/sbt/sbt-ci-release}, +} diff --git a/doc/ecscala-report.tex b/doc/ecscala-report.tex index 281d6fb9..8ada7731 100644 --- a/doc/ecscala-report.tex +++ b/doc/ecscala-report.tex @@ -8,21 +8,37 @@ \usepackage[utf8]{inputenc} \usepackage[italian]{babel} \usepackage{graphicx} +\usepackage{tikz} +\usepackage{pgfplots} \usepackage{listings} \usepackage{microtype} \usepackage{xcolor} +\usepackage{xspace} \usepackage{enumitem} \usepackage{csquotes} \usepackage{booktabs} \usepackage{float} -\usepackage[backend=biber]{biblatex} -\usepackage{hyperref} +\usepackage[backend=biber,sorting=none]{biblatex} +\usepackage{amsmath} \usepackage{textcomp} +\usepackage{hyperref} \addbibresource{ecscala-report.bib} % custom commands -\newcommand{\eg}{\emph{e.g}\ } +\def\CC{{C\nolinebreak[4]\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}} +\newcommand{\eg}{\emph{e.g.}\ } \newcommand{\emailaddr}[1]{\href{mailto:#1}{\texttt{#1}}} +\newcommand{\ECS}{\textit{ECS}\xspace} +\newcommand{\Entity}{\textit{Entity}\xspace} +\newcommand{\Component}{\textit{Component}\xspace} +\newcommand{\System}{\textit{System}\xspace} +\newcommand{\View}{\textit{View}\xspace} +\newcommand{\World}{\textit{World}\xspace} +\newcommand{\entity}{\textit{entity}\xspace} +\newcommand{\component}{\textit{component}\xspace} +\newcommand{\system}{\textit{system}\xspace} +\newcommand{\view}{\textit{view}\xspace} +\newcommand{\world}{\textit{world}\xspace} \renewcommand{\lstlistingname}{Listato} \lstset{basicstyle=\ttfamily, showspaces=false, showstringspaces=false} \definecolor{lightmauve}{rgb}{0.86, 0.82, 1.0} @@ -49,7 +65,7 @@ escapeinside={\%*}{*)} } -\title{ECScala - A general-purpose ECS framework} +\title{ECScala - An ECS framework} \author{ Giacomo Cavalieri \\ \emailaddr{giacomo.cavalieri2@studio.unibo.it} @@ -76,12 +92,13 @@ \include{0-introduction} \include{1-development-process} - \include{2-requirments} + \include{2-requirements} \include{3-architectural-design} \include{4-detailed-design} \include{5-implementation} - \include{6-retrospective} + \include{6-demo} + \include{7-retrospective} \printbibliography -\end{document} \ No newline at end of file +\end{document} diff --git a/doc/img/Architechture.eps b/doc/img/Architechture.eps index ad98f4b6..b08bffb4 100644 --- a/doc/img/Architechture.eps +++ b/doc/img/Architechture.eps @@ -1,10 +1,10 @@ %!PS-Adobe-3.0 EPSF-3.0 %%Creator: cairo 1.17.4 (https://cairographics.org) -%%CreationDate: Sat Aug 14 12:10:12 2021 +%%CreationDate: Wed Oct 13 18:15:16 2021 %%Pages: 1 %%DocumentData: Clean7Bit %%LanguageLevel: 2 -%%BoundingBox: 7 8 420 544 +%%BoundingBox: 7 8 381 616 %%EndComments %%BeginProlog 50 dict begin @@ -75,9 +75,11 @@ 0 1 255 { Encoding exch /.notdef put } for Encoding 67 /C put Encoding 69 /E put +Encoding 73 /I put Encoding 83 /S put Encoding 86 /V put Encoding 87 /W put +Encoding 97 /a put Encoding 99 /c put Encoding 100 /d put Encoding 101 /e put @@ -95,7 +97,7 @@ Encoding 117 /u put Encoding 119 /w put Encoding 120 /x put Encoding 121 /y put -/CharStrings 23 dict dup begin +/CharStrings 25 dict dup begin /.notdef 0 def /W 1 def /o 2 def @@ -119,12 +121,14 @@ Encoding 121 /y put /g 20 def /S 21 def /s 22 def +/I 23 def +/a 24 def end readonly def /sfnts [ -<000100000009008000030010637674206d5f6ba10000131c000002886670676d7e61b6110000 -15a4000007b4676c7966428a6a6d0000009c00001280686561640ac93d4f00001d5800000036 -686865610e18038a00001d9000000024686d74786e7707bf00001db40000005c6c6f63610000 -d39000001e10000000606d617870042f053400001e7000000020707265708aa104b900001e90 +<000100000009008000030010637674206d5f6ba1000014a0000002886670676d7e61b6110000 +1728000007b4676c7966faf6aea30000009c00001404686561640b8df52900001edc00000036 +686865610e18038c00001f1400000024686d74787523088400001f38000000646c6f63610000 +fa9400001f9c000000686d617870043105340000200400000020707265708aa104b900002024 00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd 2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 e9000000000100020000078b05810017014040e51617010013100f0408070c0a09090c041317 @@ -249,115 +253,126 @@ a1fee3af890244fcb88a6890477b70d3cc02af0000020054fe4e045a044f0021002b0061403a 5d2b00183f332f5f5e5d5f5d5d2b111200393911120117391133113311331133313001140423 222627371e01333236353426272e0235343633321617072e01232206151416171e03041ffeff e3dfed27f7156780766c5768eea657efdbc1eb1df90c5e6664644d5b7fc57747013c9db38d95 -254d403c40343d152f51815e9bad968e1a4241333c2f37121a374c7705cc05cc007d05810015 -0079058100150000000000000000000000000000043a001400770000ffec00000000ffec0000 -0000ffec0000fe57fff700000000000000000000000000000000000000000000000000000000 +254d403c40343d152f51815e9bad968e1a4241333c2f37121a374c7700010089000001b00581 +000300664045030000040501030012e00501b00501a005019005018005015005014005010005 +01f00501c00501b00501a005017005016005011f0501e00501d00501c00501b005018005015d +5d5d5d5d717171717171717272727272727272003f3f11120139113331303311211189012705 +81fa7f000002003cffec0480044e00260033006d403f2427270707150e0f2c03030f15033534 +06285259060600590e690e022d0e01030f0e1f0e0209040e12120b51591210192f002f4f5924 +210016bf35014f35015d71003f32322b110033183f2b1100335f5e5d5f5d5d1239182f2b1112 +0117391133113311331133113331300522263534363f0135342623220607253e013332161511 +1416333237150e0323222627230613070e0215141633323e013501899db0dbd0e94a544e4909 +fedb1bebcbcdde2930201e1928282d1e6a650a0676599062522b473b426d3e14ab9ba8b00204 +376a6747520e9ea3cabafe765b450698060a06046865d50209020423483c4d4b487f470005cc +05cc007d058100150079058100150000000000000000000000000000043a001400770000ffec +00000000ffec00000000ffec0000fe57fff70000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000800000000000119012500f500eb0000000000000000000000c100d3 -00ba00b000cf0000000000000000000000000127012901060000011200e400f400c600000000 -00000000000000000000000000000000000000000119011f014c0000000000df00d100c500b5 -00000000000000000000000000000000000000000000010200a901fd00d80119008000b701fd -00000000013f00db015d012500aa00800075008d01fc0179012100a001100000000001310119 -010e0104000000000000000000000000000000000000013d01ff00e00106009400e000940144 -00e005730319000000d802c5009c038102cd00cb00f4004e028d000000ff00d700cc01300145 -007300b400a60000000000730080008d000000000000000000000000030000a200980083008d -000000000000000005aefebc0581fd300011fff600b600bc00c60000007f008a006000000000 -0000000000f001ee0190000002190108011500000000000000be00000000000000000748036a -02b60202fd930000009100670091006101d90000028d03410000000000000000000000000000 -00aafe6ffe6801050093009800e20151008f00be00aefeb9fea4005e00af02d5005500f200a6 -04150601000003e1001002fa000ffed401eafff300b8000000000363000bfd0ffff500000000 -000006810477001504d90000ffecffc5fe7f007500cd00f2010200d5011940475b5a59585554 -535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c28 -272625242322211f181411100f0e0d0b0a090807060504030201002c20b0016045b003252011 -466123452361482d2c20451868442d2c45234660b0206120b04660b004262348482d2c452346 -2361b0206020b02661b02061b004262348482d2c45234660b0406120b06660b004262348482d -2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd -442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651582320b00d44 -235921212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a432343650a2d -2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c20 -45b00325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b006 -43b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361 -592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b52 -5845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c -01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243b00152582121 -2121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b00050 -58b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013515b58b00225 -46206861b00325b003253f2321381b2111592d2c2045b00325465058b0022546206861b00325 -b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b0 -8051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423648bb8155562 -1bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004254964234569 -b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c4b535820b003 -2549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b00e23 -44b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c45234560234560234560 -23766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1 -302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b00325 -45695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c4523 -20458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb0 -164358b00326458a586466b01f601b64b020606620581b21b04059b001615923586559b02923 -442310b029e01b2121212121592d2cb0024354584b53234b515a58381b2121591b2121212159 -2d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b0292344b00525b0 -0825082058021b0359b0042510b005252046b0042523423cb00425b0072508b0072510b00625 -2046b00425b0016023423c2058011b0059b0042510b00525b029e0b02920456544b0072510b0 -0625b029e0b00525b00825082058021b0359b00525b003254348b00425b0072508b00625b003 -25b0016043481b2159212121212121212d2c02b00425202046b004252342b0052508b0032545 -48212121212d2c02b0032520b0042508b0022543482121212d2c452320451820b00050205823 -652359236820b040505821b04059235865598a60442d2c4b53234b515a5820458a60441b2121 -592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b545838 -1b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb0 -02435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b -515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c0146234660234661 -23201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c -4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188535a58b91000 -0020885458b202010243604259b12401885158b920000040885458b2020202436042b1240188 -5458b2022002436042004b014b5258b2020802436042591bb940000080885458b20204024360 -4259b94000008063b80100885458b202080243604259b94000010063b80200885458b2021002 -43604259b12601885158b94000020063b80400885458b202400243604259b94000040063b808 -00885458b2028002436042595959595959b10002435458400a0540084009400c020d021bb101 -02435458b2054008ba010000090100b30c010d011bb18002435258b2054008b80180b109401b -b2054008ba01800009014059b9400000808855b94000020063b8040088555a58b30c000d011b -b30c000d0159595942424242422d2c451868234b51582320452064b04050587c59688a605944 -2d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201b001 -233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b0024350b001b00243 -545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d000100000002199973e779c7 -5f0f3cf5001f080000000000c849682600000000dcb67151fc25fcfd0a6f0844000100080002 -00010000000000010000073efe4e00430aaafc25fa7a0a6f0001000000000000000000000000 -00000017060000cd078d000204e30050031d00870239008f04e300540556008904e3008702aa -00190239008f0473001005c70054071d008704e30087047300500556000e0639fffa0473000e -0473005004e3007f04e300540556003b04730048000000000000004c000001ec000002780000 -0300000003600000040c000004b000000550000005d000000650000008600000091000000a18 -00000ac400000b9400000c0400000e1400000e9400000f3000000fcc000010b8000011940000 -128000010000001701520054005c000600020010002f005c0000034d0354000400014155013f -000101390055013e000101390055014201400014001f01410140001f001f013b0033013a0055 -013800330139005500a4013900f4013900020132003d0131005501310001012f00550130003d -012f0055012c012900ff001f01290001012a00550128003d0127005501270001012a00550126 -003d0125005501250001012a00550123012200ff001f01220001012a0055012b003d012a0055 -005001070001002f0107000100af0104405001d0fd01bffd0110fd016ffb0140fb0180f590f5 -a0f503f1f0351f2ff09ff0025fef012fef5fef6fef9fefdfef05e6e4201fe5e43d1fe2e0271f -e1e03d1fdf3ddd55de3d035500dd30dd02dd0103552f410b011e00010010011e0020011e0040 -011e0003ffc0011e4028191c46dc03ff1f00db01da043c1fd4d21c1fd3d2261f60d190d1c0d1 -0360d190d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ffc0b4d10a0d460fb80116400f01bfbe26 -1f40bb29414640bb222746b801214026b63d1f00b8016fb801b8b70a1f00b70100b720b740b7 -60b770b70540b760b790b7d0b7f0b705b80120400d483d1f00b560b502a0b5d0b502b8ffc040 -0eb50b0e460fb25fb202b1033c1f2f410b0119003f0119004f01190003008f01190001004001 -1940282629461faf2faf3faf9faf040faf0140af0e164600ad70ad80ad03e0adf0ad02abaa35 -1faa50261fb9011b011ab23c1f00b8011ab6010fa9010fa801bc01170113003c001f0115407e -503c1f9e9b271f9d9b271f9c9b271f809b019846281f9f97af97029646351f0f941f94029390 -261f9291261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f8d010f8c01408c0b0f460f891f890286 -850f1f5f850136824682027650261f7550261f7450261f7350261f2970011b7001037001f470 -01d670e67002687001597001b8fff0407d700a0d466f6e481f6e46321f1a0118551933185507 -3303550603ff1f6150261f605f321f5f50261f5e5a481f5c46271f5b5a781f5a46311f133212 -5505010355043203556f03010f033f034f036f037f03055f53014053282c4640531e22464053 -1318466b527b528b5203514f1c1f504f1c1f194f294f02594f694f02b80112402d46251f4946 -191f4846211f4746351ff846019846011c481b551632155511010f5510320f55020100550100 -ff1fb80111b21b091fb80110402d1b091f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0f -ff0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff524bb00750 -5bb00188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb03253 -58b0601d594bb0645358b0401d594bb0805358b0101db11600425973747374752b2b2b2b2b2b -2b2b0173742b2b2b2b0073742b2b732b2b2b7373752b2b2b012b2b2b002b2b2b2b2b2b2b2b01 -2b2b2b73737373747474002b2b2b2b0173732b73002b73732b732b2b73012b732b00732b2b2b -2b2b7373732b012b2b0073742b73742b73742b73012b73742b007374752b73742b2b2b012b00 -732b2b7374012b2b002b732b2b73752b732b2b012b2b002b2b737401732b0073737373737301 -737373002b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> +0000000000000000000000000000000000000800000000000119012500f500eb000000000000 +0000000000c100d300ba00b000cf0000000000000000000000000127012901060000011200e4 +00f400c60000000000000000000000000000000000000000000000000119011f014c00000000 +00df00d100c500b500000000000000000000000000000000000000000000010200a901fd00d8 +0119008000b701fd00000000013f00db015d012500aa00800075008d01fc0179012100a00110 +0000000001310119010e0104000000000000000000000000000000000000013d01ff00e00106 +009400e00094014400e005730319000000d802c5009c038102cd00cb00f4004e028d000000ff +00d700cc01300145007300b400a60000000000730080008d0000000000000000000000000300 +00a200980083008d000000000000000005aefebc0581fd300011fff600b600bc00c60000007f +008a0060000000000000000000f001ee0190000002190108011500000000000000be00000000 +000000000748036a02b60202fd930000009100670091006101d90000028d0341000000000000 +000000000000000000aafe6ffe6801050093009800e20151008f00be00aefeb9fea4005e00af +02d5005500f200a604150601000003e1001002fa000ffed401eafff300b8000000000363000b +fd0ffff500000000000006810477001504d90000ffecffc5fe7f007500cd00f2010200d50119 +40475b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a39383736 +3531302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201002c20b0 +016045b003252011466123452361482d2c20451868442d2c45234660b0206120b04660b00426 +2348482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b0406120b066 +60b004262348482d2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c +2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b004 +2651582320b00d44235921212d2c20204518684420b001602045b04676688a4560442d2c01b1 +0b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453a +b10200080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c2045b000 +4360442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c64 +2364615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445 +b02b23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500 +b0016023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb0 +0243b001525821212121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c +8a70456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524b +b013515b58b0022546206861b00325b003253f2321381b2111592d2c2045b00325465058b002 +2546206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648b +b84000622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c +6423648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588a +b004254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f59 +2d2c4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610 +b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c4523 +456023456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b0406144 +1b2121592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d +2c4b515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2c +b02f45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb33300 +34005944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b00161 +5923586559b02923442310b029e01b2121212121592d2cb0024354584b53234b515a58381b21 +21591b21212121592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559 +b0292344b00525b00825082058021b0359b0042510b005252046b0042523423cb00425b00725 +08b0072510b006252046b00425b0016023423c2058011b0059b0042510b00525b029e0b02920 +456544b0072510b00625b029e0b00525b00825082058021b0359b00525b003254348b00425b0 +072508b00625b00325b0016043481b2159212121212121212d2c02b00425202046b004252342 +b0052508b003254548212121212d2c02b0032520b0042508b0022543482121212d2c45232045 +1820b00050205823652359236820b040505821b04059235865598a60442d2c4b53234b515a58 +20458a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d +2cb000214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b +1b212121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c +208a08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c +014623466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a23 +53583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b140 +0188535a58b910000020885458b202010243604259b12401885158b920000040885458b20202 +02436042b12401885458b2022002436042004b014b5258b2020802436042591bb94000008088 +5458b202040243604259b94000008063b80100885458b202080243604259b94000010063b802 +00885458b202100243604259b12601885158b94000020063b80400885458b202400243604259 +b94000040063b80800885458b2028002436042595959595959b10002435458400a0540084009 +400c020d021bb10102435458b2054008ba010000090100b30c010d011bb18002435258b20540 +08b80180b109401bb2054008ba01800009014059b9400000808855b94000020063b804008855 +5a58b30c000d011bb30c000d0159595942424242422d2c451868234b51582320452064b04050 +587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a2365 +42b00b234201b001233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b0 +024350b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d00010000 +00021999f42924355f0f3cf5001f080000000000c849682600000000dd7b292bfc25fcfd0a6f +084400010008000200010000000000010000073efe4e00430aaafc25fa7a0a6f000100000000 +000000000000000000000019060000cd078d000204e30050031d00870239008f04e300540556 +008904e3008702aa00190239008f0473001005c70054071d008704e30087047300500556000e +0639fffa0473000e0473005004e3007f04e300540556003b04730048023900890473003c0000 +00000000004c000001ec0000027800000300000003600000040c000004b000000550000005d0 +00000650000008600000091000000a1800000ac400000b9400000c0400000e1400000e940000 +0f3000000fcc000010b80000119400001280000013000000140400010000001901520054005c +000600020010002f005c0000034d0354000400014155013f000101390055013e000101390055 +014201400014001f01410140001f001f013b0033013a0055013800330139005500a4013900f4 +013900020132003d0131005501310001012f00550130003d012f0055012c012900ff001f0129 +0001012a00550128003d0127005501270001012a00550126003d0125005501250001012a0055 +0123012200ff001f01220001012a0055012b003d012a0055005001070001002f0107000100af +0104405001d0fd01bffd0110fd016ffb0140fb0180f590f5a0f503f1f0351f2ff09ff0025fef +012fef5fef6fef9fefdfef05e6e4201fe5e43d1fe2e0271fe1e03d1fdf3ddd55de3d035500dd +30dd02dd0103552f410b011e00010010011e0020011e0040011e0003ffc0011e4028191c46dc +03ff1f00db01da043c1fd4d21c1fd3d2261f60d190d1c0d10360d190d1b0d1c0d1e0d105b8ff +c0b3d1191d46b8ffc0b4d10a0d460fb80116400f01bfbe261f40bb29414640bb222746b80121 +4026b63d1f00b8016fb801b8b70a1f00b70100b720b740b760b770b70540b760b790b7d0b7f0 +b705b80120400d483d1f00b560b502a0b5d0b502b8ffc0400eb50b0e460fb25fb202b1033c1f +2f410b0119003f0119004f01190003008f011900010040011940282629461faf2faf3faf9faf +040faf0140af0e164600ad70ad80ad03e0adf0ad02abaa351faa50261fb9011b011ab23c1f00 +b8011ab6010fa9010fa801bc01170113003c001f0115407e503c1f9e9b271f9d9b271f9c9b27 +1f809b019846281f9f97af97029646351f0f941f94029390261f9291261f0f8f1f8f6f8f7f8f +8f8f058e8c261f4f8d010f8c01408c0b0f460f891f890286850f1f5f85013682468202765026 +1f7550261f7450261f7350261f2970011b7001037001f47001d670e67002687001597001b8ff +f0407d700a0d466f6e481f6e46321f1a01185519331855073303550603ff1f6150261f605f32 +1f5f50261f5e5a481f5c46271f5b5a781f5a46311f1332125505010355043203556f03010f03 +3f034f036f037f03055f53014053282c4640531e224640531318466b527b528b5203514f1c1f +504f1c1f194f294f02594f694f02b80112402d46251f4946191f4846211f4746351ff8460198 +46011c481b551632155511010f5510320f55020100550100ff1fb80111b21b091fb80110402d +1b091f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f +00018016010501b80190b154532b2b4bb807ff524bb007505bb00188b02553b00188b040515a +b00688b000555a5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d59 +4bb0805358b0101db11600425973747374752b2b2b2b2b2b2b2b0173742b2b2b2b0073742b2b +732b2b2b7373752b2b2b012b2b2b002b2b2b2b2b2b2b2b012b2b2b73737373747474002b2b2b +2b0173732b73002b73732b732b2b73012b732b00732b2b2b2b2b7373732b012b2b0073742b73 +742b73742b73012b73742b007374752b73742b2b2b012b00732b2b7374012b2b002b732b2b73 +752b732b2b012b2b002b2b737401732b0073737373737301737373002b2b2b2b2b2b2b2b2b2b +2b2b732b2b2b2b2b2b1800> ] def /f-0-0 currentdict end definefont pop %%EndResource @@ -376,6 +391,7 @@ Encoding 41 /parenright put Encoding 42 /asterisk put Encoding 43 /plus put Encoding 44 /comma put +Encoding 45 /hyphen put Encoding 46 /period put Encoding 49 /one put Encoding 58 /colon put @@ -384,16 +400,19 @@ Encoding 61 /equal put Encoding 62 /greater put Encoding 63 /question put Encoding 65 /A put +Encoding 66 /B put Encoding 67 /C put +Encoding 68 /D put Encoding 69 /E put +Encoding 82 /R put Encoding 83 /S put Encoding 84 /T put Encoding 85 /U put Encoding 86 /V put -Encoding 87 /W put Encoding 91 /bracketleft put Encoding 93 /bracketright put Encoding 97 /a put +Encoding 98 /b put Encoding 99 /c put Encoding 100 /d put Encoding 101 /e put @@ -415,7 +434,7 @@ Encoding 119 /w put Encoding 121 /y put Encoding 171 /guillemotleft put Encoding 187 /guillemotright put -/CharStrings 46 dict dup begin +/CharStrings 50 dict dup begin /.notdef 0 def /plus 1 def /u 2 def @@ -425,49 +444,53 @@ Encoding 187 /guillemotright put /t 6 def /e 7 def /parenleft 8 def -/parenright 9 def -/E 10 def -/n 11 def -/i 12 def -/y 13 def -/colon 14 def -/space 15 def -/r 16 def -/m 17 def -/o 18 def -/v 19 def -/S 20 def -/s 21 def -/g 22 def -/V 23 def -/w 24 def -/bracketleft 25 def -/T 26 def -/one 27 def -/comma 28 def -/period 29 def -/bracketright 30 def -/C 31 def -/less 32 def -/c 33 def -/W 34 def -/l 35 def -/guillemotleft 36 def -/guillemotright 37 def -/question 38 def -/f 39 def -/h 40 def -/U 41 def -/equal 42 def -/greater 43 def -/asterisk 44 def -/A 45 def +/l 9 def +/T 10 def +/i 11 def +/m 12 def +/colon 13 def +/space 14 def +/D 15 def +/o 16 def +/b 17 def +/parenright 18 def +/c 19 def +/r 20 def +/E 21 def +/n 22 def +/y 23 def +/v 24 def +/S 25 def +/s 26 def +/g 27 def +/V 28 def +/w 29 def +/bracketleft 30 def +/one 31 def +/comma 32 def +/period 33 def +/bracketright 34 def +/C 35 def +/less 36 def +/guillemotleft 37 def +/guillemotright 38 def +/question 39 def +/f 40 def +/h 41 def +/U 42 def +/equal 43 def +/greater 44 def +/R 45 def +/B 46 def +/asterisk 47 def +/hyphen 48 def +/A 49 def end readonly def /sfnts [ -<000100000009008000030010637674204ada4bfa000022d8000002886670676d7e61b6110000 -2560000007b4676c796677c7b10f0000009c0000223c686561640a3bd00c00002d1400000036 -686865610d9403ab00002d4c00000024686d7478bcc0108700002d70000000b86c6f63610003 -2e3000002e28000000bc6d617870039d03e400002ee40000002070726570fdae474900002f04 +<000100000009008000030010637674204ada4bfa00002380000002886670676d7e61b6110000 +2608000007b4676c796654ea545d0000009c000022e4686561640b008bb100002dbc00000036 +686865610d9403af00002df400000024686d7478cd34135500002e18000000c86c6f63610003 +9e9800002ee0000000cc6d61787003a103e400002fac0000002070726570fdae474900002fcc 00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd 2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 e90000000001006400b40447049e000b004340260900000603030d0ca90201030f025f02020c @@ -507,109 +530,11 @@ ac96a8b406043b8472525a110124bbb1fe2e505107701069707c67875a9d5359040230645158 94758d199e61fea8f0fbfbe901ddba0f908783990601f7baca5e482dff00011e011a010c011e fdc1188aab9daf9900000001007ffe58029e05cc000e0022401007000b0a03040a0400030f10 0a1b0300003f3f111201173911331133113331301310123733060211101217232602117fb5bc -aebbafadbdaebdb40214012101cccbd0fe2cfeeafeebfe2ed3cc01cd011f0001000cfe58022b -05cc000e00224010070003040b0a00040a030f100a00031b003f3f1112011739113311331133 -3130011002072336121110022733161211022bb5bcaebcaeafbbaebdb40210fedffe34cbd201 -d10117011701d2d1ccfe33fee1000000000100a8000004fe0581000b00544032050909000a03 -0700040c0d05085f598f0501ba050179058905020f050108030505000101045f59010300095f -590012200d015d003f2b00183f2b11120039182f5f5e5d5d5d712b1112011739113311333130 -331121152111211521112115a8042dfc920332fcce039705819cfe3c9afe159c000000010088 -000003ee044e001a0061403c1209090a001a0a1a1b1c1216001605505916100d0f0a0015d01c -01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a01c01701c015d5d5d5d -5d5d5d7171727272003f323f3f2b11120039111201393911331133113331302111342e012322 -06151123113427331e0217333e01333216151103392a5c598296b406aa01020302033ea379b2 -a502ae6b7634b29efd8d0353bd2a052c394f705db1ccfd2f000200890000013d05cc00030007 -006e40480307070004040809050f0415010053590100ff0901e00901df0901c00901b009019f -09018009017009011f0901000901f00901df0901c00901b00901a009019009014f09011f0901 -5d7171717171717172727272727272727272003f2b00183f3f11120139113333113331301335 -33150311331189b4b4b40520acacfae0043afbc600010005fe5703fc043a001601e440ff1308 -0f11120a0909030f1204181708130f131711090f00055059001b921801821801741801641801 -521801421801341801241801121801021801f41801e41801d21801c21801b41801a418019218 -0182180174180164180156180142180134180124180116180102180167f41801e41801d61801 -c21801b41801a418019618018218017418016418015618014218013418012418011618010218 -01f41801e41801d61801c2180101b01801a01801941801841801701801601801541801441801 -301801201801141801041801f01801e01801d41801c41801b01801a018019418018418017018 -0160180154180144180130180120180114180104180137e018405a01d41801c41801a0180194 -1801841801601801541801441801201801141801041801e01801d41801c41801a01801941801 -84180160180102501801301801201801001801c018019018018018015018012f180110180100 -1801075e5d5d5d5d5d5d5d717171715f717171717171717272727272727272727272725e5d5d -5d5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171717171715f7171717172727272727272 -7272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d71717171717171717171003f -2b00183f3311333311331112011739113311331133333130132227351633323f010133131e02 -17371333010e02bf4a32262ea86211fe53c0e4050e4c0346edbefe6043748dfe570b8706f72b -0435fdaa0e27de0dc502b1fbc6ada9530000000200bb0000017e043a00030007002740130307 -07040004090804059c5b0401009c5b010f003f2b00182f2b1112013939113311333130133533 -1503353315bbc3c3c3036bcfcffc95cfcf000001008800000288044e00130023401006131300 -000c14150f060a10040f0015003f3f3f3333111201393911331133313033113427331615333e -01333217152623220615118e06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4 -fdcc00000001008800000623044e0029017e40ff182900002109212012080920092b2a1c2550 -591c10181100151504505915100c0f21090015642b014b2b013f2b012b2b011f2b010f2b01eb -2b01df2b01bb2b01ab2b018b2b017b2b016f2b013b2b011f2b010b2b016aeb2b01cb2b01bb2b -01af2b018b2b017f2b015b2b014f2b011b2b01fb2b01ef2b01df2b01cb2b01bb2b01af2b0194 -2b01642b014b2b012b2b011b2b01042b01f42b01db2b01ab2b018b2b017f2b016b2b01342b01 -1b2b010f2b0139fb2b01db2b01bb2b01a02b01942b01742b015b2b014b2b012b2b011f2b010b -2b01fb2b01eb2b01cb2b01a42b017b2b015b2b014b2b011b2b01f42b01d02b0102c02b01a02b -01902b01602b014f2b400b01302b012f2b01002b01085e5d5d5d5d5d5d5d5d5f5d5d71717171 -7171717172727272727272727272725e5d5d5d5d5d5d5d5d5d71717171717171717171717172 -72727272727272725e5d5d5d5d5d5d5d5d5d5d717171717171003f32323f3f2b111200393918 -3f2b11120139391133331133111239113333313021113426232206151123113427331e021733 -3e0133321617333e013332161511231134262322061511030056707386b306aa01020302033a -966c7b8f1c03389f71a495b25670768302ae9d78b0a0fd8d0353bd2a052c394f735a626b6d60 -b2cbfd2f02ae9d78afa1fd8d000000020056ffec041d044e000a00160048402c11060b000600 -1718080e50590810031450590316a01801901801801801701801601801501801301801df1801 -5d71717171717171003f2b00183f2b1112013939113311333130011002232202111021321203 -3426232206151416333236041dfaeeedf201e5f8eabd859d9e8d8b95a28b021efee4feea0121 -01110230feeffee1e0cbcfdcd6d7d000000000010007000003f9043a000a015c40f801000609 -0a030202060a030b0c09020f0601159b0c01840c01600c01540c01440c01200c01140c01040c -01e00c01d40c01c40c01a00c01940c01840c01600c01540c01440c01140c01040c0167d40c01 -c40c01940c01840c01540c01440c01140c01040c01db0c01c40c019b0c01840c015b0c01440c -011b0c01040c01db0c01c40c019b0c018b0c015b0c014b0c011b0c010b0c0137db0c01cb0c01 -9b0c018b0c015b0c014b0c013f0c01200c01140c01040c01e00c01d40c01c40c01a00c01940c -01840c01600c01540c01440c01200c01140c01040c01d40c01c40c01a00c01940c01840c0160 -0c0102500c012f0c01100c01000c01075e5d5d5d5d5f5d5d5d5d5d5d71717171717171717171 -7171727272727272727272725e5d5d5d5d5d5d5d5d717171717171717172727272727272725e -5d5d5d5d5d5d5d5d5d5d5d7171717171717171003f333f331112011739113311331133333130 -212301331316173f0113330265d5fe77c0ee0d382327f6bf043afd4028c5757602c20001005d -ffec04f80596002d008e401f0c001d1c2316060505161c00042f2e0c10131648490c590c690c -030f0c0123b8fff04039131648462356236623030d23010c040c23031919205f596f1d01591d -014b1d0103001d0109051d190403095f59600601520601440601060313003f335d5d5d2b0018 -3f335f5e5d5f5d5d5d2b11120039395f5e5d5d2b5d5d2b111201173911331133113311333130 -011404212003371e0133323635342e02272e0335342421321617072e0123220615141e01171e -0504f8fecffeebfdfd52b920d0b3b9c93f729e60a7ad643501150102f0fe33bc1fae9aa9b245 -82c2418176674c2b0185c3d60166257f777f7b4556382616254a5b7a4fb5c493b1217065706f -41553b2b0f1f2b3a547200010039ffec03b6044b002a0064403c070622151c1b0d00001b1506 -042b2c0d220318181f50591c1810030a5059070316102c01002c01f02c01e02c01c02c01602c -01802c013f2c01102c015d5d5d717171717272003f332b00183f332b11120039391112011739 -1133113311331133313001140623222627371e013332363534262f012e023534363332161707 -2e0123220615141e01171e0303b6e7d0cadb219f179080897f5862819b834ad3cab3d31ca20f -836e7a74305e978f7e4928012b99a6858d1f5751545440501a22284d6e50949b7e8b14484d4a -4b2e3c2a25243d4a610000020056fe5703ef044b0020002e009f4064211709091f0403281111 -031f03302f1c0f170a140e1425505914100e2b50590e16000750591504010604010b04001b40 -3001203001cf3001b0300190300120300100300150df3001c030014f3001a030018030012f30 -010f3001f03001d030010f3001085e5d5d5d717171717272725e5d5d5d5d5d7171003f325e5d -5d2b00183f2b00183f2b1112003939183f111201173911331133113311333331300122262737 -1e0133201135230e012322021110123332161733343637330615111003342e01232206151416 -33323e010224b1d21eb5127b64010d0233b277c7bbc9cd73a92e020804ab06b34883538a7e76 -8f558448fe578b801a4b51013bae68690108011b011f011169611e940736aafcc5fe3803c684 -bf65c8e0dec264bb0000000100090000054d05810008003e402607080100050302020508030a -09200a500a02300a600a900ac00af00a052f0a01070203050112003f333f33015d5d71111217 -39113311333311333130212301330117370133030ec6fdc1c9018654540184c90581fc20f9f9 -03e000000001fffd000005cc043a001401ae40ff01001107060c0f0e0313090c031103140807 -140114160808010b0815030e1303080f010c1103071576160166160154160146160136160124 -1601161601041601f41601e61601c41601b21601a41601961601861601661601541601441601 -36160114160106160169f61601e21601d41601c61601b6160196160184160174160166160146 -1601361601241601161601061601f41601e61601b61601a41601941601861601691601561601 -441601361601061601e41601d61601c41601b61601a616018916017216010160160154160124 -160104160138f41601d41601c41601a416018016017416014b1601301601241601141601fb16 -01c41601a0160194164030017b16016416014416013416011b1601f01601e41601cb1601b416 -019416018416016416013f160102101601001601085e5d5d5f5d5d5d5d5d5d5d5d7171717171 -71717171727272727272727272725e5d5d5d5d5f5d5d5d5d5d5d5d7171717171717171717171 -72727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171003f -17333f17331101335e5d11335d1112173933321133331133331133333130212303270e010323 -013313161737133313173713330496d1bd240926b9d0fed1b2b7072411e2c1bd2e1fcdb002fd -a92da9fd30043afd2118ae4a035bfd19be8b031a000000010092fe57022905cc000700264014 -05000603000308090104f55901000005f559001b003f2b00183f2b1112011739113331301311 -211523113315920197e9e9fe57077581f98d810000000001002e000004b405810007013040d9 +aebbafadbdaebdb40214012101cccbd0fe2cfeeafeebfe2ed3cc01cd011f0001008a0000013e +05cc000300764051030000050401000015f00501e00501df0501c00501b005019f0501800501 +7005011f05010f0501f00501df0501c00501b00501a005019005014f0501ff0501e00501d005 +01c005018005017005011f05015d5d5d5d5d5d5d717171717171717272727272727272727200 +3f3f1112013911333130331133118ab405ccfa3400000001002e000004b405810007013040d9 0102040207030908000405045f59050301127b09014b09013b0901240901fb0901cb0901bb09 019b09018b09017f0901025f09014f09013009010f090167df0901cf0901b009018f09015f09 014f09010f0901f00901df0901cf0901af09019f09017009015f09014009011f0901ef0901df @@ -618,385 +543,206 @@ a92da9fd30043afd2118ae4a035bfd19be8b031a000000010092fe57022905cc000700264014 0901bf0901a009019009016009014009013f09012009010f0901075e5d5d5d5d5d5d5d5d5d5d 71717171717171717172727272727272725e5d5d5d5d5d5d5d5d717171717171717171727272 727272725e5d5d5d5d5f5d5d5d5d5d5d71717171003f3f2b1100331112011739113331300111 -23112135211502d0befe1c048604e5fb1b04e59c9c0000000001009c0000040f0581000a002b -4014040802020b0c0504040306060801000174590018003f2b110033183f33332f3311120139 -113333313033352111053525331121159c0167fec2014da6015799043ce3aae5fb1899000001 -00b8fefa018100db0009002240110405000805080a0b0005a85b08009b5b08002f2b2b111201 -393911331133313025151406072336352335018126287b5e58dba86a8e41887edb0000000001 -00bb0000017e00db00030017400a030000040500019b5b00002f2b1112013911333130333533 -15bbc3dbdb00000000010010fe5701a705cc00070026401402070401070309080504f5590500 -0001f559001b003f2b00183f2b111201173911333130133533112335211110e9e90197fe5781 -067381f88b00000000010068ffec057905960019005e4039031017160809091610031a1b0f17 -010d0317171313005f59130400081008400850089008a008d008e008080c0308080c0c065f59 -0c13201b015d003f2b110033182f5f5e5d3f2b110033182f5f5e5d1112011739113311331133 -31300122001110003320131706042322240235100021320417072e010318eafefc010fe70128 -959c57fec5d0d5fec9a3016c0142e1012e47b531d904fafed3fefafefdfec501254eb6beb101 -49e10151017eb0ad3c7b8200000000010065009a044804aa0006003c40270306040004070805 -3f067f068f06030603300270028002030201000f043f046f049f04cf04050400192f5d3333cd -5d32cd5d3211120117393130133501150901156503e3fca6035a023bcd01a29afe92fe919900 -00010057ffec03ca044e001900664045000d1413060707130d031a1b101750591f147f148f14 -df140414141010200670068006d006e0060500061006600670068006c006d00607090306060a -0a0350590a161f1b015d003f2b110033182f5f5e5d713f332f5d2b1112011739113311331133 -313001141633323637170e0123220211101233321617072e012322060113888960810fb615e0 -ace3eff0e0a6db1cb90e72698f800222d8d0686c0c9cba011f01130111011fac970e5a6abe00 -000000010009000007860581001901fc40ff1819080101010014071101081001111004080707 -010b03070d0a09090d041419051b1a8b1b011bc07c7f48391b012a1b01191b010a1b01f91b01 -ea1b01d91b01ca1b01b81b01891b991ba91b03781b01691b013a1b4a1b5a1b03291b011a1b01 -0c1b0168fd1b01ec1b01dd1b01cc1b01bd1b01ab1b019c1b018b1b017c1b016b1b015c1b014b -1b013c1b012b1b011c1b010b1b01fc1b01eb1b01dc1b01cb1b01bc1b01ab1b019c1b01008d1b -017f1b016d1b015f1b014d1b012f1b3f1b021d1b010f1b01fd1b01ef1b01dd1b01cf1b01bd1b -01af1b019d1b018f1b016d1b7d1b025b1b014d1b013b1b012d1b011b1b010d1b0138fb1b01ed -1b01db1b01cd1b406f01bb1b01ad1b019b1b018d1b017b1b016d1b014b1b5b1b02391b012b1b -01191b010b1b01f91b01eb1b01dd1b01cb1b01bd1b01ab1b019d1b018b1b017d1b016b1b015d -1b014b1b013d1b01012b1b011f1b01025f1b7f1b9f1bbf1bdf1bff1b06001b01081810040903 -140d0d010812003f333311333f333333015e5d5d5f71715f7171717171717171717171717172 -72727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171 -5f71717171717171727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d71 -7171712b7111121739113311335f5e5d331133335d5d1133335d1133313021230326270e0103 -23013313161736121333131617373e01013305e7e4f4182e1a24ffe4fe61c7fd2d26183ff6b7 -f53820091b220108c7037f54d9749cfc640581fc81a8b26e01040367fc93d79523739103b200 -00000001008a0000013e05cc000300764051030000050401000015f00501e00501df0501c005 -01b005019f05018005017005011f05010f0501f00501df0501c00501b00501a005019005014f -0501ff0501e00501d00501c005018005017005011f05015d5d5d5d5d5d5d7171717171717172 -727272727272727272003f3f1112013911333130331133118ab405ccfa34000000020053008d -042003ac0008001100394020050806010f0a0e110a01110804131209000300ef5b0c0f032f03 -6f037f030403002f5d332b110033111201173911331133113311333130250135013315090115 -2101350133150901150376feae0152a8feae0154fd83feb00150a7feb101518d016d3f01731f -fe8cfe911d016d3f01731ffe8cfe911d00020053008d042003ac000800110039402003080c11 -04010d0a0a1101080413120a000500ef5b0e0f052f056f057f050405002f5d332b1100331112 -0117391133113311331133313025233509013533011501233509013533011502cea80152feb0 -a60152fcddaa0152feb0a8014f8d1d016f01741ffe8d3ffe931d016f01741ffe8d3f00020054 -000004270596001e00220052402c212018190809120000092019042324121c0f093f09020e03 -09201f209c5b1f0c18010d03181c1c155f591c04003f2b1100335f5e5d182f2b001810c65f5e -5d113911120117391133113311331133313001140e010f010e0107233e073534262322060727 -36243332040135331504272c525d50484601af02273e4e504d3c259b8c8ca40eb81a0104d6df -0100fd8fc304084b7664443b3473444568503f393946583b72848c7a0cc6d4d3fb3dc9c90001 -001d0000023c05ca0015008f40680d1301060102021504150417160a0f50590a000003060350 -5913060f01151f172f174f175f177f178f179f17070f173f177f17af17bf17df17ef17073b5f -17bf17027f178f179f17030f172f17af17df17ef170517405664481740272c48201730176017 -034017015d712b2b5d71725e5d71003f3f332b110033183f2b11120139321112391133331133 -3231300111231123353335343633321715262322061d0133150169b4989882864b342d23453e -d303b7fc4903b7837a94820c8908465c618300000001008e000003ee05cc00180060403b1511 -111208071207191a13000003120715030d50590310d01a01c01a01b01a01f01a01b01a01ff1a -01e01a01d01a01c01a01b01a01a01a01701a015d5d5d5d5d5d5d7171727272003f2b00183f33 -12393f11120139391133113311333130013e0133321615112311342e01232206151123113311 -140607013d3aa37db0a7b52a60557f99b4b4070103816a63afcefd2f02ae726f34b095fd8205 -ccfe7e3d820a0001009effec0529058100130049402c0d100704100415140e0503000a5f5900 -13201501c01501b01501a015018015017015016015015015012015015d5d5d5d5d5d5d5d7100 -3f2b00183f331112013939113311333130052224263511331114163332363511331114060402 -dbadfefe8ebfc4b9bed3be91fef7147ef0a60381fc8fc1c8cfc70364fc91abf8830000000002 -00640158044703ec00030007003f4028070300040408090504ad590f051f054f055f05cf0505 -0a030501400100ad595001d001020f010101002f5d5d2b001a1810ce5f5e5d2b111201173931 -3013352115013521156403e3fc1d03e303589494fe009494000000010065009a044804aa0006 -003c402706020003040708033004700480040304013f007f008f00030006050f023f026f029f -02cf02050200192f5d3333cd5d32cd5d32111201173931303735090135011565035afca603e3 -9a99016f016e9afe5ecd00000001002102b202fd0581000e005340320c00030609050a05040b -04011a042a04020708160801050825080204080a0e0d0d020a0a020f10df05010005f0050205 -0e03003fcc5d5d111201393911123911331139395d5d11335d5d113311173931300125170517 -070b012737253705033301c801082dfee6b977969c77bdfee82d010b0c88045a678449fa4801 -02ff0048f849866b012900000002000400000552058100070010005b40360d01000c02030605 -080003040408070312110c025f590c0c080503040012b01201501201f01201c0120190120160 -12013012012f12015d5d5d5d5d5d7171003f323f33392f2b1112011739113332113333123939 -12393931302103210323013309010706070321032627048fa1fd7ea2c6023fd90236fd5b0919 -31b4020fb51c1c019cfe640581fa7f04f11c5382fe3101d14557000005cc05cc007d05810015 -0079058100150000000000000000000000000000043a001400770000ffec00000000ffec0000 -0000ffec0000fe57000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000008000000000000b400bd00af00a00000000000000000000000000088 -007e000000ac00000000000000000000000000bf00c300ab00000000009b008d000000000000 -000000000000000000000000000000000000000000b900aa0000000000000094009900870000 -00000000000000000000000000000000000000000000006a0083008d00a400b4000000000000 -000000000060006a0079009800ac00b800a700000122013300c3006b00000000000000db00c9 -0000000000000000000000000000000000000000000001e101c9009200a8006b009200b7006b -009b0000027b02f200920252006e02d703810082008900a0009f0169008f0000016000a4015b -005e0082000000000000005e0065006f0000000000000000000000000000008a009000a5007a -0080000000000000000000000581fff3000dfcb300830089008f00960069007105cc000ffc1e -fff2003404e6000dfed400bf031f00a700ae00b500000000008100000000000000000748036a -02b60202fd930000009100670091006101d90000028d03410000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000000000000000 -000006810468001404cb0000ffecffd3fe7f008300db00aa00ba00a000cf40475b5a59585554 -535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c28 -272625242322211f181411100f0e0d0b0a090807060504030201002c20b0016045b003252011 -466123452361482d2c20451868442d2c45234660b0206120b04660b004262348482d2c452346 -2361b0206020b02661b02061b004262348482d2c45234660b0406120b06660b004262348482d -2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd -442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651582320b00d44 -235921212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a432343650a2d -2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c20 -45b00325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b006 -43b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361 -592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b52 -5845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c -01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243b00152582121 -2121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b00050 -58b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013515b58b00225 -46206861b00325b003253f2321381b2111592d2c2045b00325465058b0022546206861b00325 -b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b0 -8051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423648bb8155562 -1bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004254964234569 -b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c4b535820b003 -2549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b00e23 -44b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c45234560234560234560 -23766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1 -302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b00325 -45695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c4523 -20458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb0 -164358b00326458a586466b01f601b64b020606620581b21b04059b001615923586559b02923 -442310b029e01b2121212121592d2cb0024354584b53234b515a58381b2121591b2121212159 -2d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b0292344b00525b0 -0825082058021b0359b0042510b005252046b0042523423cb00425b0072508b0072510b00625 -2046b00425b0016023423c2058011b0059b0042510b00525b029e0b02920456544b0072510b0 -0625b029e0b00525b00825082058021b0359b00525b003254348b00425b0072508b00625b003 -25b0016043481b2159212121212121212d2c02b00425202046b004252342b0052508b0032545 -48212121212d2c02b0032520b0042508b0022543482121212d2c452320451820b00050205823 -652359236820b040505821b04059235865598a60442d2c4b53234b515a5820458a60441b2121 -592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b545838 -1b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb0 -02435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b -515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c0146234660234661 -23201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c -4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188535a58b91000 -0020885458b202010243604259b12401885158b920000040885458b2020202436042b1240188 -5458b2022002436042004b014b5258b2020802436042591bb940000080885458b20204024360 -4259b94000008063b80100885458b202080243604259b94000010063b80200885458b2021002 -43604259b12601885158b94000020063b80400885458b202400243604259b94000040063b808 -00885458b2028002436042595959595959b10002435458400a0540084009400c020d021bb101 -02435458b2054008ba010000090100b30c010d011bb18002435258b2054008b80180b109401b -b2054008ba01800009014059b9400000808855b94000020063b8040088555a58b30c000d011b -b30c000d0159595942424242422d2c451868234b51582320452064b04050587c59688a605944 -2d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201b001 -233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b0024350b001b00243 -545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d0001000000021999cf0c2df2 -5f0f3cf5001f080000000000c840f99a00000000dcb67271fba6fd930a6a07d7000000080002 -00010000000000010000073efe4e00430ab4fba6fa7a0a6a0001000000000000000000000000 -0000002e060000cd04ac0064047300850473008404730056047300570239001f0473005702aa -007f02aa000c055600a80473008801c7008904000005023900bb0239000002aa008806aa0088 -04730056040000070556005d04000039047300560556000905c7fffd0239009204e3002e0473 -009c023900b8023900bb0239001005c7006804ac006504000057078d000901c7008a04730053 -04730053047300540239001d0473008e05c7009e04ac006404ac0065031d0021055600040000 -00000000004c000000c000000174000002440000030800000428000004b000000584000005e4 -00000648000006cc000007800000081400000a4c00000a9800000a9800000afc00000cf40000 -0d9000000f1c000010340000111800001248000012b4000014b40000150000001658000016b0 -000016fc0000172c000017780000183c000018a00000196000001bc000001c5000001cd80000 -1d5c00001e1c00001ef000001fa00000203000002098000020fc000021940000223c00010000 -002e01520054005c000600020010002f005c000002a402040004000141210009013f00010139 -0055013e000101390055014201400014001f01410140001f001f013b0033013a005501380033 -01390055004001070001001f01070001009f010440aa01c0fd01affd0100fd010a4ffb0120fb -01f550281ff246281ff1462a1ff0462b1f5fef7fef020fef4fef5fef8fefafef050be5e41e1f -e3e2461f0fe20140e246161fe1e0461fcfe0dfe0efe00340e0333646e046181feeedff1fed01 -e855ec48eb55ea320055e9e8e855e7480055e600ff1fdd3ddf55df010355de3d0355dc03ff1f -0fd51fd5020fd51fd50240ca181b46cfc201bdc03c1fc150261fbcbe281fffb90150b870b880 -b803b8ffc040ffb81232461fb73fb74fb76fb77fb79fb7afb70718b60170b2a0b2b0b2030fb2 -0190b501b0b5010fb501080fb33fb3efb30380b090b002b0b0c0b0d0b0032faf3faf02a0adb0 -ad02c0add0ad022fac3fac029fab01c0aad0aa024fa98fa9022fa96fa9bfa9ffa9049c9b241f -509b016f9601bf960196461d1f9594171f0f941f947f948f94ff94053091409102809101708f -808f02908f01c08fd08f024f8c5f8c6f8c038646ff1f9f85018483311f74733f1f7350261f6f -6e3c1f6e46351f1a01185519331855073303550603ff1f6050261f5f50261f5c46311f5b5a48 -1f5a46311f1332125505010355043203556c03010c033c034c036c037c0305ef51ff40645102 -40513538464051252846cf50014946201f4846351f4746351faf4601df46ef46028046011632 -155511010f5510320f55020100550100011f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf -0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff524bb007 -505bb00188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb032 -5358b0601d594bb0645358b0401d594bb0805358b0101db11600425973747374752b2b2b2b2b -017374752b2b2b00742b2b7373752b2b2b012b2b2b002b2b2b2b2b2b012b2b002b2b012b732b -00747374757374732b012b747500732b73740173737400737474737473015e73737473730073 -732b7373012b002b012b00732b74752b2b2b2b2b2b2b2b2b2b2b012b2b742b2b5e732b002b5e -7374012b2b2b002b73735e73737301737373002b2b2b2b2b2b185e0000> -] def -/f-1-0 currentdict end definefont pop -%%EndResource -%%BeginResource: font LiberationSans-Italic -11 dict begin -/FontType 42 def -/FontName /LiberationSans-Italic def -/PaintType 0 def -/FontMatrix [ 1 0 0 1 0 0 ] def -/FontBBox [ 0 0 0 0 ] def -/Encoding 256 array def -0 1 255 { Encoding exch /.notdef put } for -Encoding 32 /space put -Encoding 40 /parenleft put -Encoding 41 /parenright put -Encoding 43 /plus put -Encoding 44 /comma put -Encoding 58 /colon put -Encoding 69 /E put -Encoding 84 /T put -Encoding 86 /V put -Encoding 91 /bracketleft put -Encoding 93 /bracketright put -Encoding 97 /a put -Encoding 99 /c put -Encoding 100 /d put -Encoding 101 /e put -Encoding 105 /i put -Encoding 109 /m put -Encoding 110 /n put -Encoding 111 /o put -Encoding 112 /p put -Encoding 115 /s put -Encoding 116 /t put -Encoding 117 /u put -Encoding 118 /v put -Encoding 119 /w put -Encoding 121 /y put -/CharStrings 27 dict dup begin -/.notdef 0 def -/plus 1 def -/u 2 def -/p 3 def -/d 4 def -/a 5 def -/t 6 def -/e 7 def -/parenleft 8 def -/colon 9 def -/space 10 def -/E 11 def -/n 12 def -/i 13 def -/y 14 def -/comma 15 def -/c 16 def -/o 17 def -/m 18 def -/s 19 def -/T 20 def -/v 21 def -/V 22 def -/w 23 def -/bracketleft 24 def -/bracketright 25 def -/parenright 26 def -end readonly def -/sfnts [ -<0001000000090080000300106376742071b9631f00001034000002886670676d7e61b6110000 -12bc000007b4676c796613e663890000009c00000f986865616409ce582200001a7000000036 -686865610d2c03cd00001aa800000024686d74786a4703f300001acc0000006c6c6f63610000 -d2ec00001b38000000706d617870045e059300001ba8000000207072657060cddf0200001bc8 -000004830001008200b40465049e000b004340260906060003030d0ca90201030f025f02020c -060200040504ad5909d6070137078707020705b3003f335d5d332b110033335f5e5d5f5d1112 -01391133331133313001112311213521113311211502bd93fe5801a89301a80260fe5401ac92 -01acfe54920000010056ffed044a043a001b003d401e03180811090e0e0d0d090a180a1c1d11 -15001505505915160e150909000f003f322f3f3f2b1112003911120139391133331133111239 -3911333130010306151433323637133303060723343637230e0123222635343713019f7e12b3 -7ec02076b4a61413aa15070353a7739495157f043afd7b583ea7c0a4025efcad5f880b852973 -59928a4064028d0000000002ffcdfe570431044e00190028004340242616162a29071f0f0308 -0829031f0f031300131a505913100c0b0f07081b002250590016003f2b00183f333f333f2b11 -120017391101331117331112391133313005222627231406032313363733140607333e013332 -161514020603220e0215141633323612353426022a7b9b2005115eb3f9170ca70d040449a277 -9daf7bdf26638d62387f717c90525e14685e0b6cfe1c05066f6e1b6f175f56bda5cbfe83b803 -d751a3f5617d8b9701497b7b7c00000000020045ffeb04a905cc00170026004e40292403141d -0a030e120e0d0d1112031227281211150e0d00141d0a03070007205059071000185059001600 -3f2b00183f2b1112001739183f333f3311120139391133331133111217391133313005222635 -3412363332161733371333030607233437230e0127323e023534262322060215141601919daf -7bdfad7b9b20051c52b4f51d09ac150549a242638d62387f717a8e565e15bda5cb017db8685e -a201a3fb138d52336d5f568b51a3f5617d8b91feb7817b7c00000002002effec042d044e0029 -003700604034300b17182a0f04202720180b0438390e2b515904080e0e1b085017010f17010b -0317171b1b1450591b1027253308335059000816003f332b11003333183f2b110033182f5f5e -5d5d1112392f12392b1112011739113333331133113331300522263537230e01232226353424 -25373635342623220607273e0133321615140703061514333237070603070e0315141633323e -0137039f5d55050653b27e8caf01090122e8136a5e777a1bb22ddfbcabc7134a0b511b210e42 -b4c777884b2b614d619c66100a4d4c407e65a882b9be0403621d5b5755571d9385a087405dfe -86302849077010022204032539573e4b5e53864d0001005dffec0280052c0018003f40210c09 -09120303191a001a101a0214030f06090651590c090a0a090f001450590016003f2b00183f33 -2f11332b110033015f5e5d111239113333113331300522263534371323373337330733072303 -0615143332370706011355610f7e7d1a7f69782fc81ac87d0c5a2a3a1363146654374b028f83 -f2f283fd7b3c23580e85180000020045ffec0427044e001800200059402e201900000f191608 -0909160f16212208080005200050590d201d2002140420200c13131d505913100c0550590c16 -003f2b00183f2b11120039182f5f5e5d2b11120039182f111201393911331133113311331112 -393130010607141633323637170e012322263534122433321615140727373426232206070100 -06038586619e2c8a49e1a0c9df8e0102a1cde4189f04817986b72501f7234e858e60533f8378 -dfcac9013fb1cebc69648a487c84ab9d000000010060fe58035705cc000a001640090207070b -0c041b0000003f3f111201391133313001001110132302111000250357fdbecfaed6012c011d -05ccfe03fd37fe7bfed70128019601740266dc00000000020051000001e7043a000300070027 -4013030007040004090804059c5b0401009c5b010f003f2b00182f2b11120139391133113331 -301337330701373307fb29c329fe9329c329036bcfcffc95cfcf0001003f000005690581000b -00474028020900000d0c05085f59ba05018905017805010f050108030505000101045f590103 -00095f590012003f2b00183f2b11120039182f5f5e5d5d5d5d2b111201391133323130330121 -0721032107210321073f011104191efca658031e1efce25f03831e05819cfe3c9afe159c0001 -002200000416044d001b00474025031811080e0a0e0d0d090a180a1d1c08011a0b1105150015 -05505915100e0d0f1b0a090015003f3232323f333f2b11120017391112013939113333113311 -12393911333130211336353423220607032313363733140607333e013332161514070302cd7e -12b37ec02076b4a61413aa15070353a7739495157f0285583ea7c0a4fda203535f880b852973 -59928a4064fd7300000000020021000001f505cc00030007004a400b00040408097009c00902 -09b8ffc040212f38483f09010f091f098f099f09af09ef09060a0306050f0704150100535901 -00003f2b00183f333f33015f5e5d712b71111239113331300137330701133303011f22b422fe -4ed2b4d30520acacfae0043afbc600000001ff8cfe570467043a0017004640241214090f0b0a -0f0a1318131900192019020b031312120f090b0a0f14091500055059001b003f2b00183f333f -331239332f33015f5e5d113311123939113311333332313013222737163332363f010333131e -01173e010133010e0210483c1f2d205f91461bd9b7700f1a010a2001b5c7fd8e6f8793fe570e -8608807a2f042efdaa50b51b16400320fbc6c19b4d00000000010025fefa014b00db00090024 -4012060305000105010b0a0500a85b04059b5b04002f2b2b1112013939113311333331301323 -3637233733070e01a07b7819582ac3201242fefa897ddba85f96000000010043ffec03e9044e -0018004840281708020303100f080f191a0c1350591f100110100c10000210026002030e0302 -0205050050590516003f2b110033182f5f5e5d3f332f5d2b1112013939113333113311333130 -25323717022122263534123633321617072e0123220602151001d5cd549c79feb8c0ce91efae -a9c50ab1066c5b7e9c567ae631febddac5c80158a3aa9419616987feda8ffef500020043ffec -0432044d000e001c0032401b0f00150800081e1d001e101e021f030c1150590c100518505905 -16003f2b00183f2b015f5e5d111239391133113331300114020e012322263536123633321607 -102322060215141633323e0204325095d88ac4e4048cf8b7d2debaf887a35a807a677d5e3b02 -ab82fee7c361eccbcc013ca2dbc7011e8bfee684949b4593e4000000000100220000064b044d -002d016040fb12090f0a0f0e0e0a0b2c1903032d00261f1f000b032e2f922f0101802f01542f -742f02202f01142f01542f742f842fa42fb42fd42ff42f072b2f3b2f02002f102f0267f42f01 -e02f01d42f01b02f01442f742f942fa42f04102f01042f01d42ff42f02bb2f01742f015b2f01 -302f01242f01002f01f42f01d02f01c42f01ab2f01742f01602f01342f542f020b2f0137f42f -01db2f01942f016b2f01502f01242f442f020b2f01542f842fb42fd42fe42ff42f060b2f2b2f -02fb2f01e42f019b2fcb2f02742f015b2f01342f01102f202f0202002f0107031c2950591c10 -1912092c0124210c120716001606505916100e0f2223230a0b0b2d0015003f32322f33322f33 -3f3f2b11120017391133183f2b015f5e5d5f5d5d5d5d5d5d5d7171727272727272725e5d5d5d -5d5d5d5d5d71717171717171727272727272725e5d5d5d717171715f71111217391133113333 -113333113333113311123939313021133635342623220607032313363733140607333e013332 -16173e0133321615140703231336353426232206070302947c194c5674ad1b76b3a61413aa15 -0703499366798e0e53a1688791157fb27c194c5674ac1c76027a7d314b4fc6a0fda403535f88 -0b8529725a77718266928a4064fd73027a7d314b4fc3a0fda10000010005ffec03d6044b0027 -004e402a070620140d001a19190014060428290d200317171d5159001a701a020b031a1a1710 -030a515907070316003f332f2b00183f332f5f5e5d2b11120039391112011739113311331133 -1133313001140623222627371e01333236353426272e02353436332017072e0123220615141e -01171e02038bf8eaaecd2993218b758f9466a5808044e8d301622ca3167a677c852a4f8f7f81 -48013da2af757e385850615d3e53332a506b47919dff194f464f482a3a2d2d28527000000001 -00b80000055c05810007002a4014010204020807070903000405045f590503020112003f333f -2b1100333311013311123939113331300103231321372107035af4bef4fe1c1e04861e04e5fb -1b04e59c9c000001007000000462043a000c003c4020030201000702070d0b0c0c0e200e400e -500e800e040c0b0b070103020f000115003f333f331239332f33015d11331133123939113333 -113331302123033313161f01373637013301fbd5b6bb65090a041a2d300180c4043afd404474 -35355e5802c20000000100b1000005f5058100080028401201000503020502090708080a0702 -03050112003f333f3311013311331239391133113333313021230133131737013302a5c6fed2 -c2c623850244d00581fc20f9f903e0000001006600000635043a001401314036130001110e0d -0306070b09080808010b0308110414150714010d03141606161616461676168616961606e616 -01b916c9160264160116b8ffc04027696c480916016716406265487616015916010616461602 -f41601361666169616d6160424160116b8ffc040414548489916a916c9160386160144160106 -16261636160337a916e91602961601391649165916791604161601f91601d616e61602691679 -16891603361646160216b8ffc0400c151848921601018016010216b8ffc0401f0b0e480f163f -160207141313080e0d0d08110b030b0709080f000101060715003f33332f333f331239391133 -11332f3311332f33015e5d2b5f5d5f5d2b71717171727272725e5d5d5d5d2b7171717272722b -5e5d2b5d5d5d7111335f5e5d111217395d1133113333113333113333323130212303270e0101 -2303331317370133131615360133042cd125061e30feb0d05cb22807510155c12c06210184b0 -02baec4b71fd16043afd21c6be02e7fd196c524f035600000001ffd9fe5702e205cc0007002c -4016060004020209050000080104f55901000005f559001b003f2b00183f2b11013311331133 -1133123931300301210723013307270172019719e9febfe919fe57077581f98d810000000001 -ff57fe57026005cc00070028401405000306060900080702f559071b0603f5590600003f2b00 -183f2b11013311331133123931300337330123372101a919e80141e9190197fe8dfe57810673 -81f88b0000000001ff39fe58023005cc000a001640090207070b0c0400001b003f3f11120139 -113331300300111003331211100005c70242cfaed6fed4fee3fe5801fd02c901850129fed8fe -6afe8cfd9adc05cc05de007d058100150079058100150000000000000000000000000000043a +23112135211502d0befe1c048604e5fb1b04e59c9c000000000200890000013d05cc00030007 +006e40480307070004040809050f0415010053590100ff0901e00901df0901c00901b009019f +09018009017009011f0901000901f00901df0901c00901b00901a009019009014f09011f0901 +5d7171717171717172727272727272727272003f2b00183f3f11120139113333113331301335 +33150311331189b4b4b40520acacfae0043afbc60001008800000623044e0029017e40ff1829 +00002109212012080920092b2a1c2550591c10181100151504505915100c0f21090015642b01 +4b2b013f2b012b2b011f2b010f2b01eb2b01df2b01bb2b01ab2b018b2b017b2b016f2b013b2b +011f2b010b2b016aeb2b01cb2b01bb2b01af2b018b2b017f2b015b2b014f2b011b2b01fb2b01 +ef2b01df2b01cb2b01bb2b01af2b01942b01642b014b2b012b2b011b2b01042b01f42b01db2b +01ab2b018b2b017f2b016b2b01342b011b2b010f2b0139fb2b01db2b01bb2b01a02b01942b01 +742b015b2b014b2b012b2b011f2b010b2b01fb2b01eb2b01cb2b01a42b017b2b015b2b014b2b +011b2b01f42b01d02b0102c02b01a02b01902b01602b014f2b400b01302b012f2b01002b0108 +5e5d5d5d5d5d5d5d5d5f5d5d717171717171717172727272727272727272725e5d5d5d5d5d5d +5d5d5d7171717171717171717171717272727272727272725e5d5d5d5d5d5d5d5d5d5d717171 +717171003f32323f3f2b1112003939183f2b1112013939113333113311123911333331302111 +3426232206151123113427331e0217333e0133321617333e0133321615112311342623220615 +11030056707386b306aa01020302033a966c7b8f1c03389f71a495b25670768302ae9d78b0a0 +fd8d0353bd2a052c394f735a626b6d60b2cbfd2f02ae9d78afa1fd8d0000000200bb0000017e +043a0003000700274013030707040004090804059c5b0401009c5b010f003f2b00182f2b1112 +0139391133113331301335331503353315bbc3c3c3036bcfcffc95cfcf00000200a800000565 +058100090013002c40170f050a0005001415060e5f590603050f5f5905122015015d003f2b00 +183f2b111201393911331133313001140204232111212000031000290111213236120565aafe +c8ccfdf101d201660185c0fee1fef0fef1013a9beb7e02cfdafeb9ae0581fe99feb501060113 +fbb18801000000020056ffec041d044e000a00160048402c11060b0006001718080e50590810 +031450590316a01801901801801801701801601801501801301801df18015d71717171717171 +003f2b00183f2b11120139391133113331300110022322021110213212033426232206151416 +333236041dfaeeedf201e5f8eabd859d9e8d8b95a28b021efee4feea012101110230feeffee1 +e0cbcfdcd6d7d000000000020084ffec041d05cc00170023005d40371e050e0e0d18000d0024 +2505110215151b505915100d000a15022150590216b025013f25019025017025011f2501ff25 +01e02501c025015d5d5d7171717272003f2b00183f3f3f2b1112003939111201393911331133 +1133333130011021222627231406072336351133111407333e01333212033426232206151416 +333236041dfe727ba333020802ae06b4040432a57acdc1bd7887988b889988790222fdca5963 +1f7f0a36a904edfe594158685afeecfee2e3c4d0e2d5cbc90001000cfe58022b05cc000e0022 +4010070003040b0a00040a030f100a00031b003f3f1112011739113311331133313001100207 +2336121110022733161211022bb5bcaebcaeafbbaebdb40210fedffe34cbd201d10117011701 +d2d1ccfe33fee100000000010057ffec03ca044e001900664045000d1413060707130d031a1b +101750591f147f148f14df140414141010200670068006d006e0060500061006600670068006 +c006d00607090306060a0a0350590a161f1b015d003f2b110033182f5f5e5d713f332f5d2b11 +12011739113311331133313001141633323637170e0123220211101233321617072e01232206 +0113888960810fb615e0ace3eff0e0a6db1cb90e72698f800222d8d0686c0c9cba011f011301 +11011fac970e5a6abe0000000001008800000288044e00130023401006131300000c14150f06 +0a10040f0015003f3f3f3333111201393911331133313033113427331615333e013332171526 +23220615118e06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4fdcc00000001 +00a8000004fe0581000b00544032050909000a030700040c0d05085f598f0501ba0501790589 +05020f050108030505000101045f59010300095f590012200d015d003f2b00183f2b11120039 +182f5f5e5d5d5d712b1112011739113311333130331121152111211521112115a8042dfc9203 +32fcce039705819cfe3c9afe159c000000010088000003ee044e001a0061403c1209090a001a +0a1a1b1c1216001605505916100d0f0a0015d01c01c01c01b01c01f01c01b01c01ff1c01e01c +01d01c01c01c01b01c01a01c01701c015d5d5d5d5d5d5d7171727272003f323f3f2b11120039 +111201393911331133113331302111342e01232206151123113427331e0217333e0133321615 +1103392a5c598296b406aa01020302033ea379b2a502ae6b7634b29efd8d0353bd2a052c394f +705db1ccfd2f00010005fe5703fc043a001601e440ff13080f11120a0909030f120418170813 +0f131711090f00055059001b9218018218017418016418015218014218013418012418011218 +01021801f41801e41801d21801c21801b41801a4180192180182180174180164180156180142 +180134180124180116180102180167f41801e41801d61801c21801b41801a418019618018218 +01741801641801561801421801341801241801161801021801f41801e41801d61801c2180101 +b01801a01801941801841801701801601801541801441801301801201801141801041801f018 +01e01801d41801c41801b01801a0180194180184180170180160180154180144180130180120 +180114180104180137e018405a01d41801c41801a01801941801841801601801541801441801 +201801141801041801e01801d41801c41801a018019418018418016018010250180130180120 +1801001801c018019018018018015018012f1801101801001801075e5d5d5d5d5d5d5d717171 +715f717171717171717272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d +7171717171717171717171715f71717171727272727272727272727272727272725e5d5d5d5d +5d5d5d5d5d5d5d5d5d5d5d5d71717171717171717171003f2b00183f33113333113311120117 +39113311331133333130132227351633323f010133131e0217371333010e02bf4a32262ea862 +11fe53c0e4050e4c0346edbefe6043748dfe570b8706f72b0435fdaa0e27de0dc502b1fbc6ad +a953000000010007000003f9043a000a015c40f8010006090a030202060a030b0c09020f0601 +159b0c01840c01600c01540c01440c01200c01140c01040c01e00c01d40c01c40c01a00c0194 +0c01840c01600c01540c01440c01140c01040c0167d40c01c40c01940c01840c01540c01440c +01140c01040c01db0c01c40c019b0c01840c015b0c01440c011b0c01040c01db0c01c40c019b +0c018b0c015b0c014b0c011b0c010b0c0137db0c01cb0c019b0c018b0c015b0c014b0c013f0c +01200c01140c01040c01e00c01d40c01c40c01a00c01940c01840c01600c01540c01440c0120 +0c01140c01040c01d40c01c40c01a00c01940c01840c01600c0102500c012f0c01100c01000c +01075e5d5d5d5d5f5d5d5d5d5d5d717171717171717171717171727272727272727272725e5d +5d5d5d5d5d5d5d717171717171717172727272727272725e5d5d5d5d5d5d5d5d5d5d5d717171 +7171717171003f333f331112011739113311331133333130212301331316173f0113330265d5 +fe77c0ee0d382327f6bf043afd4028c5757602c20001005dffec04f80596002d008e401f0c00 +1d1c2316060505161c00042f2e0c10131648490c590c690c030f0c0123b8fff0403913164846 +2356236623030d23010c040c23031919205f596f1d01591d014b1d0103001d0109051d190403 +095f59600601520601440601060313003f335d5d5d2b00183f335f5e5d5f5d5d5d2b11120039 +395f5e5d5d2b5d5d2b111201173911331133113311333130011404212003371e013332363534 +2e02272e0335342421321617072e0123220615141e01171e0504f8fecffeebfdfd52b920d0b3 +b9c93f729e60a7ad643501150102f0fe33bc1fae9aa9b24582c2418176674c2b0185c3d60166 +257f777f7b4556382616254a5b7a4fb5c493b1217065706f41553b2b0f1f2b3a547200010039 +ffec03b6044b002a0064403c070622151c1b0d00001b1506042b2c0d220318181f50591c1810 +030a5059070316102c01002c01f02c01e02c01c02c01602c01802c013f2c01102c015d5d5d71 +7171717272003f332b00183f332b111200393911120117391133113311331133313001140623 +222627371e013332363534262f012e0235343633321617072e0123220615141e01171e0303b6 +e7d0cadb219f179080897f5862819b834ad3cab3d31ca20f836e7a74305e978f7e4928012b99 +a6858d1f5751545440501a22284d6e50949b7e8b14484d4a4b2e3c2a25243d4a610000020056 +fe5703ef044b0020002e009f4064211709091f0403281111031f03302f1c0f170a140e142550 +5914100e2b50590e16000750591504010604010b04001b403001203001cf3001b03001903001 +20300100300150df3001c030014f3001a030018030012f30010f3001f03001d030010f300108 +5e5d5d5d717171717272725e5d5d5d5d5d7171003f325e5d5d2b00183f2b00183f2b11120039 +39183f1112011739113311331133113333313001222627371e0133201135230e012322021110 +123332161733343637330615111003342e0123220615141633323e010224b1d21eb5127b6401 +0d0233b277c7bbc9cd73a92e020804ab06b34883538a7e768f558448fe578b801a4b51013bae +68690108011b011f011169611e940736aafcc5fe3803c684bf65c8e0dec264bb000000010009 +0000054d05810008003e402607080100050302020508030a09200a500a02300a600a900ac00a +f00a052f0a01070203050112003f333f33015d5d711112173911331133331133313021230133 +0117370133030ec6fdc1c9018654540184c90581fc20f9f903e000000001fffd000005cc043a +001401ae40ff01001107060c0f0e0313090c031103140807140114160808010b0815030e1303 +080f010c11030715761601661601541601461601361601241601161601041601f41601e61601 +c41601b21601a4160196160186160166160154160144160136160114160106160169f61601e2 +1601d41601c61601b61601961601841601741601661601461601361601241601161601061601 +f41601e61601b61601a41601941601861601691601561601441601361601061601e41601d616 +01c41601b61601a616018916017216010160160154160124160104160138f41601d41601c416 +01a416018016017416014b1601301601241601141601fb1601c41601a0160194164030017b16 +016416014416013416011b1601f01601e41601cb1601b416019416018416016416013f160102 +101601001601085e5d5d5f5d5d5d5d5d5d5d5d71717171717171717172727272727272727272 +5e5d5d5d5d5f5d5d5d5d5d5d5d71717171717171717171717272727272727272727272727272 +5e5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171003f17333f17331101335e5d11335d11 +12173933321133331133331133333130212303270e0103230133131617371333131737133304 +96d1bd240926b9d0fed1b2b7072411e2c1bd2e1fcdb002fda92da9fd30043afd2118ae4a035b +fd19be8b031a000000010092fe57022905cc00070026401405000603000308090104f5590100 +0005f559001b003f2b00183f2b1112011739113331301311211523113315920197e9e9fe5707 +7581f98d810000000001009c0000040f0581000a002b4014040802020b0c0504040306060801 +000174590018003f2b110033183f33332f331112013911333331303335211105352533112115 +9c0167fec2014da6015799043ce3aae5fb189900000100b8fefa018100db0009002240110405 +000805080a0b0005a85b08009b5b08002f2b2b11120139391133113331302515140607233635 +2335018126287b5e58dba86a8e41887edb000000000100bb0000017e00db00030017400a0300 +00040500019b5b00002f2b111201391133313033353315bbc3dbdb00000000010010fe5701a7 +05cc00070026401402070401070309080504f55905000001f559001b003f2b00183f2b111201 +173911333130133533112335211110e9e90197fe5781067381f88b00000000010068ffec0579 +05960019005e4039031017160809091610031a1b0f17010d0317171313005f59130400081008 +400850089008a008d008e008080c0308080c0c065f590c13201b015d003f2b110033182f5f5e +5d3f2b110033182f5f5e5d111201173911331133113331300122001110003320131706042322 +240235100021320417072e010318eafefc010fe70128959c57fec5d0d5fec9a3016c0142e101 +2e47b531d904fafed3fefafefdfec501254eb6beb10149e10151017eb0ad3c7b820000000001 +0065009a044804aa0006003c402703060400040708053f067f068f0603060330027002800203 +0201000f043f046f049f04cf04050400192f5d3333cd5d32cd5d321112011739313013350115 +0901156503e3fca6035a023bcd01a29afe92fe91990000020053008d042003ac000800110039 +4020050806010f0a0e110a01110804131209000300ef5b0c0f032f036f037f030403002f5d33 +2b11003311120117391133113311331133313025013501331509011521013501331509011503 +76feae0152a8feae0154fd83feb00150a7feb101518d016d3f01731ffe8cfe911d016d3f0173 +1ffe8cfe911d00020053008d042003ac000800110039402003080c1104010d0a0a1101080413 +120a000500ef5b0e0f052f056f057f050405002f5d332b110033111201173911331133113311 +33313025233509013533011501233509013533011502cea80152feb0a60152fcddaa0152feb0 +a8014f8d1d016f01741ffe8d3ffe931d016f01741ffe8d3f00020054000004270596001e0022 +0052402c212018190809120000092019042324121c0f093f09020e0309201f209c5b1f0c1801 +0d03181c1c155f591c04003f2b1100335f5e5d182f2b001810c65f5e5d113911120117391133 +113311331133313001140e010f010e0107233e07353426232206072736243332040135331504 +272c525d50484601af02273e4e504d3c259b8c8ca40eb81a0104d6df0100fd8fc304084b7664 +443b3473444568503f393946583b72848c7a0cc6d4d3fb3dc9c90001001d0000023c05ca0015 +008f40680d1301060102021504150417160a0f50590a0000030603505913060f01151f172f17 +4f175f177f178f179f17070f173f177f17af17bf17df17ef17073b5f17bf17027f178f179f17 +030f172f17af17df17ef170517405664481740272c48201730176017034017015d712b2b5d71 +725e5d71003f3f332b110033183f2b1112013932111239113333113332313001112311233533 +35343633321715262322061d0133150169b4989882864b342d23453ed303b7fc4903b7837a94 +820c8908465c618300000001008e000003ee05cc00180060403b1511111208071207191a1300 +0003120715030d50590310d01a01c01a01b01a01f01a01b01a01ff1a01e01a01d01a01c01a01 +b01a01a01a01701a015d5d5d5d5d5d5d7171727272003f2b00183f3312393f11120139391133 +113311333130013e0133321615112311342e01232206151123113311140607013d3aa37db0a7 +b52a60557f99b4b4070103816a63afcefd2f02ae726f34b095fd8205ccfe7e3d820a0001009e +ffec0529058100130049402c0d100704100415140e0503000a5f590013201501c01501b01501 +a015018015017015016015015015012015015d5d5d5d5d5d5d5d71003f2b00183f3311120139 +39113311333130052224263511331114163332363511331114060402dbadfefe8ebfc4b9bed3 +be91fef7147ef0a60381fc8fc1c8cfc70364fc91abf883000000000200640158044703ec0003 +0007003f4028070300040408090504ad590f051f054f055f05cf05050a030501400100ad5950 +01d001020f010101002f5d5d2b001a1810ce5f5e5d2b11120117393130133521150135211564 +03e3fc1d03e303589494fe009494000000010065009a044804aa0006003c4027060200030407 +08033004700480040304013f007f008f00030006050f023f026f029f02cf02050200192f5d33 +33cd5d32cd5d32111201173931303735090135011565035afca603e39a99016f016e9afe5ecd +0000000200a8000005680581000d00160057402f010c0c1309130303040e09000d0d09040317 +180c0213025f591313000505125f5905030400128018017018012018015d5d5d003f323f2b11 +120039182f2b1100331112011739113311331133113311123911333130210121112311213204 +1514060701033426232111213236048cfe92fe49bf0297ee0103b7a10190f8a79dfe3b01cd97 +a50249fdb70581d5be9dd61cfda103ec7b81fdf88d00000300a8000004ea0581000d0016001e +0068403a0b1308131b1b040e081700000804031f200b131a131a5f59132413024d0f1301033e +1301040f130110051313040505125f590503041b5f590412003f2b00183f2b11120039182f5f +5e5d5f5d5f712b2b111200391112011739113311331133113311123931300114042321112120 +111406071e01013426232111213236133429011121323604eafeeef4fdc4020001f08c80a8b6 +feee9c94febf0141999751fea2fe9c0173afa0018dbcd10581feaa7daa1d14b901fa7262fe42 +73fdfff9fe04820000000001002102b202fd0581000e005340320c00030609050a05040b0401 +1a042a04020708160801050825080204080a0e0d0d020a0a020f10df05010005f00502050e03 +003fcc5d5d111201393911123911331139395d5d11335d5d113311173931300125170517070b +012737253705033301c801082dfee6b977969c77bdfee82d010b0c88045a678449fa480102ff +0048f849866b012900000001005b01d0024f02700003001f4011000304050100bb599f01cf01 +022f010101002f5d712b11120139393130133521155b01f401d0a0a000020004000005520581 +00070010005b40360d01000c02030605080003040408070312110c025f590c0c080503040012 +b01201501201f01201c012019012016012013012012f12015d5d5d5d5d5d7171003f323f3339 +2f2b111201173911333211333312393912393931302103210323013309010706070321032627 +048fa1fd7ea2c6023fd90236fd5b091931b4020fb51c1c019cfe640581fa7f04f11c5382fe31 +01d14557000005cc05cc007d058100150079058100150000000000000000000000000000043a 001400770000ffec00000000ffec00000000ffec0000fe570000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000008000000000000b400bd00af -00a000d600b1009d00a8009600870088007e00a000ac000000000000000005cc012000bf00c3 -00ab000000bc009b008d00aa00000000000000000000000000000000000000000581011200b9 -00af007200b200a9009400990080000000000000000000000000000000000000000005810112 -006a009100ae00b4005b004c0074006401d90181006a00b800ac0095008a016500f601080122 -013300ed00e900c300a5008800db00cf00c900c30039002b00a0000000000000000000000000 -01e101c9009200a8006b009200b7006b009b0000000002f2008a0292006e02d60381004c0089 -00a0005e000000d70000000000a4015b005e0082007400000000005e0065006f000000000000 -00000000000000000088008d00a5007a00800000000000000000fee50581fff3000dfcb30083 -0088008d00960069007105cc000ffc1efff2003404e6000dfed400bf031f00a9000000b50000 +00a00000000000000000000000000088007e000000ac00000000000000000000000000bf00c3 +00ab00000000009b008d000000000000000000000000000000000000000000000000000000b9 +00aa000000000000009400990087000000000000000000000000000000000000000000000000 +006a0083008d00a400b4000000000000000000000060006a0079009800ac00b800a700000122 +013300c3006b00000000000000db00c900000000000000000000000000000000000000000000 +01e101c9009200a8006b009200b7006b009b0000027b02f200920252006e02d7038100820089 +00a0009f0169008f0000016000a4015b005e0082000000000000005e0065006f000000000000 +0000000000000000008a009000a5007a0080000000000000000000000581fff3000dfcb30083 +0089008f00960069007105cc000ffc1efff2003404e6000dfed400bf031f00a700ae00b50000 0000008100000000000000000748036a02b60202fd930000009100670091006101d90000028d -0341000001530145019700e3007904d103d10727feef004e00880057006400ad00bd00b4035c -000e0078fff20098005f00000000000000000000000000000000000000000000000000000000 -00000000000000000000000000000000000006810468001404cb0000ffecffd3fe7f008300dd +0341000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000006810468001404cb0000ffecffd3fe7f008300db 00aa00ba00a000cf40475b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e 3d3c3b3a393837363531302f2e2d2c28272625242322211f181411100f0e0d0b0a0908070605 04030201002c20b0016045b003252011466123452361482d2c20451868442d2c45234660b020 @@ -1049,53 +795,49 @@ b202400243604259b94000040063b80800885458b2028002436042595959595959b100024354 2320452064b04050587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb1 0102060cb00a236542b00b234201b001233f00b002233fb10102060cb006236542b0072342b0 0116012d2cb080b0024350b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c -8a10e52d000100000002199927f1cfbc5f0f3cf5001f080000000000c84e81b500000000dcb6 -7226fab0fd930ae3081d00020008000200010000000000010000073efe4e00430aaafab0fa56 -0ae300640015000000000000000000000000001b0600000004ac0082047300560473ffcd0473 -00450473002e0239005d0473004502aa006002390051023900000556003f0473002201c70021 -0400ff8c02390025040000430473004306aa00220400000504e300b804000070055600b105c7 -00660239ffd90239ff5702aaff3900000000000000000000007400000110000001d40000029c -000003a000000430000004f400000544000005940000059400000610000006b40000072c0000 -07cc0000081c000008b80000094c00000b3800000c0000000c5400000cc800000d1c00000ea0 -00000ef800000f4c00000f9800010000001b015200540065000600020010002f005c00000378 -03aa0004000141380009013f000101390055013e000101390055014201400014001f01410140 -001f001f013b0033013a005501380033013900550080010f000100f0010f0001004f010f00af -010f000200ef010f00010080010f0001003f010f00010000010f0001004001070001001f0107 -0001009f0104405201c0fd01affd0100fd010a4ffb0120fb01f550281ff246281ff0462b1f5f -ef7fef020fef4fef5fef8fefafef050be5e41e1fe3e2461f0fe20140e246161fe1e0461fbfe0 -cfe0dfe00340e0333646e046181fbe011c003d011b0055011a003d0119405855eeedff1fed02 -e855ec48eb55ea320055e9e8e855e8010055e7480055e600ff1fdd3ddf55df010355de3d0355 -dc03ff1f0fd5010fd5ffd502ffd5019fd401d3d23c1fbfc201c150261f60be70be80be0340b8 -60b870b803b8ffc04059b81232460fb73fb7020fb33fb3efb3030960b070b00290b0a0b0b0b0 -0380ad90ad02a0adb0ad027fab01a0aab0aa022fa96fa9020fa94fa99fa9dfa9040ba09f2b1f -409f09114600a110a1023a40a150a102b0a1c0a1d0a103b8ffc04020a12024469e9b241f9d9b -241f9c9b241f509b01985a481f9796241fd096e09602b8ffc0b4960d11460fb8010a4056010f -957f95025f946f94cf94df94040f941f947f948f94ff940593923c1f4092171d464092090c46 -0f91015f919f91af91bf91ef91ff910640911c2546a08fb08f02c08fd08fe08f038e8d461f30 -8d408d02808d016fbe010c000100e0010c0001ffc0010c409a0e1146208a308a028584461f81 -6dff1f8003ff1fcf75df75ef7503ef750174733f1f7350261f7246351f7146351f4070262c46 -20703070026f46351f6e46351f1a01185519331855073303550603ff1fa76d01296d016c03ff -1f615f2f1f605f421f5f50261f5e5a321f5c46311f5b5a481f5a46311f133212550501035504 -3203556f03010f033f034f036f037f0305965901b052c052d05203b8ffc0b3522d3446b8ffc0 -409b52202446ef51ff510240513538464051252846cf5001204e292f46084e1f2246094d194d -02484d584dd84de84df84d05984d01184c242d46184c1d2046984ca84c024b46371f4946201f -4846351f4746351faf4601df46ef46028046011632155511010f5510320f5502010055010001 -1f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f0001 -8016010501b80190b154532b2b4bb807ff524bb007505bb00188b02553b00188b040515ab006 -88b000555a5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0 -805358b0101db11600425973747374752b2b2b2b2b017374752b2b2b002b732b2b7374752b2b -742b2b732b2b7301730073752b2b2b012b2b2b002b2b2b2b2b73732b2b2b2b012b2b742b002b -2b2b2b73742b2b012b732b73740073742b73742b73742b2b2b73747373012b732b2b00732b2b -2b2b73755e73012b2b005e737401737300737473745e73732b730173002b73012b7300737475 -2b2b2b2b2b2b2b2b2b2b2b2b2b2b012b2b742b2b5e732b002b5e7374012b2b002b73735e7373 -730173737300737373737474752b2b2b2b2b2b185e0000> +8a10e52d0001000000021999f24c83405f0f3cf5001f080000000000c840f99a00000000dd7b +2e16fba6fd930a6a07d700000008000200010000000000010000073efe4e00430ab4fba6fa7a +0a6a000100000000000000000000000000000032060000cd04ac006404730085047300840473 +0056047300570239001f0473005702aa007f01c7008a04e3002e01c7008906aa0088023900bb +0239000005c700a8047300560473008402aa000c0400005702aa0088055600a8047300880400 +0005040000070556005d04000039047300560556000905c7fffd023900920473009c023900b8 +023900bb0239001005c7006804ac00650473005304730053047300540239001d0473008e05c7 +009e04ac006404ac006505c700a8055600a8031d002102aa005b05560004000000000000004c +000000c000000174000002440000030800000428000004b000000584000005e4000006740000 +07cc0000086000000a5800000aa400000aa400000b2400000bc000000c8c00000cf000000db0 +00000e1400000e9800000f4c0000118400001310000014280000150c0000163c000016a80000 +18a8000018f40000194c00001998000019c800001a1400001ad800001b3c00001bc400001c48 +00001d0800001ddc00001e8c00001f1c00001f8400001fe8000020940000216c000022040000 +223c000022e400010000003201520054005c000600020010002f005c000002a4020400040001 +41210009013f000101390055013e000101390055014201400014001f01410140001f001f013b +0033013a00550138003301390055004001070001001f01070001009f010440aa01c0fd01affd +0100fd010a4ffb0120fb01f550281ff246281ff1462a1ff0462b1f5fef7fef020fef4fef5fef +8fefafef050be5e41e1fe3e2461f0fe20140e246161fe1e0461fcfe0dfe0efe00340e0333646 +e046181feeedff1fed01e855ec48eb55ea320055e9e8e855e7480055e600ff1fdd3ddf55df01 +0355de3d0355dc03ff1f0fd51fd5020fd51fd50240ca181b46cfc201bdc03c1fc150261fbcbe +281fffb90150b870b880b803b8ffc040ffb81232461fb73fb74fb76fb77fb79fb7afb70718b6 +0170b2a0b2b0b2030fb20190b501b0b5010fb501080fb33fb3efb30380b090b002b0b0c0b0d0 +b0032faf3faf02a0adb0ad02c0add0ad022fac3fac029fab01c0aad0aa024fa98fa9022fa96f +a9bfa9ffa9049c9b241f509b016f9601bf960196461d1f9594171f0f941f947f948f94ff9405 +3091409102809101708f808f02908f01c08fd08f024f8c5f8c6f8c038646ff1f9f8501848331 +1f74733f1f7350261f6f6e3c1f6e46351f1a01185519331855073303550603ff1f6050261f5f +50261f5c46311f5b5a481f5a46311f1332125505010355043203556c03010c033c034c036c03 +7c0305ef51ff4064510240513538464051252846cf50014946201f4846351f4746351faf4601 +df46ef46028046011632155511010f5510320f55020100550100011f1f0f3f0f5f0f7f0f040f +0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b15453 +2b2b4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b58b101018e +59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101db116004259 +73747374752b2b2b2b2b017374752b2b2b00742b2b7373752b2b2b012b2b2b002b2b2b2b2b2b +012b2b002b2b012b732b00747374757374732b012b747500732b737401737374007374747374 +73015e73737473730073732b7373012b002b012b00732b74752b2b2b2b2b2b2b2b2b2b2b012b +2b742b2b5e732b002b5e7374012b2b2b002b73735e73737301737373002b2b2b2b2b2b185e0000> ] def -/f-2-0 currentdict end definefont pop +/f-1-0 currentdict end definefont pop %%EndResource -%%BeginResource: font f-3-1 -%!FontType1-1.1 f-3-1 1.0 +%%BeginResource: font f-2-1 +%!FontType1-1.1 f-2-1 1.0 11 dict begin -/FontName /f-3-1 def +/FontName /f-2-1 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def @@ -1131,30 +873,30 @@ cleartomark %%EndSetup %%Page: 1 1 %%BeginPageSetup -%%PageBoundingBox: 7 8 420 544 +%%PageBoundingBox: 7 8 381 616 %%EndPageSetup -q 7 8 413 536 rectclip -1 0 0 -1 0 551 cm q +q 7 8 374 608 rectclip +1 0 0 -1 0 623 cm q 0.988235 0.917647 0.639216 rg -102 223.5 176.246 91.5 re f +97.5 199.5 176.246 91.5 re f 0 g 0.75 w 0 J 0 j [] 0.0 d 10 M q 1 0 0 1 0 0 cm -102 223.5 176.246 91.5 re S Q +97.5 199.5 176.246 91.5 re S Q q 1 0 0 1 0 0 cm -102 242.25 m 278.246 242.25 l S Q +97.5 218.25 m 273.746 218.25 l S Q BT -9.75 0 0 -9.75 177.481201 238.125 Tm +9.75 0 0 -9.75 172.981201 214.125 Tm /f-0-0 1 Tf [(W)18(orld)]TJ /f-1-0 1 Tf -7.357046 -1.769231 Td -(+update\(\))Tj +[(+update\(deltaT)37(ime: Double\))]TJ 0 -1.153846 Td -(+addEntity\(e: Entity\))Tj +(+createEntity\(\): Entity)Tj 0 -1.153846 Td (+removeEntity\(e: Entity\))Tj 0 -1.153846 Td @@ -1165,37 +907,33 @@ BT [(+getV)18(iew[\(T1,...,Tn\)]\(\): V)18(iew[\(T1,...,Tn\)])]TJ ET 0.988235 0.917647 0.639216 rg -101.25 97.5 177.461 80.25 re f +96.75 97.5 177.457 57.75 re f 0 g q 1 0 0 1 0 0 cm -101.25 97.5 177.461 80.25 re S Q +96.75 97.5 177.457 57.75 re S Q q 1 0 0 1 0 0 cm -101.25 116.25 m 278.711 116.25 l S Q +96.75 116.25 m 274.207 116.25 l S Q BT -9.75 0 0 -9.75 177.788086 112.125 Tm +9.75 0 0 -9.75 173.285706 112.125 Tm /f-0-0 1 Tf (Entity)Tj /f-1-0 1 Tf --7.465445 -1.769231 Td -[(+addComponent[T)18( <: Component]\(c: )18(T\))]TJ -0 -1.153846 Td -[(+removeComponent[T)18( <: Component]\(\))]TJ -0 -1.153846 Td -[(+getW)18(orld\(\): W)18(orld)]TJ +-7.465201 -1.769231 Td +[(+setComponent[T)18( <: Component]\(c: )18(T\))]TJ 0 -1.153846 Td [(+getComponent[T)18( <: Component]\(\): )18(T)]TJ 0 -1.153846 Td -(+update\(c: Component\))Tj +[(+removeComponent[T)18( <: Component]\(\))]TJ ET 0.980392 0.858824 0.678431 rg -150 7.5 92.102 45 re f +139.5 7.5 92.102 45 re f 0 g q 1 0 0 1 0 0 cm -150 7.5 92.102 45 re S Q +139.5 7.5 92.102 45 re S Q q 1 0 0 1 0 0 cm -150 36 m 242.102 36 l S Q +139.5 36 m 231.602 36 l S Q BT -9.75 0 0 -9.75 182.501221 20.625 Tm +9.75 0 0 -9.75 172.001221 20.625 Tm /f-1-0 1 Tf (\253trait\273)Tj /f-0-0 1 Tf @@ -1206,14 +944,14 @@ BT (+getEntity\(\): Entity?)Tj ET 0.988235 0.917647 0.639216 rg -7.5 363 135.273 35.25 re f +7.5 429 135.273 35.25 re f 0 g q 1 0 0 1 0 0 cm -7.5 363 135.273 35.25 re S Q +7.5 429 135.273 35.25 re S Q q 1 0 0 1 0 0 cm -7.5 381.75 m 142.773 381.75 l S Q +7.5 447.75 m 142.773 447.75 l S Q BT -9.75 0 0 -9.75 64.658936 377.625 Tm +9.75 0 0 -9.75 64.658936 443.625 Tm /f-0-0 1 Tf [(V)18(iew)]TJ /f-1-0 1 Tf @@ -1221,237 +959,282 @@ BT (+foreach[U]\(f: Entity => U\))Tj ET 0.988235 0.917647 0.639216 rg -89.688 349.5 59.836 16.5 re f +89.688 415.5 59.836 16.5 re f 0 g [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -89.688 349.5 59.836 16.5 re S Q +89.688 415.5 59.836 16.5 re S Q BT -9.75 0 0 -9.75 93.437622 362.625 Tm +9.75 0 0 -9.75 93.437622 428.625 Tm /f-1-0 1 Tf [(T)111(: \(T1,...,Tn\))]TJ ET 0.988235 0.917647 0.639216 rg -36 453 138.773 18 re f +31.5 536.25 90.383 18 re f 0 g [] 0.0 d q 1 0 0 1 0 0 cm -36 453 138.773 18 re S Q +31.5 536.25 90.383 18 re S Q BT -9.75 0 0 -9.75 73.770813 467.625 Tm +9.75 0 0 -9.75 42.824341 550.875 Tm /f-0-0 1 Tf [(ExcludingV)18(iew)]TJ ET 0.988235 0.917647 0.639216 rg -57.75 439.5 123.773 16.5 re f +66.07 511.5 62.562 27.75 re f 0 g [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -57.75 439.5 123.773 16.5 re S Q +66.07 511.5 62.562 27.75 re S Q BT -9.75 0 0 -9.75 61.5 452.625 Tm +9.75 0 0 -9.75 69.820679 524.625 Tm /f-1-0 1 Tf -[(T)111(: \(T1,...,Tn\), E: \(E1,...,En\))]TJ +[(T)111(: \(T1,...,Tn\))]TJ +0 -1.153846 Td +(E: \(E1,...,En\))Tj ET 0.980392 0.858824 0.678431 rg -210 363 202.285 45 re f +217.5 331.5 127.52 56.25 re f 0 g [] 0.0 d q 1 0 0 1 0 0 cm -210 363 202.285 45 re S Q +217.5 331.5 127.52 56.25 re S Q q 1 0 0 1 0 0 cm -210 391.5 m 412.285 391.5 l S Q +217.5 360 m 345.02 360 l S Q BT -9.75 0 0 -9.75 297.59436 376.125 Tm +9.75 0 0 -9.75 267.711182 344.625 Tm /f-1-0 1 Tf (\253trait\273)Tj /f-0-0 1 Tf -0.277344 -1.153846 Td (System)Tj -/f-2-0 1 Tf --8.322078 -1.769231 Td -[(+update\(e: Entity)74(, comps: T)92(, v: V)18(iew[T]\): T)]TJ -ET -0.980392 0.858824 0.678431 rg -359.199 349.5 59.836 16.5 re f -0 g -[ 2.25 2.25] 0 d -q 1 0 0 1 0 0 cm -359.199 349.5 59.836 16.5 re S Q -BT -9.75 0 0 -9.75 362.949829 362.625 Tm /f-1-0 1 Tf -[(T)111(: \(T1,...,Tn\))]TJ +-4.487906 -1.769231 Td +[(+update\(deltaT)37(ime: Double\))]TJ +0 -1.153846 Td +(+shouldRun\(\): Boolean)Tj ET 0.980392 0.858824 0.678431 rg -222 453 138.773 27.75 re f +235.5 526.5 103.027 27.75 re f 0 g -[] 0.0 d q 1 0 0 1 0 0 cm -222 453 138.773 27.75 re S Q +235.5 526.5 103.027 27.75 re S Q BT -9.75 0 0 -9.75 277.83783 466.125 Tm +9.75 0 0 -9.75 273.463623 539.625 Tm /f-1-0 1 Tf (\253trait\273)Tj /f-0-0 1 Tf --2.445312 -1.153846 Td +-2.676082 -1.153846 Td (ExcludingSystem)Tj ET 0.980392 0.858824 0.678431 rg -243.75 439.5 123.773 16.5 re f +282.715 501.75 62.562 27.75 re f 0 g [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -243.75 439.5 123.773 16.5 re S Q +282.715 501.75 62.562 27.75 re S Q BT -9.75 0 0 -9.75 247.5 452.625 Tm +9.75 0 0 -9.75 286.46521 514.875 Tm /f-1-0 1 Tf -[(T)111(: \(T1,...,Tn\), E: \(E1,...,En\))]TJ +[(T)111(: \(T1,...,Tn\))]TJ +0 -1.153846 Td +(E: \(E1,...,En\))Tj ET [] 0.0 d q 1 0 0 1 0 0 cm -192 177.75 m 192 223.5 l S Q -188.844 215.879 m 192 223.5 l 195.156 215.879 l 192 207 l f +187.5 155.25 m 187.5 199.5 l S Q +184.344 191.879 m 187.5 199.5 l 190.656 191.879 l 187.5 183 l f q 1 0 0 1 0 0 cm -188.844 215.879 m 192 223.5 l 195.156 215.879 l 192 207 l 188.844 215.879 +184.344 191.879 m 187.5 199.5 l 190.656 191.879 l 187.5 183 l 184.344 191.879 l S Q BT -9.75 0 0 -9.75 180.439087 196.875 Tm +9.75 0 0 -9.75 175.939087 174.375 Tm /f-1-0 1 Tf (*)Tj --0.237342 -1.615385 Td +-0.237342 -1.461538 Td (1)Tj ET q 1 0 0 1 0 0 cm -194.25 52.5 m 194.25 97.5 l S Q -191.094 89.879 m 194.25 97.5 l 197.406 89.879 l 194.25 81 l f +187.5 52.5 m 187.5 97.5 l S Q +184.344 89.879 m 187.5 97.5 l 190.656 89.879 l 187.5 81 l f q 1 0 0 1 0 0 cm -191.094 89.879 m 194.25 97.5 l 197.406 89.879 l 194.25 81 l 191.094 89.879 +184.344 89.879 m 187.5 97.5 l 190.656 89.879 l 187.5 81 l 184.344 89.879 l S Q BT -9.75 0 0 -9.75 182.689087 70.875 Tm +9.75 0 0 -9.75 175.939087 70.875 Tm /f-1-0 1 Tf (*)Tj -0.0834961 -1.769231 Td (1)Tj ET q 1 0 0 1 0 0 cm -78 439.5 m 78 398.25 l S Q -1 g -84.312 413.492 m 78 398.25 l 71.688 413.492 l f -0 g -q 1 0 0 1 0 0 cm -84.312 413.492 m 78 398.25 l 71.688 413.492 l 84.312 413.492 l S Q -q 1 0 0 1 0 0 cm -312.75 439.5 m 312.75 408 l S Q +73.5 511.5 m 73.5 464.25 l S Q 1 g -319.062 423.242 m 312.75 408 l 306.438 423.242 l f +79.812 479.492 m 73.5 464.25 l 67.188 479.492 l f 0 g q 1 0 0 1 0 0 cm -319.062 423.242 m 312.75 408 l 306.438 423.242 l 319.062 423.242 l S Q -[ 2.25 2.25] 0 d -q 1 0 0 1 0 0 cm -126 315 m 126 349.5 l S Q -[] 0.0 d -q 1 0 0 1 0 0 cm -122.844 341.879 m 126 349.5 l 129.156 341.879 l S Q +79.812 479.492 m 73.5 464.25 l 67.188 479.492 l 79.812 479.492 l S Q +BT +9.75 0 0 -9.75 80.625 502.125 Tm +/f-1-0 1 Tf +[(T)18( -> )18(T)]TJ +0.384615 1.307692 Td +(\253bind\273)Tj +ET [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -54 363 m 54 157.5 l 101.25 157.5 l S Q +121.5 291 m 121.5 415.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -93.629 160.656 m 101.25 157.5 l 93.629 154.344 l S Q +118.344 407.879 m 121.5 415.5 l 124.656 407.879 l S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -210 376.5 m 142.5 376.5 l S Q +19.5 429 m 19.5 120.75 l 96.75 120.75 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -153.121 373.344 m 145.5 376.5 l 153.121 379.656 l S Q +89.129 123.906 m 96.75 120.75 l 89.129 117.594 l S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -222 462.75 m 177 462.75 l S Q +235.5 547.5 m 122.25 547.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -183.871 459.594 m 176.25 462.75 l 183.871 465.906 l S Q +129.871 544.344 m 122.25 547.5 l 129.871 550.656 l S Q 0.976471 0.960784 0.894118 rg -300 97.5 m 399.75 97.5 l 407.25 105 l 407.25 144 l 300 144 l 300 97.5 l - f +283.5 49.5 m 371.25 49.5 l 378.75 57 l 378.75 96 l 283.5 96 l 283.5 49.5 + l f 0 g q 1 0 0 1 0 0 cm -300 97.5 m 399.75 97.5 l 407.25 105 l 407.25 144 l 300 144 l 300 97.5 l - S Q +283.5 49.5 m 371.25 49.5 l 378.75 57 l 378.75 96 l 283.5 96 l 283.5 49.5 + l S Q q 1 0 0 1 0 0 cm -399.75 97.5 m 399.75 105 l 407.25 105 l 399.75 97.5 l S Q +371.25 49.5 m 371.25 57 l 378.75 57 l 371.25 49.5 l S Q BT -9.75 0 0 -9.75 303.75 111 Tm +9.75 0 0 -9.75 287.25 63 Tm /f-1-0 1 Tf -[(An)-278(entity)-278(can)-277(have)-278(at)]TJ +[(An)-278(entity)-278(can)-277(have)]TJ 0 -1 Td -(most one Component)Tj +(at most one)Tj 0 -1 Td -(per type)Tj +(Component per type)Tj ET [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -300 115.5 m 279 115.5 l S Q -[ 2.25 2.25] 0 d -q 1 0 0 1 0 0 cm -330 363 m 330 157.5 l 279 157.5 l S Q +367.5 409.5 m 367.5 121.5 l 274.5 121.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -286.621 154.344 m 279 157.5 l 286.621 160.656 l S Q +282.121 118.344 m 274.5 121.5 l 282.121 124.656 l S Q 0.976471 0.960784 0.894118 rg -120 505.5 m 243.75 505.5 l 251.25 513 l 251.25 542.25 l 120 542.25 l 120 - 505.5 l f +121.5 577.5 m 245.25 577.5 l 252.75 585 l 252.75 614.25 l 121.5 614.25 +l 121.5 577.5 l f 0 g q 1 0 0 1 0 0 cm -120 505.5 m 243.75 505.5 l 251.25 513 l 251.25 542.25 l 120 542.25 l 120 - 505.5 l S Q +121.5 577.5 m 245.25 577.5 l 252.75 585 l 252.75 614.25 l 121.5 614.25 +l 121.5 577.5 l S Q q 1 0 0 1 0 0 cm -243.75 505.5 m 243.75 513 l 251.25 513 l 243.75 505.5 l S Q +245.25 577.5 m 245.25 585 l 252.75 585 l 245.25 577.5 l S Q BT -9.75 0 0 -9.75 123.75 519 Tm +9.75 0 0 -9.75 125.25 591 Tm /f-1-0 1 Tf [(T)37(i)-278(<:)-278(Component)]TJ -/f-3-1 1 Tf +/f-2-1 1 Tf [<>-277<01>]TJ /f-1-0 1 Tf [()-278(i)-278(=)-278(1,...,n)]TJ 0 -1 Td (Ei <: Component )Tj -/f-3-1 1 Tf +/f-2-1 1 Tf <01>Tj /f-1-0 1 Tf ( i = 1,...,n)Tj ET [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -120 524.25 m 99 524.25 l 99 471 l S Q +121.5 596.25 m 94.5 596.25 l 94.5 554.25 l S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -252 524.25 m 280.5 524.25 l 280.5 480.75 l S Q +253.5 596.25 m 276 596.25 l 276 554.25 l S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -120 524.25 m 24 524.25 l 24 398.25 l S Q +121.5 596.25 m 19.5 596.25 l 19.5 464.25 l S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -252 524.25 m 390 524.25 l 390 408 l S Q +253.5 596.25 m 367.5 596.25 l 367.5 468 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -246 363 m 246 315 l S Q +247.5 331.5 m 247.5 291 l S Q 1 g -249.156 322.621 m 246 315 l 242.844 322.621 l 246 331.5 l f +250.656 298.621 m 247.5 291 l 244.344 298.621 l 247.5 307.5 l f 0 g q 1 0 0 1 0 0 cm -249.156 322.621 m 246 315 l 242.844 322.621 l 246 331.5 l 249.156 322.621 +250.656 298.621 m 247.5 291 l 244.344 298.621 l 247.5 307.5 l 250.656 298.621 l S Q BT -9.75 0 0 -9.75 252.375 358.125 Tm +9.75 0 0 -9.75 252.915344 328.875 Tm /f-1-0 1 Tf (*)Tj -0.0769231 2.307692 Td +-0.0554199 1.307692 Td (*)Tj ET +0.980392 0.858824 0.678431 rg +193.5 423 179.539 45 re f +0 g +q 1 0 0 1 0 0 cm +193.5 423 179.539 45 re S Q +q 1 0 0 1 0 0 cm +193.5 451.5 m 373.039 451.5 l S Q +BT +9.75 0 0 -9.75 269.720947 436.125 Tm +/f-1-0 1 Tf +(\253trait\273)Tj +/f-0-0 1 Tf +-2.083984 -1.153846 Td +(IteratingSystem)Tj +/f-1-0 1 Tf +-5.348933 -1.769231 Td +[(+update\(e: Entity)74(, components: )18(T\): )18(T)]TJ +ET +0.980392 0.858824 0.678431 rg +319.953 409.5 59.836 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +319.953 409.5 59.836 16.5 re S Q +BT +9.75 0 0 -9.75 323.703003 422.625 Tm +/f-1-0 1 Tf +[(T)111(: \(T1,...,Tn\))]TJ +ET +[] 0.0 d +q 1 0 0 1 0 0 cm +283.5 423 m 283.5 387.75 l S Q +1 g +289.812 402.992 m 283.5 387.75 l 277.188 402.992 l f +0 g +q 1 0 0 1 0 0 cm +289.812 402.992 m 283.5 387.75 l 277.188 402.992 l 289.812 402.992 l S Q +q 1 0 0 1 0 0 cm +283.5 501.75 m 283.5 468 l S Q +1 g +289.812 483.242 m 283.5 468 l 277.188 483.242 l f +0 g +q 1 0 0 1 0 0 cm +289.812 483.242 m 283.5 468 l 277.188 483.242 l 289.812 483.242 l S Q +BT +9.75 0 0 -9.75 232.875 502.875 Tm +/f-1-0 1 Tf +[(T)18( -> )18(T)]TJ +0.769231 1.461538 Td +(\253bind\273)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +282.75 73.5 m 188.25 73.5 l 188.25 74.25 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +193.5 439.5 m 142.5 439.5 l S Q +[] 0.0 d +q 1 0 0 1 0 0 cm +150.121 436.344 m 142.5 439.5 l 150.121 442.656 l S Q Q Q showpage %%Trailer diff --git a/doc/img/Demo.eps b/doc/img/Demo.eps index 7f9b61e3..2098bb00 100644 --- a/doc/img/Demo.eps +++ b/doc/img/Demo.eps @@ -1,10 +1,10 @@ %!PS-Adobe-3.0 EPSF-3.0 %%Creator: cairo 1.17.4 (https://cairographics.org) -%%CreationDate: Wed Sep 22 14:45:28 2021 +%%CreationDate: Thu Oct 14 17:42:50 2021 %%Pages: 1 %%DocumentData: Clean7Bit %%LanguageLevel: 2 -%%BoundingBox: 7 7 419 354 +%%BoundingBox: 7 7 458 380 %%EndComments %%BeginProlog 50 dict begin @@ -77,6 +77,7 @@ Encoding 65 /A put Encoding 66 /B put Encoding 67 /C put Encoding 68 /D put +Encoding 69 /E put Encoding 70 /F put Encoding 77 /M put Encoding 80 /P put @@ -101,7 +102,7 @@ Encoding 116 /t put Encoding 118 /v put Encoding 119 /w put Encoding 121 /y put -/CharStrings 29 dict dup begin +/CharStrings 30 dict dup begin /.notdef 0 def /W 1 def /o 2 def @@ -130,13 +131,14 @@ Encoding 121 /y put /g 25 def /M 26 def /p 27 def -/v 28 def +/E 28 def +/v 29 def end readonly def /sfnts [ -<000100000009008000030010637674206d5f6ba100001b38000002886670676d7e61b6110000 -1dc0000007b4676c796641a8bf950000009c00001a9c686561640ac93d4f0000257400000036 -686865610e180390000025ac00000024686d747890b00a56000025d0000000746c6f63610001 -788000002644000000786d61787004350534000026bc00000020707265708aa104b9000026dc +<000100000009008000030010637674206d5f6ba100001bdc000002886670676d7e61b6110000 +1e64000007b4676c79668bdb118a0000009c00001b40686561640b8df5290000261800000036 +686865610e1803910000265000000024686d747896060adf00002674000000786c6f63610001 +92dc000026ec0000007c6d617870043605340000276800000020707265708aa104b900002788 00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd 2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 e9000000000100020000078b05810017014040e51617010013100f0408070c0a09090c041317 @@ -306,126 +308,131 @@ ab19018b19017b19015b19013b19012f190104190137eb1901cb1901b419019b19017419014b 183f3f3f332b1112013939113311333311333130011002232226272316151121113427211e01 15333633321201102322061514163332048fd9c672a92d0606fee70801110507045ffbbdd0fe dbdf7077776ee10222fef1fed9635d1e98fe6104ea9960126a34c7feddfef4016cc4b0afbf00 -0000000100080000046a043a000a015340ff0302010006090a0a0602030b0c940c01800c0162 -0c720c02540c01420c01340c01260c01120c01040c01f40c01e60c01d20c0101c00c01a40cb4 -0c02800c900c02640c740c02400c500c02340c01100c01040c0167f40c01d00ce00c02b40cc4 -0c02a00c01840c940c02600c01440c540c02200c01140c01d40ce40c02cb0c01900ca00c0284 -0c01600c700c02440c540c02200c300c02140c01f00c01d40ce40c02b00c01640c740c940ca4 -0c04400c01240c340c02000c013702700c800cb00cc00cf00c055f0c01000c100c400c03d00c -01af0c01900c016f0c01500c012f0c3f0c027f0c8f0cbf0cef0cff0c05500c010f0c1f0c3f0c -030709020f0601b015003f333f33015e5d5d5d7171717171717272725f5e5d5d5d5d5d5d5d71 -717171717171717272727272727272725e5d5d5d5d5d5d5d5d5f5d5d5d717171717171717171 -11121739113311333311333130290101211316173e01132102dbfeb0fe7d0129bd0f380a3ec7 -0126043afda332c829ce0260000005cc05cc007d058100150079058100150000000000000000 -000000000000043a001400770000ffec00000000ffec00000000ffec0000fe57fff700000000 +000000010089000005060581000b0074404a050909000b00010b060a030700040c0d05085f59 +0f057f059f05030f058f05ff05030f03051615490f0501140505160c490505000101045f5901 +0300095f590012400d01300d01200d015d5d5d003f2b00183f2b11120039182f2b5f5e5d2b5f +5e5d712b11120117395f5e5d113311333130331121152111211521112115890454fcd302f0fd +1003560581e4fe9ee4fe8de40000000100080000046a043a000a015340ff0302010006090a0a +0602030b0c940c01800c01620c720c02540c01420c01340c01260c01120c01040c01f40c01e6 +0c01d20c0101c00c01a40cb40c02800c900c02640c740c02400c500c02340c01100c01040c01 +67f40c01d00ce00c02b40cc40c02a00c01840c940c02600c01440c540c02200c01140c01d40c +e40c02cb0c01900ca00c02840c01600c700c02440c540c02200c300c02140c01f00c01d40ce4 +0c02b00c01640c740c940ca40c04400c01240c340c02000c013702700c800cb00cc00cf00c05 +5f0c01000c100c400c03d00c01af0c01900c016f0c01500c012f0c3f0c027f0c8f0cbf0cef0c +ff0c05500c010f0c1f0c3f0c030709020f0601b015003f333f33015e5d5d5d71717171717172 +72725f5e5d5d5d5d5d5d5d71717171717171717272727272727272725e5d5d5d5d5d5d5d5d5f +5d5d5d71717171717171717111121739113311333311333130290101211316173e01132102db +feb0fe7d0129bd0f380a3ec70126043afda332c829ce0260000005cc05cc007d058100150079 +058100150000000000000000000000000000043a001400770000ffec00000000ffec00000000 +ffec0000fe57fff7000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000000008000000 -00000119012500f500eb0000000000000000000000c100d300ba00b000cf0000000000000000 -000000000127012901060000011200e400f400c6000000000000000000000000000000000000 -0000000000000119011f014c0000000000df00d100c500b50000000000000000000000000000 -0000000000000000010200a901fd00d80119008000b701fd00000000013f00db015d012500aa -00800075008d01fc0179012100a001100000000001310119010e010400000000000000000000 -0000000000000000013d01ff00e00106009400e00094014400e005730319000000d802c5009c -038102cd00cb00f4004e028d000000ff00d700cc01300145007300b400a60000000000730080 -008d000000000000000000000000030000a200980083008d000000000000000005aefebc0581 -fd300011fff600b600bc00c60000007f008a0060000000000000000000f001ee019000000219 -0108011500000000000000be00000000000000000748036a02b60202fd930000009100670091 -006101d90000028d0341000000000000000000000000000000aafe6ffe6801050093009800e2 -0151008f00be00aefeb9fea4005e00af02d5005500f200a604150601000003e1001002fa000f -fed401eafff300b8000000000363000bfd0ffff500000000000006810477001504d90000ffec -ffc5fe7f007500cd00f2010200d5011940475b5a59585554535251504f4e4d4c4b4a49484746 -4544434241403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f181411100f0e -0d0b0a090807060504030201002c20b0016045b003252011466123452361482d2c2045186844 -2d2c45234660b0206120b04660b004262348482d2c4523462361b0206020b02661b02061b004 -262348482d2c45234660b0406120b06660b004262348482d2c4523462361b0406020b02661b0 -4061b004262348482d2c0110203c003c2d2c20452320b0cd442320b8015a51582320b08d4423 -5920b0ed51582320b04d44235920b0042651582320b00d44235921212d2c20204518684420b0 -01602045b04676688a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b028 -2370b101283e01b0282370b10228453ab10200080d2d2c2045b00325456164b050515845441b -2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0 -008b20b12cc08a8cb8100062602b0c642364615c58b00361592d2c8a03458a8a87b0112bb029 -2344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845441b2121592d2c4b51584544 -1b2121592d2c01b005251023208af500b0016023edec2d2c01b005251023208af500b0016123 -edec2d2c01b0062510f500edec2d2cb00243b001525821212121211b462346608a8a46232046 -8a608a61b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b0 -106068013a592d2c2045b0032546524bb013515b58b0022546206861b00325b003253f232138 -1b2111592d2c2045b00325465058b0022546206861b00325b003253f2321381b2111592d2c00 -b00743b006430b2d2c21210c6423648bb84000622d2c21b08051580c6423648bb82000621bb2 -00402f2b59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b002602d2c0c64 -23648bb84000626023212d2c4b53588ab004254964234569b0408b61b08062b020616ab00e23 -442310b00ef61b21238a121120392f592d2c4b535820b0032549646920b00526b00625496423 -61b08062b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab0 -0426111220392320392f2f592d2c4523456023456023456023766818b08062202d2cb0482b2d -2c2045b0005458b040442045b04061441b2121592d2c45b1302f4523456160b0016069442d2c -4b5158b02f2370b01423421b2121592d2c4b515820b0032545695358441b2121591b2121592d -2c45b01443b0006063b0016069442d2cb02f45442d2c452320458a60442d2c45234560442d2c -4b235158b90033ffe0b134201bb3330034005944442d2cb0164358b00326458a586466b01f60 -1b64b020606620581b21b04059b001615923586559b02923442310b029e01b2121212121592d -2cb0024354584b53234b515a58381b2121591b21212121592d2cb0164358b004254564b02060 -6620581b21b04059b0016123581b6559b0292344b00525b00825082058021b0359b0042510b0 -05252046b0042523423cb00425b0072508b0072510b006252046b00425b0016023423c205801 -1b0059b0042510b00525b029e0b02920456544b0072510b00625b029e0b00525b00825082058 -021b0359b00525b003254348b00425b0072508b00625b00325b0016043481b21592121212121 -21212d2c02b00425202046b004252342b0052508b003254548212121212d2c02b0032520b004 -2508b0022543482121212d2c452320451820b00050205823652359236820b040505821b04059 -235865598a60442d2c4b53234b515a5820458a60441b2121592d2c4b545820458a60441b2121 -592d2c4b53234b515a58381b2121592d2cb000214b5458381b2121592d2cb002435458b0462b -1b21212121592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b21212121592d -2cb002435458b0492b1b212121592d2c208a08234b538a4b515a5823381b2121592d2c00b002 -2549b000535820b04038111b21592d2c014623466023466123201020468a61b8ff80628ab140 -408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb012004b01 -4b54422d2cb1020042b123018851b1400188535a58b910000020885458b202010243604259b1 -2401885158b920000040885458b2020202436042b12401885458b2022002436042004b014b52 -58b2020802436042591bb940000080885458b202040243604259b94000008063b80100885458 -b202080243604259b94000010063b80200885458b202100243604259b12601885158b9400002 -0063b80400885458b202400243604259b94000040063b80800885458b2028002436042595959 -595959b10002435458400a0540084009400c020d021bb10102435458b2054008ba0100000901 -00b30c010d011bb18002435258b2054008b80180b109401bb2054008ba01800009014059b940 -0000808855b94000020063b8040088555a58b30c000d011bb30c000d0159595942424242422d -2c451868234b51582320452064b04050587c59688a6059442d2cb00016b00225b0022501b001 -233e00b002233eb10102060cb00a236542b00b234201b001233f00b002233fb10102060cb006 -236542b0072342b00116012d2cb080b0024350b001b00243545b58212310b0201ac91b8a10ed -592d2cb0592b2d2c8a10e52d0001000000021999312b36b95f0f3cf5001f080000000000c849 -682600000000dcb67151fc25fcfd0a6f084400010008000200010000000000010000073efe4e -00430aaafc25fa7a0a6f00010000000000000000000000000000001d060000cd078d000204e3 -0050031d00870239008f04e300540556000e04730050047300500239008f02aa001904730010 -05c700330639fffa05c7008904e300870556003b04730048071d008705c700890473003c05c7 -00540556008904e3008905c7008904e3005406aa008904e3008704730008000000000000004c -000001ec0000027800000300000003600000040c0000047c0000054c000005e8000006680000 -06e8000008f800000b4c00000d5c00000e1000000eb000000f8c000010780000118000001278 -0000137c0000142c000014c000001534000015b4000016a0000018680000191400001a9c0001 -0000001d01520054005c000600020010002f005c0000034d0354000400014155013f00010139 -0055013e000101390055014201400014001f01410140001f001f013b0033013a005501380033 -0139005500a4013900f4013900020132003d0131005501310001012f00550130003d012f0055 -012c012900ff001f01290001012a00550128003d0127005501270001012a00550126003d0125 -005501250001012a00550123012200ff001f01220001012a0055012b003d012a005500500107 -0001002f0107000100af0104405001d0fd01bffd0110fd016ffb0140fb0180f590f5a0f503f1 -f0351f2ff09ff0025fef012fef5fef6fef9fefdfef05e6e4201fe5e43d1fe2e0271fe1e03d1f -df3ddd55de3d035500dd30dd02dd0103552f410b011e00010010011e0020011e0040011e0003 -ffc0011e4028191c46dc03ff1f00db01da043c1fd4d21c1fd3d2261f60d190d1c0d10360d190 -d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ffc0b4d10a0d460fb80116400f01bfbe261f40bb29 -414640bb222746b801214026b63d1f00b8016fb801b8b70a1f00b70100b720b740b760b770b7 -0540b760b790b7d0b7f0b705b80120400d483d1f00b560b502a0b5d0b502b8ffc0400eb50b0e -460fb25fb202b1033c1f2f410b0119003f0119004f01190003008f0119000100400119402826 -29461faf2faf3faf9faf040faf0140af0e164600ad70ad80ad03e0adf0ad02abaa351faa5026 -1fb9011b011ab23c1f00b8011ab6010fa9010fa801bc01170113003c001f0115407e503c1f9e -9b271f9d9b271f9c9b271f809b019846281f9f97af97029646351f0f941f94029390261f9291 -261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f8d010f8c01408c0b0f460f891f890286850f1f5f -850136824682027650261f7550261f7450261f7350261f2970011b7001037001f47001d670e6 -7002687001597001b8fff0407d700a0d466f6e481f6e46321f1a011855193318550733035506 -03ff1f6150261f605f321f5f50261f5e5a481f5c46271f5b5a781f5a46311f13321255050103 -55043203556f03010f033f034f036f037f03055f53014053282c4640531e224640531318466b -527b528b5203514f1c1f504f1c1f194f294f02594f694f02b80112402d46251f4946191f4846 -211f4746351ff846019846011c481b551632155511010f5510320f55020100550100ff1fb801 -11b21b091fb80110402d1b091f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f -0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff524bb007505bb00188 -b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb0325358b0601d -594bb0645358b0401d594bb0805358b0101db11600425973747374752b2b2b2b2b2b2b2b0173 -742b2b2b2b0073742b2b732b2b2b7373752b2b2b012b2b2b002b2b2b2b2b2b2b2b012b2b2b73 -737373747474002b2b2b2b0173732b73002b73732b732b2b73012b732b00732b2b2b2b2b7373 -732b012b2b0073742b73742b73742b73012b73742b007374752b73742b2b2b012b00732b2b73 -74012b2b002b732b2b73752b732b2b012b2b002b2b737401732b007373737373730173737300 -2b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> +00000000000000000800000000000119012500f500eb0000000000000000000000c100d300ba +00b000cf0000000000000000000000000127012901060000011200e400f400c6000000000000 +0000000000000000000000000000000000000119011f014c0000000000df00d100c500b50000 +0000000000000000000000000000000000000000010200a901fd00d80119008000b701fd0000 +0000013f00db015d012500aa00800075008d01fc0179012100a001100000000001310119010e +0104000000000000000000000000000000000000013d01ff00e00106009400e00094014400e0 +05730319000000d802c5009c038102cd00cb00f4004e028d000000ff00d700cc013001450073 +00b400a60000000000730080008d000000000000000000000000030000a200980083008d0000 +00000000000005aefebc0581fd300011fff600b600bc00c60000007f008a0060000000000000 +000000f001ee0190000002190108011500000000000000be00000000000000000748036a02b6 +0202fd930000009100670091006101d90000028d0341000000000000000000000000000000aa +fe6ffe6801050093009800e20151008f00be00aefeb9fea4005e00af02d5005500f200a60415 +0601000003e1001002fa000ffed401eafff300b8000000000363000bfd0ffff5000000000000 +06810477001504d90000ffecffc5fe7f007500cd00f2010200d5011940475b5a595855545352 +51504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c282726 +25242322211f181411100f0e0d0b0a090807060504030201002c20b0016045b0032520114661 +23452361482d2c20451868442d2c45234660b0206120b04660b004262348482d2c4523462361 +b0206020b02661b02061b004262348482d2c45234660b0406120b06660b004262348482d2c45 +23462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd4423 +20b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651582320b00d442359 +21212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a432343650a2d2c00 +b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c2045b0 +0325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b0 +0743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361592d +2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845 +441b2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c01b0 +05251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243b001525821212121 +211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b0005058b0 +0161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013515b58b002254620 +6861b00325b003253f2321381b2111592d2c2045b00325465058b0022546206861b00325b003 +253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b08051 +580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423648bb81555621bb2 +00802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004254964234569b040 +8b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c4b535820b0032549 +646920b00526b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b00e2344b0 +0ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c452345602345602345602376 +6818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1302f +4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b003254569 +5358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c45232045 +8a60442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb01643 +58b00326458a586466b01f601b64b020606620581b21b04059b001615923586559b029234423 +10b029e01b2121212121592d2cb0024354584b53234b515a58381b2121591b21212121592d2c +b0164358b004254564b020606620581b21b04059b0016123581b6559b0292344b00525b00825 +082058021b0359b0042510b005252046b0042523423cb00425b0072508b0072510b006252046 +b00425b0016023423c2058011b0059b0042510b00525b029e0b02920456544b0072510b00625 +b029e0b00525b00825082058021b0359b00525b003254348b00425b0072508b00625b00325b0 +016043481b2159212121212121212d2c02b00425202046b004252342b0052508b00325454821 +2121212d2c02b0032520b0042508b0022543482121212d2c452320451820b000502058236523 +59236820b040505821b04059235865598a60442d2c4b53234b515a5820458a60441b2121592d +2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b5458381b21 +21592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb00243 +5458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b515a +5823381b2121592d2c00b0022549b000535820b04038111b21592d2c01462346602346612320 +1020468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52 +587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188535a58b910000020 +885458b202010243604259b12401885158b920000040885458b2020202436042b12401885458 +b2022002436042004b014b5258b2020802436042591bb940000080885458b202040243604259 +b94000008063b80100885458b202080243604259b94000010063b80200885458b20210024360 +4259b12601885158b94000020063b80400885458b202400243604259b94000040063b8080088 +5458b2028002436042595959595959b10002435458400a0540084009400c020d021bb1010243 +5458b2054008ba010000090100b30c010d011bb18002435258b2054008b80180b109401bb205 +4008ba01800009014059b9400000808855b94000020063b8040088555a58b30c000d011bb30c +000d0159595942424242422d2c451868234b51582320452064b04050587c59688a6059442d2c +b00016b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201b001233f +00b002233fb10102060cb006236542b0072342b00116012d2cb080b0024350b001b00243545b +58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d0001000000021999908ee76f5f0f +3cf5001f080000000000c849682600000000dd7b292bfc25fcfd0a6f08440001000800020001 +0000000000010000073efe4e00430aaafc25fa7a0a6f00010000000000000000000000000000 +001e060000cd078d000204e30050031d00870239008f04e300540556000e0473005004730050 +0239008f02aa00190473001005c700330639fffa05c7008904e300870556003b04730048071d +008705c700890473003c05c700540556008904e3008905c7008904e3005406aa008904e30087 +0556008904730008000000000000004c000001ec0000027800000300000003600000040c0000 +047c0000054c000005e800000668000006e8000008f800000b4c00000d5c00000e1000000eb0 +00000f8c0000107800001180000012780000137c0000142c000014c000001534000015b40000 +16a00000186800001914000019b800001b4000010000001e01520054005c000600020010002f +005c0000034d0354000400014155013f000101390055013e000101390055014201400014001f +01410140001f001f013b0033013a0055013800330139005500a4013900f4013900020132003d +0131005501310001012f00550130003d012f0055012c012900ff001f01290001012a00550128 +003d0127005501270001012a00550126003d0125005501250001012a00550123012200ff001f +01220001012a0055012b003d012a0055005001070001002f0107000100af0104405001d0fd01 +bffd0110fd016ffb0140fb0180f590f5a0f503f1f0351f2ff09ff0025fef012fef5fef6fef9f +efdfef05e6e4201fe5e43d1fe2e0271fe1e03d1fdf3ddd55de3d035500dd30dd02dd0103552f +410b011e00010010011e0020011e0040011e0003ffc0011e4028191c46dc03ff1f00db01da04 +3c1fd4d21c1fd3d2261f60d190d1c0d10360d190d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ff +c0b4d10a0d460fb80116400f01bfbe261f40bb29414640bb222746b801214026b63d1f00b801 +6fb801b8b70a1f00b70100b720b740b760b770b70540b760b790b7d0b7f0b705b80120400d48 +3d1f00b560b502a0b5d0b502b8ffc0400eb50b0e460fb25fb202b1033c1f2f410b0119003f01 +19004f01190003008f011900010040011940282629461faf2faf3faf9faf040faf0140af0e16 +4600ad70ad80ad03e0adf0ad02abaa351faa50261fb9011b011ab23c1f00b8011ab6010fa901 +0fa801bc01170113003c001f0115407e503c1f9e9b271f9d9b271f9c9b271f809b019846281f +9f97af97029646351f0f941f94029390261f9291261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f +8d010f8c01408c0b0f460f891f890286850f1f5f850136824682027650261f7550261f745026 +1f7350261f2970011b7001037001f47001d670e67002687001597001b8fff0407d700a0d466f +6e481f6e46321f1a01185519331855073303550603ff1f6150261f605f321f5f50261f5e5a48 +1f5c46271f5b5a781f5a46311f1332125505010355043203556f03010f033f034f036f037f03 +055f53014053282c4640531e224640531318466b527b528b5203514f1c1f504f1c1f194f294f +02594f694f02b80112402d46251f4946191f4846211f4746351ff846019846011c481b551632 +155511010f5510320f55020100550100ff1fb80111b21b091fb80110402d1b091f1f0f3f0f5f +0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b8 +0190b154532b2b4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b +58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101d +b11600425973747374752b2b2b2b2b2b2b2b0173742b2b2b2b0073742b2b732b2b2b7373752b +2b2b012b2b2b002b2b2b2b2b2b2b2b012b2b2b73737373747474002b2b2b2b0173732b73002b +73732b732b2b73012b732b00732b2b2b2b2b7373732b012b2b0073742b73742b73742b73012b +73742b007374752b73742b2b2b012b00732b2b7374012b2b002b732b2b73752b732b2b012b2b +002b2b737401732b0073737373737301737373002b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b +2b1800> ] def /f-0-0 currentdict end definefont pop %%EndResource @@ -477,7 +484,7 @@ Encoding 187 /guillemotright put end readonly def /sfnts [ <000100000009008000030010637674204ada4bfa00000cbc000002886670676d7e61b6110000 -0f44000007b4676c7966408837e50000009c00000c20686561640a3bd00c000016f800000036 +0f44000007b4676c7966408837e50000009c00000c20686561640b008bb1000016f800000036 686865610d94038f0000173000000024686d74784808063600001754000000486c6f63610000 70500000179c0000004c6d617870038103e4000017e80000002070726570fdae474900001808 00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd @@ -630,8 +637,8 @@ b10102435458b2054008ba010000090100b30c010d011bb18002435258b2054008b80180b109 011bb30c000d0159595942424242422d2c451868234b51582320452064b04050587c59688a60 59442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201 b001233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b0024350b001b0 -0243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d00010000000219992739 -7aec5f0f3cf5001f080000000000c840f99a00000000dcb67271fba6fd930a6a07d700000008 +0243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d000100000002199925b0 +03a25f0f3cf5001f080000000000c840f99a00000000dd7b2e16fba6fd930a6a07d700000008 000200010000000000010000073efe4e00430ab4fba6fa7a0a6a000100000000000000000000 000000000012060000cd047300530239001f02aa00880473005701c700890473005304ac0064 0473005605c7fffd05c700680400005701c7008a0473005702aa007f02aa000c055600040473 @@ -666,175 +673,185 @@ a9049c9b241f509b016f9601bf960196461d1f9594171f0f941f947f948f94ff940530914091 %%EndSetup %%Page: 1 1 %%BeginPageSetup -%%PageBoundingBox: 7 7 419 354 +%%PageBoundingBox: 7 7 458 380 %%EndPageSetup -q 7 7 412 347 rectclip -1 0 0 -1 0 361 cm q -0.988235 0.917647 0.639216 rg -164.887 169.5 34.191 18 re f -0 g +q 7 7 451 373 rectclip +1 0 0 -1 0 387 cm q +0.976471 0.960784 0.894118 rg +229.5 67.5 228 114 re f 0.75 w 0 J 0 j [] 0.0 d 10 M q 1 0 0 1 0 0 cm -164.887 169.5 34.191 18 re S Q +229.5 67.5 228 114 re S Q +61.5 193.5 306 186 re f +q 1 0 0 1 0 0 cm +61.5 193.5 306 186 re S Q +7.5 85.5 174 294 re f +q 1 0 0 1 0 0 cm +7.5 85.5 174 294 re S Q +0.988235 0.917647 0.639216 rg +187.5 169.5 34.191 18 re f +0 g +q 1 0 0 1 0 0 cm +187.5 169.5 34.191 18 re S Q BT -9.75 0 0 -9.75 169.339417 184.125 Tm +9.75 0 0 -9.75 191.203308 184.125 Tm /f-0-0 1 Tf [(W)18(orld)]TJ ET 0.988235 0.917647 0.639216 rg -7.5 144.75 140.051 18 re f +30.113 144.75 140.051 18 re f 0 g q 1 0 0 1 0 0 cm -7.5 144.75 140.051 18 re S Q +30.113 144.75 140.051 18 re S Q BT -9.75 0 0 -9.75 15.75238 159.375 Tm +9.75 0 0 -9.75 34.616272 159.375 Tm /f-0-0 1 Tf [(V)55(elocityArrowRenderSystem)]TJ ET 0.988235 0.917647 0.639216 rg -54.641 97.5 92.91 18 re f +77.254 97.5 92.91 18 re f 0 g q 1 0 0 1 0 0 cm -54.641 97.5 92.91 18 re S Q +77.254 97.5 92.91 18 re S Q BT -9.75 0 0 -9.75 60.724731 112.125 Tm +9.75 0 0 -9.75 80.338623 112.125 Tm /f-0-0 1 Tf (BallRenderSystem)Tj ET 0.988235 0.917647 0.639216 rg -218.887 199.5 98.863 18 re f +241.5 205.5 98.867 18 re f 0 g q 1 0 0 1 0 0 cm -218.887 199.5 98.863 18 re S Q +241.5 205.5 98.867 18 re S Q BT -9.75 0 0 -9.75 225.510315 214.125 Tm +9.75 0 0 -9.75 245.124207 220.125 Tm /f-0-0 1 Tf (BallCreationSystem)Tj ET 0.988235 0.917647 0.639216 rg -218.887 223.5 97.773 18 re f +241.5 229.5 97.777 18 re f 0 g q 1 0 0 1 0 0 cm -218.887 223.5 97.773 18 re S Q +241.5 229.5 97.777 18 re S Q BT -9.75 0 0 -9.75 226.048279 238.125 Tm +9.75 0 0 -9.75 245.66217 244.125 Tm /f-0-0 1 Tf (BallPositionSystem)Tj ET 0.988235 0.917647 0.639216 rg -218.887 247.5 96.172 18 re f +241.5 253.5 96.172 18 re f 0 g q 1 0 0 1 0 0 cm -218.887 247.5 96.172 18 re S Q +241.5 253.5 96.172 18 re S Q BT -9.75 0 0 -9.75 225.788818 262.125 Tm +9.75 0 0 -9.75 245.40271 268.125 Tm /f-0-0 1 Tf [(BallV)55(elocitySystem)]TJ ET 0.988235 0.917647 0.639216 rg -45.266 223.5 102.285 18 re f +67.883 229.5 102.281 18 re f 0 g q 1 0 0 1 0 0 cm -45.266 223.5 102.285 18 re S Q +67.883 229.5 102.281 18 re S Q BT -9.75 0 0 -9.75 52.433899 238.125 Tm +9.75 0 0 -9.75 72.047791 244.125 Tm /f-0-0 1 Tf [(W)37(allCollisionSystem)]TJ ET 0.988235 0.917647 0.639216 rg -47.066 247.5 100.484 18 re f +69.68 253.5 100.484 18 re f 0 g q 1 0 0 1 0 0 cm -47.066 247.5 100.484 18 re S Q +69.68 253.5 100.484 18 re S Q BT -9.75 0 0 -9.75 54.502441 262.125 Tm +9.75 0 0 -9.75 74.116333 268.125 Tm /f-0-0 1 Tf (BallCollisionSystem)Tj ET 0.988235 0.917647 0.639216 rg -70.367 199.5 77.184 18 re f +92.98 205.5 77.184 18 re f 0 g q 1 0 0 1 0 0 cm -70.367 199.5 77.184 18 re S Q +92.98 205.5 77.184 18 re S Q BT -9.75 0 0 -9.75 76.723206 214.125 Tm +9.75 0 0 -9.75 97.837097 220.125 Tm /f-0-0 1 Tf (FrictionSystem)Tj ET 0.988235 0.917647 0.639216 rg -218.887 271.5 81.531 18 re f +241.5 277.5 81.531 18 re f 0 g q 1 0 0 1 0 0 cm -218.887 271.5 81.531 18 re S Q +241.5 277.5 81.531 18 re S Q BT -9.75 0 0 -9.75 224.703369 286.125 Tm +9.75 0 0 -9.75 245.817261 292.125 Tm /f-0-0 1 Tf (BallDragSystem)Tj ET 0.988235 0.917647 0.639216 rg -32.977 121.5 114.574 18 re f +55.59 121.5 114.574 18 re f 0 g q 1 0 0 1 0 0 cm -32.977 121.5 114.574 18 re S Q +55.59 121.5 114.574 18 re S Q BT -9.75 0 0 -9.75 39.594177 136.125 Tm +9.75 0 0 -9.75 59.208069 136.125 Tm /f-0-0 1 Tf (CreationRenderSystem)Tj ET 0.988235 0.917647 0.639216 rg -73.074 295.5 74.477 18 re f +95.688 301.5 74.477 18 re f 0 g q 1 0 0 1 0 0 cm -73.074 295.5 74.477 18 re S Q +95.688 301.5 74.477 18 re S Q BT -9.75 0 0 -9.75 78.61084 310.125 Tm +9.75 0 0 -9.75 99.724731 316.125 Tm /f-0-0 1 Tf (RegionSystem)Tj ET 0.988235 0.917647 0.639216 rg -44.887 271.5 102.664 18 re f +67.5 277.5 102.664 18 re f 0 g q 1 0 0 1 0 0 cm -44.887 271.5 102.664 18 re S Q +67.5 277.5 102.664 18 re S Q BT -9.75 0 0 -9.75 51.781677 286.125 Tm +9.75 0 0 -9.75 71.395569 292.125 Tm /f-0-0 1 Tf (BallSelectionSystem)Tj ET q 1 0 0 1 0 0 cm -170.887 187.5 m 170.887 208.5 l 147.637 208.5 l S Q +193.5 187.5 m 193.5 217.5 l 170.25 217.5 l S Q q 1 0 0 1 0 0 cm -170.887 187.5 m 170.887 232.5 l 147.637 232.5 l S Q +193.5 187.5 m 193.5 241.5 l 170.25 241.5 l S Q q 1 0 0 1 0 0 cm -170.887 187.5 m 170.887 256.5 l 147.637 256.5 l S Q +193.5 187.5 m 193.5 265.5 l 170.25 265.5 l S Q q 1 0 0 1 0 0 cm -170.887 187.5 m 170.887 280.5 l 147.637 280.5 l S Q +193.5 187.5 m 193.5 289.5 l 170.25 289.5 l S Q q 1 0 0 1 0 0 cm -170.887 187.5 m 170.887 304.5 l 147.637 304.5 l S Q +193.5 187.5 m 193.5 313.5 l 170.25 313.5 l S Q q 1 0 0 1 0 0 cm -194.887 187.5 m 194.887 208.5 l 218.887 208.5 l S Q +217.5 187.5 m 217.5 217.5 l 241.5 217.5 l S Q q 1 0 0 1 0 0 cm -194.887 187.5 m 194.887 232.5 l 218.887 232.5 l S Q +217.5 187.5 m 217.5 241.5 l 241.5 241.5 l S Q q 1 0 0 1 0 0 cm -194.887 187.5 m 194.887 256.5 l 218.887 256.5 l S Q +217.5 187.5 m 217.5 265.5 l 241.5 265.5 l S Q q 1 0 0 1 0 0 cm -194.887 187.5 m 194.887 280.5 l 218.887 280.5 l S Q +217.5 187.5 m 217.5 289.5 l 241.5 289.5 l S Q q 1 0 0 1 0 0 cm -182.887 169.5 m 182.887 106.5 l 147.637 106.5 l S Q +205.5 169.5 m 205.5 106.5 l 170.25 106.5 l S Q q 1 0 0 1 0 0 cm -182.887 169.5 m 182.887 153.75 l 147.637 153.75 l S Q +205.5 169.5 m 205.5 153.75 l 170.25 153.75 l S Q q 1 0 0 1 0 0 cm -182.887 169.5 m 182.887 130.5 l 147.637 130.5 l S Q +205.5 169.5 m 205.5 130.5 l 170.25 130.5 l S Q 0.980392 0.858824 0.678431 rg -164.887 325.5 41.438 27.75 re f +187.5 331.5 41.438 27.75 re f 0 g q 1 0 0 1 0 0 cm -164.887 325.5 41.438 27.75 re S Q +187.5 331.5 41.438 27.75 re S Q BT -9.75 0 0 -9.75 172.05542 338.625 Tm +9.75 0 0 -9.75 194.669312 344.625 Tm /f-1-0 1 Tf (\253trait\273)Tj /f-0-0 1 Tf @@ -842,164 +859,164 @@ BT (System)Tj ET q 1 0 0 1 0 0 cm -109.387 313.5 m 109.387 337.5 l 164.887 337.5 l S Q +96 313.5 m 49.5 313.5 l 49.5 343.5 l 187.5 343.5 l S Q 1 g -149.641 343.812 m 164.887 337.5 l 149.641 331.188 l f +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l f 0 g q 1 0 0 1 0 0 cm -149.641 343.812 m 164.887 337.5 l 149.641 331.188 l 149.641 343.812 l S Q +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l 172.258 349.812 l S Q q 1 0 0 1 0 0 cm -251.887 289.5 m 251.887 337.5 l 206.137 337.5 l S Q +323.25 289.5 m 355.5 289.5 l 355.5 343.5 l 228.75 343.5 l S Q 1 g -221.379 331.188 m 206.137 337.5 l 221.379 343.812 l f +243.992 337.188 m 228.75 343.5 l 243.992 349.812 l f 0 g q 1 0 0 1 0 0 cm -221.379 331.188 m 206.137 337.5 l 221.379 343.812 l 221.379 331.188 l S Q +243.992 337.188 m 228.75 343.5 l 243.992 349.812 l 243.992 337.188 l S Q 0.988235 0.917647 0.639216 rg -211.387 115.5 24.629 18 re f +241.5 115.5 24.633 18 re f 0 g q 1 0 0 1 0 0 cm -211.387 115.5 24.629 18 re S Q +241.5 115.5 24.633 18 re S Q BT -9.75 0 0 -9.75 215.572815 130.125 Tm +9.75 0 0 -9.75 244.936707 130.125 Tm /f-0-0 1 Tf (Ball)Tj ET 0.988235 0.917647 0.639216 rg -272.887 127.5 45.207 18 re f +301.5 127.5 45.207 18 re f 0 g q 1 0 0 1 0 0 cm -272.887 127.5 45.207 18 re S Q +301.5 127.5 45.207 18 re S Q BT -9.75 0 0 -9.75 278.146362 142.125 Tm +9.75 0 0 -9.75 305.260254 142.125 Tm /f-0-0 1 Tf (Position)Tj ET 0.988235 0.917647 0.639216 rg -272.887 151.5 43.602 18 re f +301.5 151.5 43.602 18 re f 0 g q 1 0 0 1 0 0 cm -272.887 151.5 43.602 18 re S Q +301.5 151.5 43.602 18 re S Q BT -9.75 0 0 -9.75 277.886902 166.125 Tm +9.75 0 0 -9.75 305.000793 166.125 Tm /f-0-0 1 Tf [(V)55(elocity)]TJ ET 0.988235 0.917647 0.639216 rg -272.887 103.5 33.848 18 re f +301.5 103.5 33.848 18 re f 0 g q 1 0 0 1 0 0 cm -272.887 103.5 33.848 18 re S Q +301.5 103.5 33.848 18 re S Q BT -9.75 0 0 -9.75 277.351318 118.125 Tm +9.75 0 0 -9.75 305.96521 118.125 Tm /f-0-0 1 Tf (Circle)Tj ET 0.988235 0.917647 0.639216 rg -272.887 79.5 31.141 18 re f +301.5 79.5 31.141 18 re f 0 g q 1 0 0 1 0 0 cm -272.887 79.5 31.141 18 re S Q +301.5 79.5 31.141 18 re S Q BT -9.75 0 0 -9.75 276.808594 94.125 Tm +9.75 0 0 -9.75 305.422485 94.125 Tm /f-0-0 1 Tf (Mass)Tj ET q 1 0 0 1 0 0 cm -236.137 121.5 m 248.887 121.5 l 248.887 85.5 l 272.887 85.5 l S Q +266.25 121.5 m 277.5 121.5 l 277.5 85.5 l 301.5 85.5 l S Q 1 g -265.266 88.656 m 272.887 85.5 l 265.266 82.344 l 256.387 85.5 l f +293.879 88.656 m 301.5 85.5 l 293.879 82.344 l 285 85.5 l f 0 g q 1 0 0 1 0 0 cm -265.266 88.656 m 272.887 85.5 l 265.266 82.344 l 256.387 85.5 l 265.266 - 88.656 l S Q +293.879 88.656 m 301.5 85.5 l 293.879 82.344 l 285 85.5 l 293.879 88.656 + l S Q q 1 0 0 1 0 0 cm -236.137 121.5 m 248.887 121.5 l 248.887 109.5 l 272.887 109.5 l S Q +266.25 121.5 m 277.5 121.5 l 277.5 109.5 l 301.5 109.5 l S Q 1 g -265.266 112.656 m 272.887 109.5 l 265.266 106.344 l 256.387 109.5 l f +293.879 112.656 m 301.5 109.5 l 293.879 106.344 l 285 109.5 l f 0 g q 1 0 0 1 0 0 cm -265.266 112.656 m 272.887 109.5 l 265.266 106.344 l 256.387 109.5 l 265.266 - 112.656 l S Q +293.879 112.656 m 301.5 109.5 l 293.879 106.344 l 285 109.5 l 293.879 112.656 + l S Q q 1 0 0 1 0 0 cm -236.137 121.5 m 248.887 121.5 l 248.887 133.5 l 272.887 133.5 l S Q +266.25 121.5 m 277.5 121.5 l 277.5 133.5 l 301.5 133.5 l S Q 1 g -265.266 136.656 m 272.887 133.5 l 265.266 130.344 l 256.387 133.5 l f +293.879 136.656 m 301.5 133.5 l 293.879 130.344 l 285 133.5 l f 0 g q 1 0 0 1 0 0 cm -265.266 136.656 m 272.887 133.5 l 265.266 130.344 l 256.387 133.5 l 265.266 - 136.656 l S Q +293.879 136.656 m 301.5 133.5 l 293.879 130.344 l 285 133.5 l 293.879 136.656 + l S Q q 1 0 0 1 0 0 cm -236.137 121.5 m 248.887 121.5 l 248.887 157.5 l 272.887 157.5 l S Q +266.25 121.5 m 277.5 121.5 l 277.5 157.5 l 301.5 157.5 l S Q 1 g -265.266 160.656 m 272.887 157.5 l 265.266 154.344 l 256.387 157.5 l f +293.879 160.656 m 301.5 157.5 l 293.879 154.344 l 285 157.5 l f 0 g q 1 0 0 1 0 0 cm -265.266 160.656 m 272.887 157.5 l 265.266 154.344 l 256.387 157.5 l 265.266 - 160.656 l S Q +293.879 160.656 m 301.5 157.5 l 293.879 154.344 l 285 157.5 l 293.879 160.656 + l S Q q 1 0 0 1 0 0 cm -199.387 178.5 m 223.387 178.5 l 223.387 133.5 l S Q -226.543 141.121 m 223.387 133.5 l 220.23 141.121 l 223.387 150 l f +222 178.5 m 252 178.5 l 252 133.5 l S Q +255.156 141.121 m 252 133.5 l 248.844 141.121 l 252 150 l f q 1 0 0 1 0 0 cm -226.543 141.121 m 223.387 133.5 l 220.23 141.121 l 223.387 150 l 226.543 - 141.121 l S Q +255.156 141.121 m 252 133.5 l 248.844 141.121 l 252 150 l 255.156 141.121 + l S Q 0.980392 0.858824 0.678431 rg -356.887 103.5 60.906 27.75 re f +385.5 103.5 60.91 27.75 re f 0 g q 1 0 0 1 0 0 cm -356.887 103.5 60.906 27.75 re S Q +385.5 103.5 60.91 27.75 re S Q BT -9.75 0 0 -9.75 373.791138 116.625 Tm +9.75 0 0 -9.75 402.405029 116.625 Tm /f-1-0 1 Tf (\253trait\273)Tj /f-0-0 1 Tf --1.195312 -1.153846 Td +-1.349159 -1.153846 Td (Component)Tj ET q 1 0 0 1 0 0 cm -304.387 85.5 m 332.887 85.5 l 332.887 121.5 l 356.887 121.5 l S Q +333 85.5 m 361.5 85.5 l 361.5 121.5 l 385.5 121.5 l S Q 1 g -341.641 127.812 m 356.887 121.5 l 341.641 115.188 l f +370.258 127.812 m 385.5 121.5 l 370.258 115.188 l f 0 g q 1 0 0 1 0 0 cm -341.641 127.812 m 356.887 121.5 l 341.641 115.188 l 341.641 127.812 l S Q +370.258 127.812 m 385.5 121.5 l 370.258 115.188 l 370.258 127.812 l S Q q 1 0 0 1 0 0 cm -306.637 109.5 m 332.887 109.5 l 332.887 121.5 l 356.887 121.5 l S Q +335.25 109.5 m 361.5 109.5 l 361.5 121.5 l 385.5 121.5 l S Q 1 g -341.641 127.812 m 356.887 121.5 l 341.641 115.188 l f +370.258 127.812 m 385.5 121.5 l 370.258 115.188 l f 0 g q 1 0 0 1 0 0 cm -341.641 127.812 m 356.887 121.5 l 341.641 115.188 l 341.641 127.812 l S Q +370.258 127.812 m 385.5 121.5 l 370.258 115.188 l 370.258 127.812 l S Q q 1 0 0 1 0 0 cm -317.887 133.5 m 332.887 133.5 l 332.887 121.5 l 356.887 121.5 l S Q +346.5 133.5 m 361.5 133.5 l 361.5 121.5 l 385.5 121.5 l S Q 1 g -341.641 127.812 m 356.887 121.5 l 341.641 115.188 l f +370.258 127.812 m 385.5 121.5 l 370.258 115.188 l f 0 g q 1 0 0 1 0 0 cm -341.641 127.812 m 356.887 121.5 l 341.641 115.188 l 341.641 127.812 l S Q +370.258 127.812 m 385.5 121.5 l 370.258 115.188 l 370.258 127.812 l S Q q 1 0 0 1 0 0 cm -316.387 157.5 m 332.887 157.5 l 332.887 121.5 l 356.887 121.5 l S Q +345 157.5 m 361.5 157.5 l 361.5 121.5 l 385.5 121.5 l S Q 1 g -341.641 127.812 m 356.887 121.5 l 341.641 115.188 l f +370.258 127.812 m 385.5 121.5 l 370.258 115.188 l f 0 g q 1 0 0 1 0 0 cm -341.641 127.812 m 356.887 121.5 l 341.641 115.188 l 341.641 127.812 l S Q +370.258 127.812 m 385.5 121.5 l 370.258 115.188 l 370.258 127.812 l S Q 0.980392 0.858824 0.678431 rg -80.887 7.5 65.531 67.5 re f +103.5 7.5 65.531 67.5 re f 0 g q 1 0 0 1 0 0 cm -80.887 7.5 65.531 67.5 re S Q +103.5 7.5 65.531 67.5 re S Q q 1 0 0 1 0 0 cm -80.887 36 m 146.418 36 l S Q +103.5 36 m 169.031 36 l S Q BT -9.75 0 0 -9.75 100.102478 20.625 Tm +9.75 0 0 -9.75 122.71637 20.625 Tm /f-1-0 1 Tf (\253trait\273)Tj /f-0-0 1 Tf --0.305664 -1.153846 Td -(Canvas)Tj +-1.33374 -1.153846 Td +(ECSCanvas)Tj /f-1-0 1 Tf --1.28063 -1.769231 Td +-0.252554 -1.769231 Td (+drawCircle\(\))Tj 0 -1.153846 Td (+drawArrow\(\))Tj @@ -1008,22 +1025,103 @@ BT ET [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -62.887 97.5 m 62.887 61.5 l 80.887 61.5 l S Q +85.5 97.5 m 85.5 61.5 l 103.5 61.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -73.266 64.656 m 80.887 61.5 l 73.266 58.344 l S Q +95.879 64.656 m 103.5 61.5 l 95.879 58.344 l S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -38.887 121.5 m 38.887 49.5 l 80.887 49.5 l S Q +61.5 121.5 m 61.5 49.5 l 103.5 49.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -73.266 52.656 m 80.887 49.5 l 73.266 46.344 l S Q +95.879 52.656 m 103.5 49.5 l 95.879 46.344 l S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -14.887 144.75 m 14.887 37.5 l 80.887 37.5 l S Q +37.5 144.75 m 37.5 37.5 l 103.5 37.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -73.266 40.656 m 80.887 37.5 l 73.266 34.344 l S Q +95.879 40.656 m 103.5 37.5 l 95.879 34.344 l S Q +0.258824 0.211765 0.00392157 rg +BT +9.75 0 0 -9.75 317.25 369 Tm +/f-0-0 1 Tf +(Systems)Tj +7.846154 20.923077 Td +[(Entity)-278(and)]TJ +0 -1 Td +(Components)Tj +ET +0 g +q 1 0 0 1 0 0 cm +67.5 289.5 m 49.5 289.5 l 49.5 343.5 l 187.5 343.5 l S Q +1 g +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l f +0 g +q 1 0 0 1 0 0 cm +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l 172.258 349.812 l S Q +q 1 0 0 1 0 0 cm +69.75 265.5 m 49.5 265.5 l 49.5 343.5 l 187.5 343.5 l S Q +1 g +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l f +0 g +q 1 0 0 1 0 0 cm +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l 172.258 349.812 l S Q +q 1 0 0 1 0 0 cm +68.25 241.5 m 49.5 241.5 l 49.5 343.5 l 187.5 343.5 l S Q +1 g +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l f +0 g +q 1 0 0 1 0 0 cm +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l 172.258 349.812 l S Q +q 1 0 0 1 0 0 cm +93 217.5 m 49.5 217.5 l 49.5 343.5 l 187.5 343.5 l S Q +1 g +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l f +0 g +q 1 0 0 1 0 0 cm +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l 172.258 349.812 l S Q +q 1 0 0 1 0 0 cm +340.5 217.5 m 355.5 217.5 l 355.5 343.5 l 228.75 343.5 l S Q +1 g +243.992 337.188 m 228.75 343.5 l 243.992 349.812 l f +0 g +q 1 0 0 1 0 0 cm +243.992 337.188 m 228.75 343.5 l 243.992 349.812 l 243.992 337.188 l S Q +q 1 0 0 1 0 0 cm +339 241.5 m 355.5 241.5 l 355.5 343.5 l 228.75 343.5 l S Q +1 g +243.992 337.188 m 228.75 343.5 l 243.992 349.812 l f +0 g +q 1 0 0 1 0 0 cm +243.992 337.188 m 228.75 343.5 l 243.992 349.812 l 243.992 337.188 l S Q +q 1 0 0 1 0 0 cm +337.5 265.5 m 355.5 265.5 l 355.5 343.5 l 228.75 343.5 l S Q +1 g +243.992 337.188 m 228.75 343.5 l 243.992 349.812 l f +0 g +q 1 0 0 1 0 0 cm +243.992 337.188 m 228.75 343.5 l 243.992 349.812 l 243.992 337.188 l S Q +q 1 0 0 1 0 0 cm +30 151.5 m 19.5 151.5 l 19.5 343.5 l 187.5 343.5 l S Q +1 g +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l f +0 g +q 1 0 0 1 0 0 cm +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l 172.258 349.812 l S Q +q 1 0 0 1 0 0 cm +55.5 129 m 19.5 129 l 19.5 343.5 l 187.5 343.5 l S Q +1 g +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l f +0 g +q 1 0 0 1 0 0 cm +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l 172.258 349.812 l S Q +q 1 0 0 1 0 0 cm +77.25 105 m 19.5 105 l 19.5 343.5 l 187.5 343.5 l S Q +1 g +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l f +0 g +q 1 0 0 1 0 0 cm +172.258 349.812 m 187.5 343.5 l 172.258 337.188 l 172.258 349.812 l S Q Q Q showpage %%Trailer diff --git a/doc/img/DemoArchitecture.eps b/doc/img/DemoArchitecture.eps new file mode 100644 index 00000000..81503a65 --- /dev/null +++ b/doc/img/DemoArchitecture.eps @@ -0,0 +1,959 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.17.4 (https://cairographics.org) +%%CreationDate: Thu Oct 14 17:07:38 2021 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 7 7 404 278 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%BeginResource: font LiberationSans-Bold +11 dict begin +/FontType 42 def +/FontName /LiberationSans-Bold def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 66 /B put +Encoding 67 /C put +Encoding 69 /E put +Encoding 70 /F put +Encoding 77 /M put +Encoding 80 /P put +Encoding 82 /R put +Encoding 83 /S put +Encoding 86 /V put +Encoding 87 /W put +Encoding 97 /a put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 103 /g put +Encoding 105 /i put +Encoding 108 /l put +Encoding 109 /m put +Encoding 110 /n put +Encoding 111 /o put +Encoding 112 /p put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 118 /v put +Encoding 121 /y put +/CharStrings 27 dict dup begin +/.notdef 0 def +/W 1 def +/o 2 def +/r 3 def +/l 4 def +/d 5 def +/R 6 def +/e 7 def +/n 8 def +/S 9 def +/y 10 def +/s 11 def +/t 12 def +/m 13 def +/B 14 def +/a 15 def +/C 16 def +/i 17 def +/E 18 def +/g 19 def +/F 20 def +/c 21 def +/P 22 def +/V 23 def +/M 24 def +/p 25 def +/v 26 def +end readonly def +/sfnts [ +<000100000009008000030010637674206d5f6ba1000016f8000002886670676d7e61b6110000 +1980000007b4676c79666f072b980000009c0000165c686561640b8df5290000213400000036 +686865610e18038e0000216c00000024686d7478843e0a29000021900000006c6c6f63610001 +2c60000021fc000000706d617870043305340000226c00000020707265708aa104b90000228c +00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e9000000000100020000078b05810017014040e51617010013100f0408070c0a09090c041317 +0519186b19015f19013419011b1901f41901db1901cf1901b419018b19010419241944196419 +046afb1901d41901bb19019019018419016b19015019014419012b1901041901eb1901c41901 +8b19ab1902141934195419741904fb1901d41901bb1901af19019419017b19016f1901501901 +4419012b190104190139b419d419f419039b19017419014b195b19023019012419010b1901f0 +190102e01901cf1901a019014f196f198f1903101901f01901df1901b019019f19017019010f +194f195f190308160f040903130c250c010c080012003f32325d11333f333333015e5d5d5d5d +5d5d71717171715f71727272727272725e5d5d5d5d5d5d5d5d5d5d5d71717171727272727272 +727272725e5d5d5d5d5d5d717171711112173911331133331133331133331133313029010326 +270e010321012113173e0113211316133f011321061ffea2bf2318181ec6fea2fe95012bcc2e +1c35ad014ab215321935aa012b032f909d8389fcb00581fc72dc8bfd02e2fd1254fed874e603 +100000020050ffec0493044e000b00150030401a11060c0006001716090f4f59091003144f59 +03167017016017017171003f2b00183f2b111201393911331133313001100021220011100021 +2000013426232011141633200493fedcfefefdfee00120010301090117feda7e78ff007d7601 +03021efef9fed5012c01060105012bfedffef1c1aefe91b5bd00000000010087000002fe044f +0016003e402508161600000f18170d125059080d10050f00159f18017f1801d01801af18015f +18012f18015d5d5d5d7171003f3f3f332b11120139391133113331303311342627211e011533 +3e02333217152623220615118f0503010c030a0429405842362144346975033c59772e12b71e +725d2d0feb0faaa7fded00000001008f000001a805cc00030046402d03000005040100001550 +0501400501b00501a005017f05016005011f0501ef0501d00501c00501b005018005015d5d5d +5d5d71717171717272003f3f1112013911333130331121118f011905ccfa340000020054ffec +045c05cc00160021003e402017031212131d091309222312000c1a4f590f0c10061f4f590306 +16001570230171003f3f332b00183f332b00183f1112013939113311331133333130212e0135 +230623220211101233321617332711211114170134262322061510333236034c040b045bffbd +ced9c773a72d0202011908fee37572716edd6f7a0f7928c401270109010d0125605fb2018bfb +2064880223afbdb7bcfe90c30000000200890000059d0581000d0015005d4033010c0c120912 +0303040e09000d0d09040317160c120202125f590202000505115f590503040012701701a017 +013017012017015d5d5d71003f323f2b11120039182f2b111200391112011739113311331133 +113311123911333130210121112111213204151406070901342901112132360451feb9fea6fe +d902c0fc0112a88f017dfe91fefcfe8601827c800217fde90581d9cb94d722fdb003d1cbfe60 +7000000000020050ffec042d044e00120019006f4043170a1011160b0b0303110a031b1a160b +525916211011480f16010e0516160006061352590610000e51597f1001101001101000169f1b +016f1b015f1b014f1b012f1b015d5d5d5d5d003f322f5d5d2b00183f2b11120039182f5f5e5d +2b2b111201173911331133113311333130052200111000333212111521141633323705020122 +0607212e01024af4fefa010af4e9f6fd4a756c9527010973fea0636b0301a4086e1401210115 +010c0120fecbfed6089ea18117feda03b18a7c8383000001008700000464044f0018004f402f +00181007070808181a1910141403505914100c0f080015a01a01901a01f01a01b01a01a01a01 +901a01701a01ef1a015d71717171717272003f323f3f2b110033111201393911331133113331 +3021111023220615112111342627211e0115333e013332161511034cc1667dfee70503010c03 +0a0439ac77acb8025f011daf89fdbc0348576f2c13a51f7c70d4ccfd51000001003bffec0506 +0596002a0052402f0c001d1c2216070606161c00042c2b0c22031919205f591d1d1904030a5f +5910072007300703300740070207070313003f332f5d712b00183f332f2b1112003939111201 +17391133113311331133313001140421202427251e01332035342e01272e0435342421200417 +052e01232015141e01171e030506fecdfed7fef1fecc2c011d1da89501354781b79e7c644627 +011f01120106010726fee216877efef43970abcbaf66360196cfdbc0c32f7065bc3c4e342525 +2d3d56744bbfcba4bd275b5ca8374631252b4961870000010010fe570468043a001501ba40ff +0b0a13090e1112120e030a041617110a0f130e0900055059001b961701861701731701631701 +00501701421701321701241701141701061701f21701e01701d01701c21701b41701a4170196 +170182170174170160170152170142170134170126170112170104170167f41701e21701d217 +01c41701b41701a2170194170184170176170166170154170144170132170122170114170106 +1701f61701d41701c61701b01701a21701921701841701761701661701401701321701221701 +141701061701f61701d41701c21701b2170101a0170190170184170160170154170144170130 +170120170114170104170137f41701cb1701b41701741701041701403bf41701e41701cb1701 +bb1701ab17019417017417013b170124170100170102f01701e01701bf170180170170170150 +1701301701101701001701075e5d5d5d5d5d5d5d5d5d5f717171717171717171717272727272 +5e5d5d5d5d5d5d5d5d5d5d5f5d5d5d5d71717171717171717171717171717272727272727272 +72727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171715f71717171003f +2b00182f33333f331112011739113311333311333130012227351633323e013701211316173f +011321010e01011b654c352c3c4f3f27fe540129aa283d1941a00126fe5456b9fe570dc80826 +5869042ffe056de15feb01fffb8dd0a0000000010048ffec041f044f00280072404507062114 +1b1a0d00001a140604292a210d1703171e5159c21b01601b01030f1b1f1b020a041b1b171003 +0a5159140724070207070316502a01b02a01302a01402a012f2a015d5d717172003f332f5d2b +00183f332f5f5e5d5f5d5d2b1112003939111201173911331133113311333130011404232226 +27371e01333236353426272e0235343633321617072e01232206151416171e03041ffeffe3df +ed27f7156780766c5768eea657efdbc1eb1df90c5e6664644d5b7fc57747013c9db38d95254d +403c40343d152f51815e9bad968e1a4241333c2f37121a374c7700010019ffee029105380015 +003b401d130c0c0a0d080d040416170d0506054f590a060808060f00114f590016003f2b0018 +3f332f11332b1100331112013911333311333311333130052226351123353337331533152311 +1416333237150601a47c86899758b0cdcd3c3f213d68128789027ebefefebefdce4f4b0eae22 +0000000100870000069e044f00260093405e172600001f081f1e1007081e0828272203140350 +5910171a0314100c0f1f080015e42801d428018428015428013b2801db2801bb28019b280154 +28013b28012f2801021f2801002801e02801d02801b028019f28018028016028012f28015d5d +5d5d5d5d5d71715f7171717171717272727272003f32323f3f17332b11003311120139391133 +331133111239113333313021111023220615112111342627211e0115333e01333217333e0133 +321615112111102322060711030ca4556bfee70503010c030a04349b6cf83506379a779ea6fe +e9a4526905025f011dae8afdbc0348576f2c13a51f7c70ec7e6ed7c9fd51025f011d9f8cfdaf +000300890000056a0581000e0017001f008540510c1309131b1b040f0918000009040321200c +141b141b5f590f141f1402140514160c491414040505135f590503041c5f590412a021019021 +018021017021016021015021014021013021013021012021015d5d7171717171717171003f2b +00183f2b11120039182f2b5f5e5d2b1112003911120117391133113311331133111239313001 +1404290111212004151406071e010134262321112132361334290111213236056afee0ff00fd +3f0285010201098588abb3fe867977feb001527d7152fee4fe8a01818e830192c0d20581b3af +78a51d14af01d55f50fea357fe09c6fe6c6700000002003cffec0480044e00260033006d403f +2427270707150e0f2c03030f1503353406285259060600590e690e022d0e01030f0e1f0e0209 +040e12120b51591210192f002f4f5924210016bf35014f35015d71003f32322b110033183f2b +1100335f5e5d5f5d5d1239182f2b11120117391133113311331133113331300522263534363f +0135342623220607253e0133321615111416333237150e0323222627230613070e0215141633 +323e013501899db0dbd0e94a544e4909fedb1bebcbcdde2930201e1928282d1e6a650a067659 +9062522b473b426d3e14ab9ba8b00204376a6747520e9ea3cabafe765b450698060a06046865 +d50209020423483c4d4b487f470000010054ffec058f05960018005240321609100f0203090f +03031a190c135f5910100c040002100202000240028002c002d002050b0302020606005f5906 +13301a015d003f2b110033182f5f5e5d713f332f2b1112011739113311331133313025201305 +060423200011100021320417052e01232206151412031b010b68010153febfe0feacfe8d0166 +0154f801383ffefc21c183c8cfd5d4010c61ccc70181015a015b0174c7c1476a7df8eff3ff00 +0002008f000001a805cc00030007005640360307070004040809050f04150100535901005009 +01400901b00901a009017f09016009011f0901ef0901d00901c00901b009018009015d5d5d5d +5d71717171717272003f2b00183f3f111201391133331133313013352115011121118f0119fe +e7011904fdcfcffb03043afbc60000010089000005060581000b0074404a050909000b00010b +060a030700040c0d05085f590f057f059f05030f058f05ff05030f03051615490f0501140505 +160c490505000101045f59010300095f590012400d01300d01200d015d5d5d003f2b00183f2b +11120039182f2b5f5e5d2b5f5e5d712b11120117395f5e5d1133113331303311211521112115 +21112115890454fcd302f0fd1003560581e4fe9ee4fe8de4000000020054fe4e045a044f0021 +002b0061403a18220a0a1f0403271212031f032d2c1b0f15254f591715100f294f590c0f1500 +075159560466047604032204320402050415040204001b702d0171003f325d5d5d2b00183f33 +2b00183f332b00183f1112011739113311331133113333313001222627251e013332363d0137 +230623220211101233321733343637210615111404033426232211103332360254c6f11c0119 +0f6350756c02025dffbdd0d6ccec5b050905010a06fefa0f776ee1df7077fe4e978c21414a90 +8e396bc7011c010801090120c32378136c8efce1e7ec03dea7bbfe98fe9fbb00000000010089 +00000498058100090048402a01050506080206030a0b01045f590f01010b0301400d31480101 +050707005f5907030512300b01200b015d5d003f3f2b11120039182f2b5f5e5d2b1112011739 +1133113331300111211521112111211501b002d1fd2ffed9040f049dfe4ce4fdfb0581e40001 +0050ffec0437044e00180042402414150a090f03030915031a19060d4f590a0a061000146014 +020d0314140000114f590016003f2b110033182f5f5e5d3f332f2b1112011739113311331133 +313005220011100033321617052e012322111033323637050e020252f6fef4010ef8bffa20fe +e50c6058d9dd506c0d011a0f81d21401250106010c012bc0a90e5363fe95fe8a65640d6fae5f +000000020089000005100581000b0013004840290f0606070c000700151405105f5905050608 +080f5f59080306128015017015016015013015011f15017171717171003f3f2b11120039182f +2b1112013939113311331133313001140e012321112111213204053429011121323605107ce7 +9ffea2fed90279fd0111fed7fefafecf01397a8403c388d675fe100581e9dadefe3779000001 +000e000005480581000a0038401f090a010006030202060a030c0bc00c019f0c01600c012f0c +01090203060112003f333f33015d5d5d5d11121739113311333311333130290101210116173f +0101210342fed5fdf7013401221b2f1533012101310581fc7758b256b4038900000000010089 +0000062105810017016d40ff150017100d0e170e1918040a07131713271303080a180a280a03 +090a13150f030e0800128b19016b19014b19013b19011b1901fb1901ef1901c41901ab19019f +19018b19017419015b19014f19013419010b190167ff1901e41901cb1901bb1901af19019419 +017b19016f19014419012b19011f19010b1901f41901db1901cf1901bb19018b19016b19014b +19013b19011b1901fb1901cb1901ab19018b19017b19015b19013b19012f190104190137eb19 +01cb1901b419019b19017419014b19012419010b1901fb1901d41901bb1901af19018419016b +19015f1901024019013f19011f1901f01901e01901cf1901a019017f19014f19013f19012019 +01b3001901075e5d5d5d5d5d5d5d5d5d7171715f7171717171717172727272727272725e5d5d +5d5d5d5d5d5d5d7171717171717171717272727272727272727272725e5d5d5d5d5d5d5d5d5d +5d5d7171717171003f32323f3339395e5d5d1133111201393911333311333331302111343637 +020703230b01161511211121131f0137012111051b01094722fed2fe6b0cfefa018bfc16303f +0103018903561d3adcfef36afcee03120177e84bfcaa0581fcec4cbde2033bfa7f0000020087 +fe57048f045100170021003c40201800121d09090b000b2322151a4f591215100e0f0a1b0320 +4f5906031670230171003f332b00183f3f3f332b111201393911331133331133313001100223 +2226272316151121113427211e0115333633321201102322061514163332048fd9c672a92d06 +06fee70801110507045ffbbdd0fedbdf7077776ee10222fef1fed9635d1e98fe6104ea996012 +6a34c7feddfef4016cc4b0afbf000000000100080000046a043a000a015340ff030201000609 +0a0a0602030b0c940c01800c01620c720c02540c01420c01340c01260c01120c01040c01f40c +01e60c01d20c0101c00c01a40cb40c02800c900c02640c740c02400c500c02340c01100c0104 +0c0167f40c01d00ce00c02b40cc40c02a00c01840c940c02600c01440c540c02200c01140c01 +d40ce40c02cb0c01900ca00c02840c01600c700c02440c540c02200c300c02140c01f00c01d4 +0ce40c02b00c01640c740c940ca40c04400c01240c340c02000c013702700c800cb00cc00cf0 +0c055f0c01000c100c400c03d00c01af0c01900c016f0c01500c012f0c3f0c027f0c8f0cbf0c +ef0cff0c05500c010f0c1f0c3f0c030709020f0601b015003f333f33015e5d5d5d7171717171 +717272725f5e5d5d5d5d5d5d5d71717171717171717272727272727272725e5d5d5d5d5d5d5d +5d5f5d5d5d71717171717171717111121739113311333311333130290101211316173e011321 +02dbfeb0fe7d0129bd0f380a3ec70126043afda332c829ce0260000005cc05cc007d05810015 +0079058100150000000000000000000000000000043a001400770000ffec00000000ffec0000 +0000ffec0000fe57fff700000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000800000000000119012500f500eb0000000000000000000000c100d3 +00ba00b000cf0000000000000000000000000127012901060000011200e400f400c600000000 +00000000000000000000000000000000000000000119011f014c0000000000df00d100c500b5 +00000000000000000000000000000000000000000000010200a901fd00d80119008000b701fd +00000000013f00db015d012500aa00800075008d01fc0179012100a001100000000001310119 +010e0104000000000000000000000000000000000000013d01ff00e00106009400e000940144 +00e005730319000000d802c5009c038102cd00cb00f4004e028d000000ff00d700cc01300145 +007300b400a60000000000730080008d000000000000000000000000030000a200980083008d +000000000000000005aefebc0581fd300011fff600b600bc00c60000007f008a006000000000 +0000000000f001ee0190000002190108011500000000000000be00000000000000000748036a +02b60202fd930000009100670091006101d90000028d03410000000000000000000000000000 +00aafe6ffe6801050093009800e20151008f00be00aefeb9fea4005e00af02d5005500f200a6 +04150601000003e1001002fa000ffed401eafff300b8000000000363000bfd0ffff500000000 +000006810477001504d90000ffecffc5fe7f007500cd00f2010200d5011940475b5a59585554 +535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c28 +272625242322211f181411100f0e0d0b0a090807060504030201002c20b0016045b003252011 +466123452361482d2c20451868442d2c45234660b0206120b04660b004262348482d2c452346 +2361b0206020b02661b02061b004262348482d2c45234660b0406120b06660b004262348482d +2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd +442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651582320b00d44 +235921212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a432343650a2d +2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c20 +45b00325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b006 +43b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361 +592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b52 +5845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c +01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243b00152582121 +2121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b00050 +58b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013515b58b00225 +46206861b00325b003253f2321381b2111592d2c2045b00325465058b0022546206861b00325 +b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b0 +8051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423648bb8155562 +1bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004254964234569 +b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c4b535820b003 +2549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b00e23 +44b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c45234560234560234560 +23766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1 +302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b00325 +45695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c4523 +20458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb0 +164358b00326458a586466b01f601b64b020606620581b21b04059b001615923586559b02923 +442310b029e01b2121212121592d2cb0024354584b53234b515a58381b2121591b2121212159 +2d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b0292344b00525b0 +0825082058021b0359b0042510b005252046b0042523423cb00425b0072508b0072510b00625 +2046b00425b0016023423c2058011b0059b0042510b00525b029e0b02920456544b0072510b0 +0625b029e0b00525b00825082058021b0359b00525b003254348b00425b0072508b00625b003 +25b0016043481b2159212121212121212d2c02b00425202046b004252342b0052508b0032545 +48212121212d2c02b0032520b0042508b0022543482121212d2c452320451820b00050205823 +652359236820b040505821b04059235865598a60442d2c4b53234b515a5820458a60441b2121 +592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b545838 +1b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb0 +02435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b +515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c0146234660234661 +23201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c +4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188535a58b91000 +0020885458b202010243604259b12401885158b920000040885458b2020202436042b1240188 +5458b2022002436042004b014b5258b2020802436042591bb940000080885458b20204024360 +4259b94000008063b80100885458b202080243604259b94000010063b80200885458b2021002 +43604259b12601885158b94000020063b80400885458b202400243604259b94000040063b808 +00885458b2028002436042595959595959b10002435458400a0540084009400c020d021bb101 +02435458b2054008ba010000090100b30c010d011bb18002435258b2054008b80180b109401b +b2054008ba01800009014059b9400000808855b94000020063b8040088555a58b30c000d011b +b30c000d0159595942424242422d2c451868234b51582320452064b04050587c59688a605944 +2d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201b001 +233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b0024350b001b00243 +545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d0001000000021999edcdae15 +5f0f3cf5001f080000000000c849682600000000dd7b292bfc25fcfd0a6f0844000100080002 +00010000000000010000073efe4e00430aaafc25fa7a0a6f0001000000000000000000000000 +0000001b060000cd078d000204e30050031d00870239008f04e3005405c700890473005004e3 +00870556003b047300100473004802aa0019071d008705c700890473003c05c700540239008f +0556008904e3005404e3008904730050055600890556000e06aa008904e30087047300080000 +00000000004c000001ec0000027800000300000003600000040c000004c00000059000000630 +0000070c0000091c00000a0800000a8800000b9000000c8800000d8c00000e3c00000ebc0000 +0f600000104c000010c00000115c000011f00000126000001428000014d40000165c00010000 +001b01520054005c000600020010002f005c0000034d0354000400014155013f000101390055 +013e000101390055014201400014001f01410140001f001f013b0033013a0055013800330139 +005500a4013900f4013900020132003d0131005501310001012f00550130003d012f0055012c +012900ff001f01290001012a00550128003d0127005501270001012a00550126003d01250055 +01250001012a00550123012200ff001f01220001012a0055012b003d012a0055005001070001 +002f0107000100af0104405001d0fd01bffd0110fd016ffb0140fb0180f590f5a0f503f1f035 +1f2ff09ff0025fef012fef5fef6fef9fefdfef05e6e4201fe5e43d1fe2e0271fe1e03d1fdf3d +dd55de3d035500dd30dd02dd0103552f410b011e00010010011e0020011e0040011e0003ffc0 +011e4028191c46dc03ff1f00db01da043c1fd4d21c1fd3d2261f60d190d1c0d10360d190d1b0 +d1c0d1e0d105b8ffc0b3d1191d46b8ffc0b4d10a0d460fb80116400f01bfbe261f40bb294146 +40bb222746b801214026b63d1f00b8016fb801b8b70a1f00b70100b720b740b760b770b70540 +b760b790b7d0b7f0b705b80120400d483d1f00b560b502a0b5d0b502b8ffc0400eb50b0e460f +b25fb202b1033c1f2f410b0119003f0119004f01190003008f01190001004001194028262946 +1faf2faf3faf9faf040faf0140af0e164600ad70ad80ad03e0adf0ad02abaa351faa50261fb9 +011b011ab23c1f00b8011ab6010fa9010fa801bc01170113003c001f0115407e503c1f9e9b27 +1f9d9b271f9c9b271f809b019846281f9f97af97029646351f0f941f94029390261f9291261f +0f8f1f8f6f8f7f8f8f8f058e8c261f4f8d010f8c01408c0b0f460f891f890286850f1f5f8501 +36824682027650261f7550261f7450261f7350261f2970011b7001037001f47001d670e67002 +687001597001b8fff0407d700a0d466f6e481f6e46321f1a01185519331855073303550603ff +1f6150261f605f321f5f50261f5e5a481f5c46271f5b5a781f5a46311f133212550501035504 +3203556f03010f033f034f036f037f03055f53014053282c4640531e224640531318466b527b +528b5203514f1c1f504f1c1f194f294f02594f694f02b80112402d46251f4946191f4846211f +4746351ff846019846011c481b551632155511010f5510320f55020100550100ff1fb80111b2 +1b091fb80110402d1b091f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f +0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff524bb007505bb00188b025 +53b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb0325358b0601d594b +b0645358b0401d594bb0805358b0101db11600425973747374752b2b2b2b2b2b2b2b0173742b +2b2b2b0073742b2b732b2b2b7373752b2b2b012b2b2b002b2b2b2b2b2b2b2b012b2b2b737373 +73747474002b2b2b2b0173732b73002b73732b732b2b73012b732b00732b2b2b2b2b7373732b +012b2b0073742b73742b73742b73012b73742b007374752b73742b2b2b012b00732b2b737401 +2b2b002b732b2b73752b732b2b012b2b002b2b737401732b0073737373737301737373002b2b +2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> +] def +/f-0-0 currentdict end definefont pop +%%EndResource +%%BeginResource: font LiberationSans +11 dict begin +/FontType 42 def +/FontName /LiberationSans def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 40 /parenleft put +Encoding 41 /parenright put +Encoding 43 /plus put +Encoding 65 /A put +Encoding 67 /C put +Encoding 97 /a put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 105 /i put +Encoding 108 /l put +Encoding 111 /o put +Encoding 114 /r put +Encoding 116 /t put +Encoding 119 /w put +Encoding 171 /guillemotleft put +Encoding 187 /guillemotright put +/CharStrings 18 dict dup begin +/.notdef 0 def +/guillemotleft 1 def +/t 2 def +/r 3 def +/a 4 def +/i 5 def +/guillemotright 6 def +/plus 7 def +/d 8 def +/w 9 def +/C 10 def +/c 11 def +/l 12 def +/e 13 def +/parenleft 14 def +/parenright 15 def +/A 16 def +/o 17 def +end readonly def +/sfnts [ +<000100000009008000030010637674204ada4bfa00000cbc000002886670676d7e61b6110000 +0f44000007b4676c7966408837e50000009c00000c20686561640b008bb1000016f800000036 +686865610d94038f0000173000000024686d74784808063600001754000000486c6f63610000 +70500000179c0000004c6d617870038103e4000017e80000002070726570fdae474900001808 +00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e900000000020053008d042003ac0008001100394020050806010f0a0e110a01110804131209 +000300ef5b0c0f032f036f037f030403002f5d332b1100331112011739113311331133113331 +302501350133150901152101350133150901150376feae0152a8feae0154fd83feb00150a7fe +b101518d016d3f01731ffe8cfe911d016d3f01731ffe8cfe911d0001001ffff0022a052c0014 +004540240d14140b0f0f09040416150e05080550590b0f09010c030940080f02125059021680 +16015d003f2b00183f1acd5f5e5d332b11003311120139113333113332113331302506232235 +11233533373315331523111416333237022a595dd87d843578c8c8333f24440818f502d283f2 +f283fd554e3f0e0000000001008800000288044e00130023401006131300000c14150f060a10 +040f0015003f3f3f3333111201393911331133313033113427331615333e0133321715262322 +0615118e06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4fdcc000000020057 +ffec0473044e00230030008e40562029290707150e0f2e03030f151a0432311d1851591d1620 +001107295159070711003f0e010f0e6f0e020b030e0e11110b50591110002450590016c03201 +a03201903201803201703201603201503201303201a032015d7171717171717171003f2b0018 +3f2b110033182f5f5e5d711112392f2b11120039183f2b111201173911331133113311331133 +31300522263534363f0135342623220607271221321615111416333237150623222627230e01 +27323e013d01070e02151416019ea3a4ddf6f37078796e0bbc2e0184ccce2a3b1a214447645b +060645b75a639a59c57f83465f14ac96a8b406043b8472525a110124bbb1fe2e505107701069 +707c67875a9d535904023064515860000000000200890000013d05cc00030007006e40480307 +070004040809050f0415010053590100ff0901e00901df0901c00901b009019f090180090170 +09011f0901000901f00901df0901c00901b00901a009019009014f09011f09015d7171717171 +717172727272727272727272003f2b00183f3f11120139113333113331301335331503113311 +89b4b4b40520acacfae0043afbc600020053008d042003ac000800110039402003080c110401 +0d0a0a1101080413120a000500ef5b0e0f052f056f057f050405002f5d332b11003311120117 +391133113311331133313025233509013533011501233509013533011502cea80152feb0a601 +52fcddaa0152feb0a8014f8d1d016f01741ffe8d3ffe931d016f01741ffe8d3f0001006400b4 +0447049e000b004340260900000603030d0ca90201030f025f02020c060200040504ad5909d6 +070137078707020705b3003f335d5d332b110033335f5e5d5f5d111201391133331133313001 +1123112135211133112115029f93fe5801a89301a80260fe5401ac9201acfe54920000020056 +ffec03ef05cc00160022005640311d000e0e0f17060f06242312150e00000b03080820505908 +10031a505903169024017024011f2401ff2401e02401c024015d5d5d717171003f2b00183f2b +1112003939183f3f1112013939113311331133333130250e0123220211102132161733271133 +111417232e0135011416333236353426232206033532a57acdc1018e7ba4320202b406ac0307 +fdda7887998a8a978879ae685a0114011802365a627901c1fb13a93610742a0170e3c4d4dfd7 +c8c90001fffd000005cc043a001401ae40ff01001107060c0f0e0313090c0311031408071401 +14160808010b0815030e1303080f010c11030715761601661601541601461601361601241601 +161601041601f41601e61601c41601b21601a416019616018616016616015416014416013616 +0114160106160169f61601e21601d41601c61601b61601961601841601741601661601461601 +361601241601161601061601f41601e61601b61601a416019416018616016916015616014416 +01361601061601e41601d61601c41601b61601a6160189160172160101601601541601241601 +04160138f41601d41601c41601a416018016017416014b1601301601241601141601fb1601c4 +1601a0160194164030017b16016416014416013416011b1601f01601e41601cb1601b4160194 +16018416016416013f160102101601001601085e5d5d5f5d5d5d5d5d5d5d5d71717171717171 +7171727272727272727272725e5d5d5d5d5f5d5d5d5d5d5d5d71717171717171717171717272 +7272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171003f1733 +3f17331101335e5d11335d1112173933321133331133331133333130212303270e0103230133 +13161737133313173713330496d1bd240926b9d0fed1b2b7072411e2c1bd2e1fcdb002fda92d +a9fd30043afd2118ae4a035bfd19be8b031a000000010068ffec057905960019005e40390310 +17160809091610031a1b0f17010d0317171313005f59130400081008400850089008a008d008 +e008080c0308080c0c065f590c13201b015d003f2b110033182f5f5e5d3f2b110033182f5f5e +5d11120117391133113311333130012200111000332013170604232224023510002132041707 +2e010318eafefc010fe70128959c57fec5d0d5fec9a3016c0142e1012e47b531d904fafed3fe +fafefdfec501254eb6beb10149e10151017eb0ad3c7b8200000000010057ffec03ca044e0019 +00664045000d1413060707130d031a1b101750591f147f148f14df1404141410102006700680 +06d006e0060500061006600670068006c006d00607090306060a0a0350590a161f1b015d003f +2b110033182f5f5e5d713f332f5d2b1112011739113311331133313001141633323637170e01 +23220211101233321617072e012322060113888960810fb615e0ace3eff0e0a6db1cb90e7269 +8f800222d8d0686c0c9cba011f01130111011fac970e5a6abe0000000001008a0000013e05cc +000300764051030000050401000015f00501e00501df0501c00501b005019f05018005017005 +011f05010f0501f00501df0501c00501b00501a005019005014f0501ff0501e00501d00501c0 +05018005017005011f05015d5d5d5d5d5d5d7171717171717172727272727272727272003f3f +1112013911333130331133118ab405ccfa34000000020057ffec0418044e0012001900774046 +131106071900000c0c0711031b1a06060003190050590d190114041919090f0f1650590f1009 +0350590916d01b01c01b01a01b01901b01801b01701b01601b01501b01301b01717171717171 +717171003f2b00183f2b11120039182f5f5e5d2b11120039182f111201173911331133113311 +33313001141633323637170221220211101233201115272e012322060701149a94758d199e61 +fea8f0fbfbe901ddba0f908783990601f7baca5e482dff00011e011a010c011efdc1188aab9d +af9900000001007ffe58029e05cc000e0022401007000b0a03040a0400030f100a1b0300003f +3f111201173911331133113331301310123733060211101217232602117fb5bcaebbafadbdae +bdb40214012101cccbd0fe2cfeeafeebfe2ed3cc01cd011f0001000cfe58022b05cc000e0022 +4010070003040b0a00040a030f100a00031b003f3f1112011739113311331133313001100207 +2336121110022733161211022bb5bcaebcaeafbbaebdb40210fedffe34cbd201d10117011701 +d2d1ccfe33fee10000000002000400000552058100070010005b40360d01000c020306050800 +03040408070312110c025f590c0c080503040012b01201501201f01201c01201901201601201 +3012012f12015d5d5d5d5d5d7171003f323f33392f2b11120117391133321133331239391239 +3931302103210323013309010706070321032627048fa1fd7ea2c6023fd90236fd5b091931b4 +020fb51c1c019cfe640581fa7f04f11c5382fe3101d14557000000020056ffec041d044e000a +00160048402c11060b0006001718080e50590810031450590316a01801901801801801701801 +601801501801301801df18015d71717171717171003f2b00183f2b1112013939113311333130 +0110022322021110213212033426232206151416333236041dfaeeedf201e5f8eabd859d9e8d +8b95a28b021efee4feea012101110230feeffee1e0cbcfdcd6d7d000000005cc05cc007d0581 +00150079058100150000000000000000000000000000043a001400770000ffec00000000ffec +00000000ffec0000fe5700000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000008000000000000b400bd00af00a0000000000000000000000000 +0088007e000000ac00000000000000000000000000bf00c300ab00000000009b008d00000000 +0000000000000000000000000000000000000000000000b900aa000000000000009400990087 +000000000000000000000000000000000000000000000000006a0083008d00a400b400000000 +0000000000000060006a0079009800ac00b800a700000122013300c3006b00000000000000db +00c90000000000000000000000000000000000000000000001e101c9009200a8006b009200b7 +006b009b0000027b02f200920252006e02d703810082008900a0009f0169008f0000016000a4 +015b005e0082000000000000005e0065006f0000000000000000000000000000008a009000a5 +007a0080000000000000000000000581fff3000dfcb300830089008f00960069007105cc000f +fc1efff2003404e6000dfed400bf031f00a700ae00b500000000008100000000000000000748 +036a02b60202fd930000009100670091006101d90000028d0341000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000006810468001404cb0000ffecffd3fe7f008300db00aa00ba00a000cf40475b5a5958 +5554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d +2c28272625242322211f181411100f0e0d0b0a090807060504030201002c20b0016045b00325 +2011466123452361482d2c20451868442d2c45234660b0206120b04660b004262348482d2c45 +23462361b0206020b02661b02061b004262348482d2c45234660b0406120b06660b004262348 +482d2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c20452320 +b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651582320b0 +0d44235921212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a43234365 +0a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d +2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01 +b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b0 +0361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c +4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec +2d2c01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243b0015258 +21212121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b0 +005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013515b58b0 +022546206861b00325b003253f2321381b2111592d2c2045b00325465058b0022546206861b0 +0325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c +21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423648bb815 +55621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab00425496423 +4569b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c4b535820 +b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b0 +0e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c4523456023456023 +456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c +45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b0 +032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c +452320458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034005944442d +2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b001615923586559b0 +2923442310b029e01b2121212121592d2cb0024354584b53234b515a58381b2121591b212121 +21592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b0292344b005 +25b00825082058021b0359b0042510b005252046b0042523423cb00425b0072508b0072510b0 +06252046b00425b0016023423c2058011b0059b0042510b00525b029e0b02920456544b00725 +10b00625b029e0b00525b00825082058021b0359b00525b003254348b00425b0072508b00625 +b00325b0016043481b2159212121212121212d2c02b00425202046b004252342b0052508b003 +254548212121212d2c02b0032520b0042508b0022543482121212d2c452320451820b0005020 +5823652359236820b040505821b04059235865598a60442d2c4b53234b515a5820458a60441b +2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b54 +58381b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b212121592d +2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a08234b53 +8a4b515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c014623466023 +466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353583c1b2159 +2d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188535a58b9 +10000020885458b202010243604259b12401885158b920000040885458b2020202436042b124 +01885458b2022002436042004b014b5258b2020802436042591bb940000080885458b2020402 +43604259b94000008063b80100885458b202080243604259b94000010063b80200885458b202 +100243604259b12601885158b94000020063b80400885458b202400243604259b94000040063 +b80800885458b2028002436042595959595959b10002435458400a0540084009400c020d021b +b10102435458b2054008ba010000090100b30c010d011bb18002435258b2054008b80180b109 +401bb2054008ba01800009014059b9400000808855b94000020063b8040088555a58b30c000d +011bb30c000d0159595942424242422d2c451868234b51582320452064b04050587c59688a60 +59442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201 +b001233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b0024350b001b0 +0243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d000100000002199925b0 +03a25f0f3cf5001f080000000000c840f99a00000000dd7b2e16fba6fd930a6a07d700000008 +000200010000000000010000073efe4e00430ab4fba6fa7a0a6a000100000000000000000000 +000000000012060000cd047300530239001f02aa00880473005701c700890473005304ac0064 +0473005605c7fffd05c700680400005701c7008a0473005702aa007f02aa000c055600040473 +0056000000000000004c000000d40000015c000001c0000002e000000374000003f80000046c +0000053000000730000007f4000008b40000094400000a1800000a7800000adc00000b840000 +0c2000010000001201520054005c000600020010002f005c000002a402040004000141210009 +013f000101390055013e000101390055014201400014001f01410140001f001f013b0033013a +00550138003301390055004001070001001f01070001009f010440aa01c0fd01affd0100fd01 +0a4ffb0120fb01f550281ff246281ff1462a1ff0462b1f5fef7fef020fef4fef5fef8fefafef +050be5e41e1fe3e2461f0fe20140e246161fe1e0461fcfe0dfe0efe00340e0333646e046181f +eeedff1fed01e855ec48eb55ea320055e9e8e855e7480055e600ff1fdd3ddf55df010355de3d +0355dc03ff1f0fd51fd5020fd51fd50240ca181b46cfc201bdc03c1fc150261fbcbe281fffb9 +0150b870b880b803b8ffc040ffb81232461fb73fb74fb76fb77fb79fb7afb70718b60170b2a0 +b2b0b2030fb20190b501b0b5010fb501080fb33fb3efb30380b090b002b0b0c0b0d0b0032faf +3faf02a0adb0ad02c0add0ad022fac3fac029fab01c0aad0aa024fa98fa9022fa96fa9bfa9ff +a9049c9b241f509b016f9601bf960196461d1f9594171f0f941f947f948f94ff940530914091 +02809101708f808f02908f01c08fd08f024f8c5f8c6f8c038646ff1f9f85018483311f74733f +1f7350261f6f6e3c1f6e46351f1a01185519331855073303550603ff1f6050261f5f50261f5c +46311f5b5a481f5a46311f1332125505010355043203556c03010c033c034c036c037c0305ef +51ff4064510240513538464051252846cf50014946201f4846351f4746351faf4601df46ef46 +028046011632155511010f5510320f55020100550100011f1f0f3f0f5f0f7f0f040f0f2f0f4f +0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb8 +07ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d +00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101db11600425973747374 +752b2b2b2b2b017374752b2b2b00742b2b7373752b2b2b012b2b2b002b2b2b2b2b2b012b2b00 +2b2b012b732b00747374757374732b012b747500732b73740173737400737474737473015e73 +737473730073732b7373012b002b012b00732b74752b2b2b2b2b2b2b2b2b2b2b012b2b742b2b +5e732b002b5e7374012b2b2b002b73735e73737301737373002b2b2b2b2b2b185e0000> +] def +/f-1-0 currentdict end definefont pop +%%EndResource +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 7 7 404 278 +%%EndPageSetup +q 7 7 397 271 rectclip +1 0 0 -1 0 285 cm q +0.976471 0.960784 0.894118 rg +175.5 7.5 228 114 re f +0.75 w +0 J +0 j +[] 0.0 d +10 M q 1 0 0 1 0 0 cm +175.5 7.5 228 114 re S Q +7.5 133.5 306 144 re f +q 1 0 0 1 0 0 cm +7.5 133.5 306 144 re S Q +0.988235 0.917647 0.639216 rg +133.5 109.5 34.191 18 re f +0 g +q 1 0 0 1 0 0 cm +133.5 109.5 34.191 18 re S Q +BT +9.75 0 0 -9.75 137.203308 124.125 Tm +/f-0-0 1 Tf +[(W)18(orld)]TJ +ET +0.988235 0.917647 0.639216 rg +47.137 145.5 75.027 18 re f +0 g +q 1 0 0 1 0 0 cm +47.137 145.5 75.027 18 re S Q +BT +9.75 0 0 -9.75 50.908264 160.125 Tm +/f-0-0 1 Tf +(RenderSystem)Tj +ET +0.988235 0.917647 0.639216 rg +181.5 145.5 98.867 18 re f +0 g +q 1 0 0 1 0 0 cm +181.5 145.5 98.867 18 re S Q +BT +9.75 0 0 -9.75 185.124207 160.125 Tm +/f-0-0 1 Tf +(BallCreationSystem)Tj +ET +0.988235 0.917647 0.639216 rg +181.5 169.5 92.352 18 re f +0 g +q 1 0 0 1 0 0 cm +181.5 169.5 92.352 18 re S Q +BT +9.75 0 0 -9.75 185.388428 184.125 Tm +/f-0-0 1 Tf +(BallEditingSystem)Tj +ET +0.988235 0.917647 0.639216 rg +39.562 193.5 82.602 18 re f +0 g +q 1 0 0 1 0 0 cm +39.562 193.5 82.602 18 re S Q +BT +9.75 0 0 -9.75 43.185974 208.125 Tm +/f-0-0 1 Tf +(CollisionSystem)Tj +ET +0.988235 0.917647 0.639216 rg +44.98 169.5 77.184 18 re f +0 g +q 1 0 0 1 0 0 cm +44.98 169.5 77.184 18 re S Q +BT +9.75 0 0 -9.75 48.337097 184.125 Tm +/f-0-0 1 Tf +(FrictionSystem)Tj +ET +0.988235 0.917647 0.639216 rg +181.5 193.5 102.664 18 re f +0 g +q 1 0 0 1 0 0 cm +181.5 193.5 102.664 18 re S Q +BT +9.75 0 0 -9.75 185.395569 208.125 Tm +/f-0-0 1 Tf +(BallSelectionSystem)Tj +ET +q 1 0 0 1 0 0 cm +139.5 127.5 m 139.5 181.5 l 122.25 181.5 l S Q +q 1 0 0 1 0 0 cm +139.5 127.5 m 139.5 202.5 l 122.25 202.5 l S Q +q 1 0 0 1 0 0 cm +163.5 127.5 m 163.5 202.5 l 181.5 202.5 l S Q +q 1 0 0 1 0 0 cm +163.5 127.5 m 163.5 157.5 l 181.5 157.5 l S Q +q 1 0 0 1 0 0 cm +163.5 127.5 m 163.5 181.5 l 181.5 181.5 l S Q +q 1 0 0 1 0 0 cm +139.5 127.5 m 139.5 157.5 l 122.25 157.5 l S Q +0.980392 0.858824 0.678431 rg +133.5 223.5 41.438 27.75 re f +0 g +q 1 0 0 1 0 0 cm +133.5 223.5 41.438 27.75 re S Q +BT +9.75 0 0 -9.75 140.669312 236.625 Tm +/f-1-0 1 Tf +(\253trait\273)Tj +/f-0-0 1 Tf +-0.354267 -1.153846 Td +(System)Tj +ET +0.988235 0.917647 0.639216 rg +187.5 55.5 24.633 18 re f +0 g +q 1 0 0 1 0 0 cm +187.5 55.5 24.633 18 re S Q +BT +9.75 0 0 -9.75 190.936707 70.125 Tm +/f-0-0 1 Tf +(Ball)Tj +ET +0.988235 0.917647 0.639216 rg +247.5 67.5 45.207 18 re f +0 g +q 1 0 0 1 0 0 cm +247.5 67.5 45.207 18 re S Q +BT +9.75 0 0 -9.75 251.260254 82.125 Tm +/f-0-0 1 Tf +(Position)Tj +ET +0.988235 0.917647 0.639216 rg +247.5 91.5 43.602 18 re f +0 g +q 1 0 0 1 0 0 cm +247.5 91.5 43.602 18 re S Q +BT +9.75 0 0 -9.75 251.000793 106.125 Tm +/f-0-0 1 Tf +[(V)55(elocity)]TJ +ET +0.988235 0.917647 0.639216 rg +247.5 43.5 33.848 18 re f +0 g +q 1 0 0 1 0 0 cm +247.5 43.5 33.848 18 re S Q +BT +9.75 0 0 -9.75 251.21521 58.125 Tm +/f-0-0 1 Tf +(Circle)Tj +ET +0.988235 0.917647 0.639216 rg +247.5 19.5 31.141 18 re f +0 g +q 1 0 0 1 0 0 cm +247.5 19.5 31.141 18 re S Q +BT +9.75 0 0 -9.75 251.422485 34.125 Tm +/f-0-0 1 Tf +(Mass)Tj +ET +q 1 0 0 1 0 0 cm +212.25 61.5 m 223.5 61.5 l 223.5 25.5 l 247.5 25.5 l S Q +1 g +239.879 28.656 m 247.5 25.5 l 239.879 22.344 l 231 25.5 l f +0 g +q 1 0 0 1 0 0 cm +239.879 28.656 m 247.5 25.5 l 239.879 22.344 l 231 25.5 l 239.879 28.656 + l S Q +q 1 0 0 1 0 0 cm +212.25 61.5 m 223.5 61.5 l 223.5 49.5 l 247.5 49.5 l S Q +1 g +239.879 52.656 m 247.5 49.5 l 239.879 46.344 l 231 49.5 l f +0 g +q 1 0 0 1 0 0 cm +239.879 52.656 m 247.5 49.5 l 239.879 46.344 l 231 49.5 l 239.879 52.656 + l S Q +q 1 0 0 1 0 0 cm +212.25 61.5 m 223.5 61.5 l 223.5 73.5 l 247.5 73.5 l S Q +1 g +239.879 76.656 m 247.5 73.5 l 239.879 70.344 l 231 73.5 l f +0 g +q 1 0 0 1 0 0 cm +239.879 76.656 m 247.5 73.5 l 239.879 70.344 l 231 73.5 l 239.879 76.656 + l S Q +q 1 0 0 1 0 0 cm +212.25 61.5 m 223.5 61.5 l 223.5 97.5 l 247.5 97.5 l S Q +1 g +239.879 100.656 m 247.5 97.5 l 239.879 94.344 l 231 97.5 l f +0 g +q 1 0 0 1 0 0 cm +239.879 100.656 m 247.5 97.5 l 239.879 94.344 l 231 97.5 l 239.879 100.656 + l S Q +q 1 0 0 1 0 0 cm +168 118.5 m 198 118.5 l 198 73.5 l S Q +201.156 81.121 m 198 73.5 l 194.844 81.121 l 198 90 l f +q 1 0 0 1 0 0 cm +201.156 81.121 m 198 73.5 l 194.844 81.121 l 198 90 l 201.156 81.121 l S Q +0.980392 0.858824 0.678431 rg +331.5 43.5 60.91 27.75 re f +0 g +q 1 0 0 1 0 0 cm +331.5 43.5 60.91 27.75 re S Q +BT +9.75 0 0 -9.75 348.405029 56.625 Tm +/f-1-0 1 Tf +(\253trait\273)Tj +/f-0-0 1 Tf +-1.349159 -1.153846 Td +(Component)Tj +ET +q 1 0 0 1 0 0 cm +279 25.5 m 307.5 25.5 l 307.5 61.5 l 331.5 61.5 l S Q +1 g +316.258 67.812 m 331.5 61.5 l 316.258 55.188 l f +0 g +q 1 0 0 1 0 0 cm +316.258 67.812 m 331.5 61.5 l 316.258 55.188 l 316.258 67.812 l S Q +q 1 0 0 1 0 0 cm +281.25 49.5 m 307.5 49.5 l 307.5 61.5 l 331.5 61.5 l S Q +1 g +316.258 67.812 m 331.5 61.5 l 316.258 55.188 l f +0 g +q 1 0 0 1 0 0 cm +316.258 67.812 m 331.5 61.5 l 316.258 55.188 l 316.258 67.812 l S Q +q 1 0 0 1 0 0 cm +292.5 73.5 m 307.5 73.5 l 307.5 61.5 l 331.5 61.5 l S Q +1 g +316.258 67.812 m 331.5 61.5 l 316.258 55.188 l f +0 g +q 1 0 0 1 0 0 cm +316.258 67.812 m 331.5 61.5 l 316.258 55.188 l 316.258 67.812 l S Q +q 1 0 0 1 0 0 cm +291 97.5 m 307.5 97.5 l 307.5 61.5 l 331.5 61.5 l S Q +1 g +316.258 67.812 m 331.5 61.5 l 316.258 55.188 l f +0 g +q 1 0 0 1 0 0 cm +316.258 67.812 m 331.5 61.5 l 316.258 55.188 l 316.258 67.812 l S Q +0.980392 0.858824 0.678431 rg +49.5 25.5 65.531 67.5 re f +0 g +q 1 0 0 1 0 0 cm +49.5 25.5 65.531 67.5 re S Q +q 1 0 0 1 0 0 cm +49.5 54 m 115.031 54 l S Q +BT +9.75 0 0 -9.75 68.71637 38.625 Tm +/f-1-0 1 Tf +(\253trait\273)Tj +/f-0-0 1 Tf +-1.33374 -1.153846 Td +(ECSCanvas)Tj +/f-1-0 1 Tf +-0.252554 -1.769231 Td +(+drawCircle\(\))Tj +0 -1.153846 Td +(+drawArrow\(\))Tj +0 -1.153846 Td +(+clear\(\))Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +79.5 145.5 m 79.5 93 l S Q +[] 0.0 d +q 1 0 0 1 0 0 cm +82.656 100.621 m 79.5 93 l 76.344 100.621 l S Q +0.258824 0.211765 0.00392157 rg +BT +9.75 0 0 -9.75 263.25 267 Tm +/f-0-0 1 Tf +(Systems)Tj +7.846154 16.615385 Td +[(Entity)-278(and)]TJ +0 -1 Td +(Components)Tj +ET +0 g +q 1 0 0 1 0 0 cm +284.25 202.5 m 295.5 202.5 l 295.5 237 l 174.75 237 l S Q +1 g +189.992 230.688 m 174.75 237 l 189.992 243.312 l f +0 g +q 1 0 0 1 0 0 cm +189.992 230.688 m 174.75 237 l 189.992 243.312 l 189.992 230.688 l S Q +q 1 0 0 1 0 0 cm +39.75 202.5 m 25.5 202.5 l 25.5 237 l 133.5 237 l S Q +1 g +118.258 243.312 m 133.5 237 l 118.258 230.688 l f +0 g +q 1 0 0 1 0 0 cm +118.258 243.312 m 133.5 237 l 118.258 230.688 l 118.258 243.312 l S Q +q 1 0 0 1 0 0 cm +45 178.5 m 25.5 178.5 l 25.5 237 l 133.5 237 l S Q +1 g +118.258 243.312 m 133.5 237 l 118.258 230.688 l f +0 g +q 1 0 0 1 0 0 cm +118.258 243.312 m 133.5 237 l 118.258 230.688 l 118.258 243.312 l S Q +q 1 0 0 1 0 0 cm +280.5 157.5 m 295.5 157.5 l 295.5 237 l 174.75 237 l S Q +1 g +189.992 230.688 m 174.75 237 l 189.992 243.312 l f +0 g +q 1 0 0 1 0 0 cm +189.992 230.688 m 174.75 237 l 189.992 243.312 l 189.992 230.688 l S Q +q 1 0 0 1 0 0 cm +273.75 181.5 m 295.5 181.5 l 295.5 237 l 174.75 237 l S Q +1 g +189.992 230.688 m 174.75 237 l 189.992 243.312 l f +0 g +q 1 0 0 1 0 0 cm +189.992 230.688 m 174.75 237 l 189.992 243.312 l 189.992 230.688 l S Q +q 1 0 0 1 0 0 cm +47.25 154.5 m 25.5 154.5 l 25.5 237 l 133.5 237 l S Q +1 g +118.258 243.312 m 133.5 237 l 118.258 230.688 l f +0 g +q 1 0 0 1 0 0 cm +118.258 243.312 m 133.5 237 l 118.258 230.688 l 118.258 243.312 l S Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/doc/img/Facade.eps b/doc/img/Facade.eps new file mode 100644 index 00000000..9da693ca --- /dev/null +++ b/doc/img/Facade.eps @@ -0,0 +1,728 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.17.4 (https://cairographics.org) +%%CreationDate: Thu Oct 14 17:52:40 2021 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 7 7 330 212 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%BeginResource: font LiberationSans +11 dict begin +/FontType 42 def +/FontName /LiberationSans def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 32 /space put +Encoding 40 /parenleft put +Encoding 41 /parenright put +Encoding 43 /plus put +Encoding 44 /comma put +Encoding 58 /colon put +Encoding 67 /C put +Encoding 68 /D put +Encoding 76 /L put +Encoding 80 /P put +Encoding 87 /W put +Encoding 97 /a put +Encoding 98 /b put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 102 /f put +Encoding 104 /h put +Encoding 105 /i put +Encoding 108 /l put +Encoding 109 /m put +Encoding 110 /n put +Encoding 111 /o put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 117 /u put +Encoding 119 /w put +Encoding 171 /guillemotleft put +Encoding 187 /guillemotright put +/CharStrings 31 dict dup begin +/.notdef 0 def +/guillemotleft 1 def +/t 2 def +/r 3 def +/a 4 def +/i 5 def +/guillemotright 6 def +/plus 7 def +/d 8 def +/w 9 def +/C 10 def +/l 11 def +/c 12 def +/e 13 def +/parenleft 14 def +/o 15 def +/colon 16 def +/space 17 def +/P 18 def +/n 19 def +/comma 20 def +/u 21 def +/s 22 def +/D 23 def +/b 24 def +/W 25 def +/h 26 def +/parenright 27 def +/f 28 def +/L 29 def +/m 30 def +end readonly def +/sfnts [ +<000100000009008000030010637674204ada4bfa000016e0000002886670676d7e61b6110000 +1968000007b4676c796676b006be0000009c00001644686561640b008bb10000211c00000036 +686865610d94039c0000215400000024686d74787f290ca3000021780000007c6c6f63610001 +4688000021f4000000806d617870038e03e4000022740000002070726570fdae474900002294 +00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e900000000020053008d042003ac0008001100394020050806010f0a0e110a01110804131209 +000300ef5b0c0f032f036f037f030403002f5d332b1100331112011739113311331133113331 +302501350133150901152101350133150901150376feae0152a8feae0154fd83feb00150a7fe +b101518d016d3f01731ffe8cfe911d016d3f01731ffe8cfe911d0001001ffff0022a052c0014 +004540240d14140b0f0f09040416150e05080550590b0f09010c030940080f02125059021680 +16015d003f2b00183f1acd5f5e5d332b11003311120139113333113332113331302506232235 +11233533373315331523111416333237022a595dd87d843578c8c8333f24440818f502d283f2 +f283fd554e3f0e0000000001008800000288044e00130023401006131300000c14150f060a10 +040f0015003f3f3f3333111201393911331133313033113427331615333e0133321715262322 +0615118e06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4fdcc000000020057 +ffec0473044e00230030008e40562029290707150e0f2e03030f151a0432311d1851591d1620 +001107295159070711003f0e010f0e6f0e020b030e0e11110b50591110002450590016c03201 +a03201903201803201703201603201503201303201a032015d7171717171717171003f2b0018 +3f2b110033182f5f5e5d711112392f2b11120039183f2b111201173911331133113311331133 +31300522263534363f0135342623220607271221321615111416333237150623222627230e01 +27323e013d01070e02151416019ea3a4ddf6f37078796e0bbc2e0184ccce2a3b1a214447645b +060645b75a639a59c57f83465f14ac96a8b406043b8472525a110124bbb1fe2e505107701069 +707c67875a9d535904023064515860000000000200890000013d05cc00030007006e40480307 +070004040809050f0415010053590100ff0901e00901df0901c00901b009019f090180090170 +09011f0901000901f00901df0901c00901b00901a009019009014f09011f09015d7171717171 +717172727272727272727272003f2b00183f3f11120139113333113331301335331503113311 +89b4b4b40520acacfae0043afbc600020053008d042003ac000800110039402003080c110401 +0d0a0a1101080413120a000500ef5b0e0f052f056f057f050405002f5d332b11003311120117 +391133113311331133313025233509013533011501233509013533011502cea80152feb0a601 +52fcddaa0152feb0a8014f8d1d016f01741ffe8d3ffe931d016f01741ffe8d3f0001006400b4 +0447049e000b004340260900000603030d0ca90201030f025f02020c060200040504ad5909d6 +070137078707020705b3003f335d5d332b110033335f5e5d5f5d111201391133331133313001 +1123112135211133112115029f93fe5801a89301a80260fe5401ac9201acfe54920000020056 +ffec03ef05cc00160022005640311d000e0e0f17060f06242312150e00000b03080820505908 +10031a505903169024017024011f2401ff2401e02401c024015d5d5d717171003f2b00183f2b +1112003939183f3f1112013939113311331133333130250e0123220211102132161733271133 +111417232e0135011416333236353426232206033532a57acdc1018e7ba4320202b406ac0307 +fdda7887998a8a978879ae685a0114011802365a627901c1fb13a93610742a0170e3c4d4dfd7 +c8c90001fffd000005cc043a001401ae40ff01001107060c0f0e0313090c0311031408071401 +14160808010b0815030e1303080f010c11030715761601661601541601461601361601241601 +161601041601f41601e61601c41601b21601a416019616018616016616015416014416013616 +0114160106160169f61601e21601d41601c61601b61601961601841601741601661601461601 +361601241601161601061601f41601e61601b61601a416019416018616016916015616014416 +01361601061601e41601d61601c41601b61601a6160189160172160101601601541601241601 +04160138f41601d41601c41601a416018016017416014b1601301601241601141601fb1601c4 +1601a0160194164030017b16016416014416013416011b1601f01601e41601cb1601b4160194 +16018416016416013f160102101601001601085e5d5d5f5d5d5d5d5d5d5d5d71717171717171 +7171727272727272727272725e5d5d5d5d5f5d5d5d5d5d5d5d71717171717171717171717272 +7272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171003f1733 +3f17331101335e5d11335d1112173933321133331133331133333130212303270e0103230133 +13161737133313173713330496d1bd240926b9d0fed1b2b7072411e2c1bd2e1fcdb002fda92d +a9fd30043afd2118ae4a035bfd19be8b031a000000010068ffec057905960019005e40390310 +17160809091610031a1b0f17010d0317171313005f59130400081008400850089008a008d008 +e008080c0308080c0c065f590c13201b015d003f2b110033182f5f5e5d3f2b110033182f5f5e +5d11120117391133113311333130012200111000332013170604232224023510002132041707 +2e010318eafefc010fe70128959c57fec5d0d5fec9a3016c0142e1012e47b531d904fafed3fe +fafefdfec501254eb6beb10149e10151017eb0ad3c7b820000000001008a0000013e05cc0003 +00764051030000050401000015f00501e00501df0501c00501b005019f05018005017005011f +05010f0501f00501df0501c00501b00501a005019005014f0501ff0501e00501d00501c00501 +8005017005011f05015d5d5d5d5d5d5d7171717171717172727272727272727272003f3f1112 +013911333130331133118ab405ccfa34000000010057ffec03ca044e001900664045000d1413 +060707130d031a1b101750591f147f148f14df140414141010200670068006d006e006050006 +1006600670068006c006d00607090306060a0a0350590a161f1b015d003f2b110033182f5f5e +5d713f332f5d2b1112011739113311331133313001141633323637170e012322021110123332 +1617072e012322060113888960810fb615e0ace3eff0e0a6db1cb90e72698f800222d8d0686c +0c9cba011f01130111011fac970e5a6abe00000000020057ffec0418044e0012001900774046 +131106071900000c0c0711031b1a06060003190050590d190114041919090f0f1650590f1009 +0350590916d01b01c01b01a01b01901b01801b01701b01601b01501b01301b01717171717171 +717171003f2b00183f2b11120039182f5f5e5d2b11120039182f111201173911331133113311 +33313001141633323637170221220211101233201115272e012322060701149a94758d199e61 +fea8f0fbfbe901ddba0f908783990601f7baca5e482dff00011e011a010c011efdc1188aab9d +af9900000001007ffe58029e05cc000e0022401007000b0a03040a0400030f100a1b0300003f +3f111201173911331133113331301310123733060211101217232602117fb5bcaebbafadbdae +bdb40214012101cccbd0fe2cfeeafeebfe2ed3cc01cd011f00020056ffec041d044e000a0016 +0048402c11060b0006001718080e50590810031450590316a018019018018018017018016018 +01501801301801df18015d71717171717171003f2b00183f2b11120139391133113331300110 +022322021110213212033426232206151416333236041dfaeeedf201e5f8eabd859d9e8d8b95 +a28b021efee4feea012101110230feeffee1e0cbcfdcd6d7d0000000000200bb0000017e043a +0003000700274013030707040004090804059c5b0401009c5b010f003f2b00182f2b11120139 +391133113331301335331503353315bbc3c3c3036bcfcffc95cfcf00000200a8000004ea0581 +000a0011003c40200f0505060b00060012130f045f590f0f0507070e5f590703051220130120 +13015d71003f3f2b11120039182f2b1112013939113311331133313001140423211123112132 +040710290111212004eafefbe0fe62bf0251ed0104c0feb8fe850183014003d9c8ecfddb0581 +decc0111fdd4000000010088000003ee044e001a0061403c1209090a001a0a1a1b1c12160016 +05505916100d0f0a0015d01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b0 +1c01a01c01701c015d5d5d5d5d5d5d7171727272003f323f3f2b111200391112013939113311 +33113331302111342e01232206151123113427331e0217333e01333216151103392a5c598296 +b406aa01020302033ea379b2a502ae6b7634b29efd8d0353bd2a052c394f705db1ccfd2f0001 +00b8fefa018100db0009002240110405000805080a0b0005a85b08009b5b08002f2b2b111201 +393911331133313025151406072336352335018126287b5e58dba86a8e41887edb0000000001 +0085ffec03eb043a001a005f403b1208080b01190b191c1b12051605505916160d1509000fd0 +1c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a01c01701c015d5d5d +5d5d5d5d7171727272003f323f3f2b110033111201393911331133113331300111141e013332 +36351133111417232e0227230e012322263511013a2a5c598296b406aa01020302033ea379b2 +a5043afd526b7634b29e0273fcadbd2a052c394f705db1cc02d100010039ffec03b6044b002a +0064403c070622151c1b0d00001b1506042b2c0d220318181f50591c1810030a505907031610 +2c01002c01f02c01e02c01c02c01602c01802c013f2c01102c015d5d5d717171717272003f33 +2b00183f332b111200393911120117391133113311331133313001140623222627371e013332 +363534262f012e0235343633321617072e0123220615141e01171e0303b6e7d0cadb219f1790 +80897f5862819b834ad3cab3d31ca20f836e7a74305e978f7e4928012b99a6858d1f57515454 +40501a22284d6e50949b7e8b14484d4a4b2e3c2a25243d4a6100000200a80000056505810009 +0013002c40170f050a0005001415060e5f590603050f5f5905122015015d003f2b00183f2b11 +1201393911331133313001140204232111212000031000290111213236120565aafec8ccfdf1 +01d201660185c0fee1fef0fef1013a9beb7e02cfdafeb9ae0581fe99feb501060113fbb18801 +000000020084ffec041d05cc00170023005d40371e050e0e0d18000d00242505110215151b50 +5915100d000a15022150590216b025013f25019025017025011f2501ff2501e02501c025015d +5d5d7171717272003f2b00183f3f3f2b11120039391112013939113311331133333130011021 +222627231406072336351133111407333e01333212033426232206151416333236041dfe727b +a333020802ae06b4040432a57acdc1bd7887988b889988790222fdca59631f7f0a36a904edfe +594158685afeecfee2e3c4d0e2d5cbc900010009000007860581001901fc40ff181908010101 +0014071101081001111004080707010b03070d0a09090d041419051b1a8b1b011bc07c7f4839 +1b012a1b01191b010a1b01f91b01ea1b01d91b01ca1b01b81b01891b991ba91b03781b01691b +013a1b4a1b5a1b03291b011a1b010c1b0168fd1b01ec1b01dd1b01cc1b01bd1b01ab1b019c1b +018b1b017c1b016b1b015c1b014b1b013c1b012b1b011c1b010b1b01fc1b01eb1b01dc1b01cb +1b01bc1b01ab1b019c1b01008d1b017f1b016d1b015f1b014d1b012f1b3f1b021d1b010f1b01 +fd1b01ef1b01dd1b01cf1b01bd1b01af1b019d1b018f1b016d1b7d1b025b1b014d1b013b1b01 +2d1b011b1b010d1b0138fb1b01ed1b01db1b01cd1b406f01bb1b01ad1b019b1b018d1b017b1b +016d1b014b1b5b1b02391b012b1b01191b010b1b01f91b01eb1b01dd1b01cb1b01bd1b01ab1b +019d1b018b1b017d1b016b1b015d1b014b1b013d1b01012b1b011f1b01025f1b7f1b9f1bbf1b +df1bff1b06001b01081810040903140d0d010812003f333311333f333333015e5d5d5f71715f +717171717171717171717171717272727272727272727272727272725e5d5d5d5d5d5d5d5d5d +5d5d5d5d5d5d71717171717171715f7171717171717172727272727272727272727272727272 +5e5d5d5d5d5d5d5d5d5d5d5d5d717171712b7111121739113311335f5e5d331133335d5d1133 +335d1133313021230326270e010323013313161736121333131617373e01013305e7e4f4182e +1a24ffe4fe61c7fd2d26183ff6b7f53820091b220108c7037f54d9749cfc640581fc81a8b26e +01040367fc93d79523739103b20000000001008e000003ee05cc00180060403b151111120807 +1207191a13000003120715030d50590310d01a01c01a01b01a01f01a01b01a01ff1a01e01a01 +d01a01c01a01b01a01a01a01701a015d5d5d5d5d5d5d7171727272003f2b00183f3312393f11 +120139391133113311333130013e0133321615112311342e0123220615112311331114060701 +3d3aa37db0a7b52a60557f99b4b4070103816a63afcefd2f02ae726f34b095fd8205ccfe7e3d +820a0001000cfe58022b05cc000e00224010070003040b0a00040a030f100a00031b003f3f11 +120117391133113311333130011002072336121110022733161211022bb5bcaebcaeafbbaebd +b40210fedffe34cbd201d10117011701d2d1ccfe33fee10000000001001d0000023c05ca0015 +008f40680d1301060102021504150417160a0f50590a0000030603505913060f01151f172f17 +4f175f177f178f179f17070f173f177f17af17bf17df17ef17073b5f17bf17027f178f179f17 +030f172f17af17df17ef170517405664481740272c48201730176017034017015d712b2b5d71 +725e5d71003f3f332b110033183f2b1112013932111239113333113332313001112311233533 +35343633321715262322061d0133150169b4989882864b342d23453ed303b7fc4903b7837a94 +820c8908465c61830000000100a80000042f05810005001f400e030000040607010300035f59 +0012003f2b00183f111201393911333130331133112115a8bf02c80581fb1b9c000100880000 +0623044e0029017e40ff182900002109212012080920092b2a1c2550591c1018110015150450 +5915100c0f21090015642b014b2b013f2b012b2b011f2b010f2b01eb2b01df2b01bb2b01ab2b +018b2b017b2b016f2b013b2b011f2b010b2b016aeb2b01cb2b01bb2b01af2b018b2b017f2b01 +5b2b014f2b011b2b01fb2b01ef2b01df2b01cb2b01bb2b01af2b01942b01642b014b2b012b2b +011b2b01042b01f42b01db2b01ab2b018b2b017f2b016b2b01342b011b2b010f2b0139fb2b01 +db2b01bb2b01a02b01942b01742b015b2b014b2b012b2b011f2b010b2b01fb2b01eb2b01cb2b +01a42b017b2b015b2b014b2b011b2b01f42b01d02b0102c02b01a02b01902b01602b014f2b40 +0b01302b012f2b01002b01085e5d5d5d5d5d5d5d5d5f5d5d7171717171717171727272727272 +72727272725e5d5d5d5d5d5d5d5d5d7171717171717171717171717272727272727272725e5d +5d5d5d5d5d5d5d5d5d717171717171003f32323f3f2b1112003939183f2b1112013939113333 +1133111239113333313021113426232206151123113427331e0217333e0133321617333e0133 +32161511231134262322061511030056707386b306aa01020302033a966c7b8f1c03389f71a4 +95b25670768302ae9d78b0a0fd8d0353bd2a052c394f735a626b6d60b2cbfd2f02ae9d78afa1 +fd8d000005cc05cc007d058100150079058100150000000000000000000000000000043a0014 +00770000ffec00000000ffec00000000ffec0000fe5700000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000008000000000000b400bd00af00a0 +0000000000000000000000000088007e000000ac00000000000000000000000000bf00c300ab +00000000009b008d000000000000000000000000000000000000000000000000000000b900aa +000000000000009400990087000000000000000000000000000000000000000000000000006a +0083008d00a400b4000000000000000000000060006a0079009800ac00b800a7000001220133 +00c3006b00000000000000db00c90000000000000000000000000000000000000000000001e1 +01c9009200a8006b009200b7006b009b0000027b02f200920252006e02d703810082008900a0 +009f0169008f0000016000a4015b005e0082000000000000005e0065006f0000000000000000 +000000000000008a009000a5007a0080000000000000000000000581fff3000dfcb300830089 +008f00960069007105cc000ffc1efff2003404e6000dfed400bf031f00a700ae00b500000000 +008100000000000000000748036a02b60202fd930000009100670091006101d90000028d0341 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000006810468001404cb0000ffecffd3fe7f008300db00aa +00ba00a000cf40475b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c +3b3a393837363531302f2e2d2c28272625242322211f181411100f0e0d0b0a09080706050403 +0201002c20b0016045b003252011466123452361482d2c20451868442d2c45234660b0206120 +b04660b004262348482d2c4523462361b0206020b02661b02061b004262348482d2c45234660 +b0406120b06660b004262348482d2c4523462361b0406020b02661b04061b004262348482d2c +0110203c003c2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d +44235920b0042651582320b00d44235921212d2c20204518684420b001602045b04676688a45 +60442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b02823 +70b10228453ab10200080d2d2c2045b00325456164b050515845441b2121592d2c49b00e2344 +2d2c2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb810 +0062602b0c642364615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c45 +65b02c234445b02b23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b00525 +1023208af500b0016023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f5 +00edec2d2cb00243b001525821212121211b462346608a8a462320468a608a61b8ff80622320 +10238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045 +b0032546524bb013515b58b0022546206861b00325b003253f2321381b2111592d2c2045b003 +25465058b0022546206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21 +210c6423648bb84000622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c +21b0c051580c6423648bb81555621bb200802f2b59b002602d2c0c6423648bb8400062602321 +2d2c4b53588ab004254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a +121120392f592d2c4b535820b0032549646920b00526b0062549642361b08062b020616ab00e +2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f +2f592d2c4523456023456023456023766818b08062202d2cb0482b2d2c2045b0005458b04044 +2045b04061441b2121592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423 +421b2121592d2c4b515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0 +016069442d2cb02f45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b1 +34201bb3330034005944442d2cb0164358b00326458a586466b01f601b64b020606620581b21 +b04059b001615923586559b02923442310b029e01b2121212121592d2cb0024354584b53234b +515a58381b2121591b21212121592d2cb0164358b004254564b020606620581b21b04059b001 +6123581b6559b0292344b00525b00825082058021b0359b0042510b005252046b0042523423c +b00425b0072508b0072510b006252046b00425b0016023423c2058011b0059b0042510b00525 +b029e0b02920456544b0072510b00625b029e0b00525b00825082058021b0359b00525b00325 +4348b00425b0072508b00625b00325b0016043481b2159212121212121212d2c02b004252020 +46b004252342b0052508b003254548212121212d2c02b0032520b0042508b002254348212121 +2d2c452320451820b00050205823652359236820b040505821b04059235865598a60442d2c4b +53234b515a5820458a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58 +381b2121592d2cb000214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb002 +435458b0472b1b212121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b +212121592d2c208a08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038 +111b21592d2c014623466023466123201020468a61b8ff80628ab140408a704560683a2d2c20 +8a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b1 +23018851b1400188535a58b910000020885458b202010243604259b12401885158b920000040 +885458b2020202436042b12401885458b2022002436042004b014b5258b2020802436042591b +b940000080885458b202040243604259b94000008063b80100885458b202080243604259b940 +00010063b80200885458b202100243604259b12601885158b94000020063b80400885458b202 +400243604259b94000040063b80800885458b2028002436042595959595959b1000243545840 +0a0540084009400c020d021bb10102435458b2054008ba010000090100b30c010d011bb18002 +435258b2054008b80180b109401bb2054008ba01800009014059b9400000808855b940000200 +63b8040088555a58b30c000d011bb30c000d0159595942424242422d2c451868234b51582320 +452064b04050587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102 +060cb00a236542b00b234201b001233f00b002233fb10102060cb006236542b0072342b00116 +012d2cb080b0024350b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10 +e52d00010000000219994b024fdc5f0f3cf5001f080000000000c840f99a00000000dd7b2e16 +fba6fd930a6a07d700000008000200010000000000010000073efe4e00430ab4fba6fa7a0a6a +00010000000000000000000000000000001f060000cd047300530239001f02aa008804730057 +01c700890473005304ac00640473005605c7fffd05c7006801c7008a040000570473005702aa +007f04730056023900bb02390000055600a804730088023900b8047300850400003905c700a8 +04730084078d00090473008e02aa000c0239001d047300a806aa0088000000000000004c0000 +00d40000015c000001c0000002e000000374000003f80000046c0000053000000730000007f4 +000008840000094400000a1800000a7800000b1400000b6000000b6000000be400000c980000 +0ce400000d9800000e7c00000efc00000fc800001228000012d80000133c000014100000144c +0000164400010000001f01520054005c000600020010002f005c000002a40204000400014121 +0009013f000101390055013e000101390055014201400014001f01410140001f001f013b0033 +013a00550138003301390055004001070001001f01070001009f010440aa01c0fd01affd0100 +fd010a4ffb0120fb01f550281ff246281ff1462a1ff0462b1f5fef7fef020fef4fef5fef8fef +afef050be5e41e1fe3e2461f0fe20140e246161fe1e0461fcfe0dfe0efe00340e0333646e046 +181feeedff1fed01e855ec48eb55ea320055e9e8e855e7480055e600ff1fdd3ddf55df010355 +de3d0355dc03ff1f0fd51fd5020fd51fd50240ca181b46cfc201bdc03c1fc150261fbcbe281f +ffb90150b870b880b803b8ffc040ffb81232461fb73fb74fb76fb77fb79fb7afb70718b60170 +b2a0b2b0b2030fb20190b501b0b5010fb501080fb33fb3efb30380b090b002b0b0c0b0d0b003 +2faf3faf02a0adb0ad02c0add0ad022fac3fac029fab01c0aad0aa024fa98fa9022fa96fa9bf +a9ffa9049c9b241f509b016f9601bf960196461d1f9594171f0f941f947f948f94ff94053091 +409102809101708f808f02908f01c08fd08f024f8c5f8c6f8c038646ff1f9f85018483311f74 +733f1f7350261f6f6e3c1f6e46351f1a01185519331855073303550603ff1f6050261f5f5026 +1f5c46311f5b5a481f5a46311f1332125505010355043203556c03010c033c034c036c037c03 +05ef51ff4064510240513538464051252846cf50014946201f4846351f4746351faf4601df46 +ef46028046011632155511010f5510320f55020100550100011f1f0f3f0f5f0f7f0f040f0f2f +0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b +4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b58b101018e5985 +8d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101db1160042597374 +7374752b2b2b2b2b017374752b2b2b00742b2b7373752b2b2b012b2b2b002b2b2b2b2b2b012b +2b002b2b012b732b00747374757374732b012b747500732b7374017373740073747473747301 +5e73737473730073732b7373012b002b012b00732b74752b2b2b2b2b2b2b2b2b2b2b012b2b74 +2b2b5e732b002b5e7374012b2b2b002b73735e73737301737373002b2b2b2b2b2b185e0000> +] def +/f-0-0 currentdict end definefont pop +%%EndResource +%%BeginResource: font LiberationSans-Bold +11 dict begin +/FontType 42 def +/FontName /LiberationSans-Bold def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 67 /C put +Encoding 69 /E put +Encoding 70 /F put +Encoding 83 /S put +Encoding 88 /X put +Encoding 97 /a put +Encoding 99 /c put +Encoding 101 /e put +Encoding 108 /l put +Encoding 109 /m put +Encoding 110 /n put +Encoding 115 /s put +Encoding 116 /t put +Encoding 118 /v put +Encoding 121 /y put +/CharStrings 16 dict dup begin +/.notdef 0 def +/E 1 def +/C 2 def +/S 3 def +/a 4 def +/n 5 def +/v 6 def +/s 7 def +/c 8 def +/l 9 def +/F 10 def +/X 11 def +/y 12 def +/t 13 def +/e 14 def +/m 15 def +end readonly def +/sfnts [ +<000100000009008000030010637674206d5f6ba100000d74000002886670676d7e61b6110000 +0ffc000007b4676c7966f6650fc40000009c00000cd8686561640b8df529000017b000000036 +686865610e180383000017e800000024686d74784c4105720000180c000000406c6f63610000 +66900000184c000000446d617870042805340000189000000020707265708aa104b9000018b0 +00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e900000000010089000005060581000b0074404a050909000b00010b060a030700040c0d0508 +5f590f057f059f05030f058f05ff05030f03051615490f0501140505160c490505000101045f +59010300095f590012400d01300d01200d015d5d5d003f2b00183f2b11120039182f2b5f5e5d +2b5f5e5d712b11120117395f5e5d113311333130331121152111211521112115890454fcd302 +f0fd1003560581e4fe9ee4fe8de4000000010054ffec058f05960018005240321609100f0203 +090f03031a190c135f5910100c040002100202000240028002c002d002050b0302020606005f +590613301a015d003f2b110033182f5f5e5d713f332f2b111201173911331133113331302520 +1305060423200011100021320417052e01232206151412031b010b68010153febfe0feacfe8d +01660154f801383ffefc21c183c8cfd5d4010c61ccc70181015a015b0174c7c1476a7df8eff3 +ff000001003bffec05060596002a0052402f0c001d1c2216070606161c00042c2b0c22031919 +205f591d1d1904030a5f5910072007300703300740070207070313003f332f5d712b00183f33 +2f2b111200393911120117391133113311331133313001140421202427251e01332035342e01 +272e0435342421200417052e01232015141e01171e030506fecdfed7fef1fecc2c011d1da895 +01354781b79e7c644627011f01120106010726fee216877efef43970abcbaf66360196cfdbc0 +c32f7065bc3c4e3425252d3d56744bbfcba4bd275b5ca8374631252b496187000002003cffec +0480044e00260033006d403f2427270707150e0f2c03030f1503353406285259060600590e69 +0e022d0e01030f0e1f0e0209040e12120b51591210192f002f4f5924210016bf35014f35015d +71003f32322b110033183f2b1100335f5e5d5f5d5d1239182f2b111201173911331133113311 +33113331300522263534363f0135342623220607253e0133321615111416333237150e032322 +2627230613070e0215141633323e013501899db0dbd0e94a544e4909fedb1bebcbcdde293020 +1e1928282d1e6a650a0676599062522b473b426d3e14ab9ba8b00204376a6747520e9ea3caba +fe765b450698060a06046865d50209020423483c4d4b487f47000001008700000464044f0018 +004f402f00181007070808181a1910141403505914100c0f080015a01a01901a01f01a01b01a +01a01a01901a01701a01ef1a015d71717171717272003f323f3f2b1100331112013939113311 +331133313021111023220615112111342627211e0115333e013332161511034cc1667dfee705 +03010c030a0439ac77acb8025f011daf89fdbc0348576f2c13a51f7c70d4ccfd510000010008 +0000046a043a000a015340ff0302010006090a0a0602030b0c940c01800c01620c720c02540c +01420c01340c01260c01120c01040c01f40c01e60c01d20c0101c00c01a40cb40c02800c900c +02640c740c02400c500c02340c01100c01040c0167f40c01d00ce00c02b40cc40c02a00c0184 +0c940c02600c01440c540c02200c01140c01d40ce40c02cb0c01900ca00c02840c01600c700c +02440c540c02200c300c02140c01f00c01d40ce40c02b00c01640c740c940ca40c04400c0124 +0c340c02000c013702700c800cb00cc00cf00c055f0c01000c100c400c03d00c01af0c01900c +016f0c01500c012f0c3f0c027f0c8f0cbf0cef0cff0c05500c010f0c1f0c3f0c030709020f06 +01b015003f333f33015e5d5d5d7171717171717272725f5e5d5d5d5d5d5d5d71717171717171 +717272727272727272725e5d5d5d5d5d5d5d5d5f5d5d5d717171717171717171111217391133 +11333311333130290101211316173e01132102dbfeb0fe7d0129bd0f380a3ec70126043afda3 +32c829ce0260000000010048ffec041f044f002800724045070621141b1a0d00001a14060429 +2a210d1703171e5159c21b01601b01030f1b1f1b020a041b1b1710030a515914072407020707 +0316502a01b02a01302a01402a012f2a015d5d717172003f332f5d2b00183f332f5f5e5d5f5d +5d2b111200393911120117391133113311331133313001140423222627371e01333236353426 +272e0235343633321617072e01232206151416171e03041ffeffe3dfed27f7156780766c5768 +eea657efdbc1eb1df90c5e6664644d5b7fc57747013c9db38d95254d403c40343d152f51815e +9bad968e1a4241333c2f37121a374c7700010050ffec0437044e00180042402414150a090f03 +030915031a19060d4f590a0a061000146014020d0314140000114f590016003f2b110033182f +5f5e5d3f332f2b1112011739113311331133313005220011100033321617052e012322111033 +323637050e020252f6fef4010ef8bffa20fee50c6058d9dd506c0d011a0f81d2140125010601 +0c012bc0a90e5363fe95fe8a65640d6fae5f00000001008f000001a805cc00030046402d0300 +00050401000015500501400501b00501a005017f05016005011f0501ef0501d00501c00501b0 +05018005015d5d5d5d5d71717171717272003f3f1112013911333130331121118f011905ccfa +34000001008900000498058100090048402a01050506080206030a0b01045f590f01010b0301 +400d31480101050707005f5907030512300b01200b015d5d003f3f2b11120039182f2b5f5e5d +2b11120117391133113331300111211521112111211501b002d1fd2ffed9040f049dfe4ce4fd +fb0581e400010012000005440581000b00294015000b0203080906050305090b040a060d0c05 +030012003f3f111201173911331133113311333130210901210901210901210901040efe9efe +9efec801e8fe410138013901390136fe5401d50231fdcf02e5029cfe0e01f2fd64fd1b000001 +0010fe570468043a001501ba40ff0b0a13090e1112120e030a041617110a0f130e0900055059 +001b96170186170173170163170100501701421701321701241701141701061701f21701e017 +01d01701c21701b41701a4170196170182170174170160170152170142170134170126170112 +170104170167f41701e21701d21701c41701b41701a217019417018417017617016617015417 +01441701321701221701141701061701f61701d41701c61701b01701a2170192170184170176 +1701661701401701321701221701141701061701f61701d41701c21701b2170101a017019017 +0184170160170154170144170130170120170114170104170137f41701cb1701b41701741701 +041701403bf41701e41701cb1701bb1701ab17019417017417013b170124170100170102f017 +01e01701bf1701801701701701501701301701101701001701075e5d5d5d5d5d5d5d5d5d5f71 +71717171717171717172727272725e5d5d5d5d5d5d5d5d5d5d5f5d5d5d5d7171717171717171 +717171717171727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d +5d7171717171715f71717171003f2b00182f33333f3311120117391133113333113331300122 +27351633323e013701211316173f011321010e01011b654c352c3c4f3f27fe540129aa283d19 +41a00126fe5456b9fe570dc808265869042ffe056de15feb01fffb8dd0a0000000010019ffee +029105380015003b401d130c0c0a0d080d040416170d0506054f590a060808060f00114f5900 +16003f2b00183f332f11332b1100331112013911333311333311333130052226351123353337 +3315331523111416333237150601a47c86899758b0cdcd3c3f213d68128789027ebefefebefd +ce4f4b0eae22000000020050ffec042d044e00120019006f4043170a1011160b0b0303110a03 +1b1a160b525916211011480f16010e0516160006061352590610000e51597f10011010011010 +00169f1b016f1b015f1b014f1b012f1b015d5d5d5d5d003f322f5d5d2b00183f2b1112003918 +2f5f5e5d2b2b1112011739113311331133113331300522001110003332121115211416333237 +050201220607212e01024af4fefa010af4e9f6fd4a756c9527010973fea0636b0301a4086e14 +01210115010c0120fecbfed6089ea18117feda03b18a7c838300000100870000069e044f0026 +0093405e172600001f081f1e1007081e08282722031403505910171a0314100c0f1f080015e4 +2801d428018428015428013b2801db2801bb28019b28015428013b28012f2801021f28010028 +01e02801d02801b028019f28018028016028012f28015d5d5d5d5d5d5d71715f717171717171 +7272727272003f32323f3f17332b110033111201393911333311331112391133333130211110 +23220615112111342627211e0115333e01333217333e0133321615112111102322060711030c +a4556bfee70503010c030a04349b6cf83506379a779ea6fee9a4526905025f011dae8afdbc03 +48576f2c13a51f7c70ec7e6ed7c9fd51025f011d9f8cfdaf05cc05cc007d0581001500790581 +00150000000000000000000000000000043a001400770000ffec00000000ffec00000000ffec +0000fe57fff70000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000800000000000119012500f500eb0000000000000000000000c100d300ba00b0 +00cf0000000000000000000000000127012901060000011200e400f400c60000000000000000 +000000000000000000000000000000000119011f014c0000000000df00d100c500b500000000 +000000000000000000000000000000000000010200a901fd00d80119008000b701fd00000000 +013f00db015d012500aa00800075008d01fc0179012100a001100000000001310119010e0104 +000000000000000000000000000000000000013d01ff00e00106009400e00094014400e00573 +0319000000d802c5009c038102cd00cb00f4004e028d000000ff00d700cc01300145007300b4 +00a60000000000730080008d000000000000000000000000030000a200980083008d00000000 +0000000005aefebc0581fd300011fff600b600bc00c60000007f008a00600000000000000000 +00f001ee0190000002190108011500000000000000be00000000000000000748036a02b60202 +fd930000009100670091006101d90000028d0341000000000000000000000000000000aafe6f +fe6801050093009800e20151008f00be00aefeb9fea4005e00af02d5005500f200a604150601 +000003e1001002fa000ffed401eafff300b8000000000363000bfd0ffff50000000000000681 +0477001504d90000ffecffc5fe7f007500cd00f2010200d5011940475b5a5958555453525150 +4f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c2827262524 +2322211f181411100f0e0d0b0a090807060504030201002c20b0016045b00325201146612345 +2361482d2c20451868442d2c45234660b0206120b04660b004262348482d2c4523462361b020 +6020b02661b02061b004262348482d2c45234660b0406120b06660b004262348482d2c452346 +2361b0406020b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd442320b8 +015a51582320b08d44235920b0ed51582320b04d44235920b0042651582320b00d4423592121 +2d2c20204518684420b001602045b04676688a4560442d2c01b10b0a432343650a2d2c00b10a +0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c2045b00325 +456164b050515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b00743 +650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361592d2c8a +03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845441b +2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c01b00525 +1023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243b001525821212121211b +462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b0005058b00161 +b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013515b58b0022546206861 +b00325b003253f2321381b2111592d2c2045b00325465058b0022546206861b00325b003253f +2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b08051580c +6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423648bb81555621bb20080 +2f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004254964234569b0408b61 +b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c4b535820b00325496469 +20b00526b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6 +b00e2344b00eed1b8ab00426111220392320392f2f592d2c4523456023456023456023766818 +b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1302f4523 +456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b0032545695358 +441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c452320458a60 +442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb0164358b0 +0326458a586466b01f601b64b020606620581b21b04059b001615923586559b02923442310b0 +29e01b2121212121592d2cb0024354584b53234b515a58381b2121591b21212121592d2cb016 +4358b004254564b020606620581b21b04059b0016123581b6559b0292344b00525b008250820 +58021b0359b0042510b005252046b0042523423cb00425b0072508b0072510b006252046b004 +25b0016023423c2058011b0059b0042510b00525b029e0b02920456544b0072510b00625b029 +e0b00525b00825082058021b0359b00525b003254348b00425b0072508b00625b00325b00160 +43481b2159212121212121212d2c02b00425202046b004252342b0052508b003254548212121 +212d2c02b0032520b0042508b0022543482121212d2c452320451820b0005020582365235923 +6820b040505821b04059235865598a60442d2c4b53234b515a5820458a60441b2121592d2c4b +545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b5458381b212159 +2d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb002435458 +b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b515a5823 +381b2121592d2c00b0022549b000535820b04038111b21592d2c014623466023466123201020 +468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52587d +1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188535a58b9100000208854 +58b202010243604259b12401885158b920000040885458b2020202436042b12401885458b202 +2002436042004b014b5258b2020802436042591bb940000080885458b202040243604259b940 +00008063b80100885458b202080243604259b94000010063b80200885458b202100243604259 +b12601885158b94000020063b80400885458b202400243604259b94000040063b80800885458 +b2028002436042595959595959b10002435458400a0540084009400c020d021bb10102435458 +b2054008ba010000090100b30c010d011bb18002435258b2054008b80180b109401bb2054008 +ba01800009014059b9400000808855b94000020063b8040088555a58b30c000d011bb30c000d +0159595942424242422d2c451868234b51582320452064b04050587c59688a6059442d2cb000 +16b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201b001233f00b0 +02233fb10102060cb006236542b0072342b00116012d2cb080b0024350b001b00243545b5821 +2310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d00010000000219994f23d1b95f0f3cf5 +001f080000000000c849682600000000dd7b292bfc25fcfd0a6f084400010008000200010000 +000000010000073efe4e00430aaafc25fa7a0a6f000100000000000000000000000000000010 +060000cd0556008905c700540556003b0473003c04e300870473000804730048047300500239 +008f04e30089055600120473001002aa001904730050071d0087000000000000004c000000f0 +000001a00000027c0000038000000420000005a8000006940000073000000790000008040000 +087000000a8000000b0000000bd000000cd800010000001001520054005c000600020010002f +005c0000034d0354000400014155013f000101390055013e000101390055014201400014001f +01410140001f001f013b0033013a0055013800330139005500a4013900f4013900020132003d +0131005501310001012f00550130003d012f0055012c012900ff001f01290001012a00550128 +003d0127005501270001012a00550126003d0125005501250001012a00550123012200ff001f +01220001012a0055012b003d012a0055005001070001002f0107000100af0104405001d0fd01 +bffd0110fd016ffb0140fb0180f590f5a0f503f1f0351f2ff09ff0025fef012fef5fef6fef9f +efdfef05e6e4201fe5e43d1fe2e0271fe1e03d1fdf3ddd55de3d035500dd30dd02dd0103552f +410b011e00010010011e0020011e0040011e0003ffc0011e4028191c46dc03ff1f00db01da04 +3c1fd4d21c1fd3d2261f60d190d1c0d10360d190d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ff +c0b4d10a0d460fb80116400f01bfbe261f40bb29414640bb222746b801214026b63d1f00b801 +6fb801b8b70a1f00b70100b720b740b760b770b70540b760b790b7d0b7f0b705b80120400d48 +3d1f00b560b502a0b5d0b502b8ffc0400eb50b0e460fb25fb202b1033c1f2f410b0119003f01 +19004f01190003008f011900010040011940282629461faf2faf3faf9faf040faf0140af0e16 +4600ad70ad80ad03e0adf0ad02abaa351faa50261fb9011b011ab23c1f00b8011ab6010fa901 +0fa801bc01170113003c001f0115407e503c1f9e9b271f9d9b271f9c9b271f809b019846281f +9f97af97029646351f0f941f94029390261f9291261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f +8d010f8c01408c0b0f460f891f890286850f1f5f850136824682027650261f7550261f745026 +1f7350261f2970011b7001037001f47001d670e67002687001597001b8fff0407d700a0d466f +6e481f6e46321f1a01185519331855073303550603ff1f6150261f605f321f5f50261f5e5a48 +1f5c46271f5b5a781f5a46311f1332125505010355043203556f03010f033f034f036f037f03 +055f53014053282c4640531e224640531318466b527b528b5203514f1c1f504f1c1f194f294f +02594f694f02b80112402d46251f4946191f4846211f4746351ff846019846011c481b551632 +155511010f5510320f55020100550100ff1fb80111b21b091fb80110402d1b091f1f0f3f0f5f +0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b8 +0190b154532b2b4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b +58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101d +b11600425973747374752b2b2b2b2b2b2b2b0173742b2b2b2b0073742b2b732b2b2b7373752b +2b2b012b2b2b002b2b2b2b2b2b2b2b012b2b2b73737373747474002b2b2b2b0173732b73002b +73732b732b2b73012b732b00732b2b2b2b2b7373732b012b2b0073742b73742b73742b73012b +73742b007374752b73742b2b2b012b00732b2b7374012b2b002b732b2b73752b732b2b012b2b +002b2b737401732b0073737373737301737373002b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b +2b1800> +] def +/f-1-0 currentdict end definefont pop +%%EndResource +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 7 7 330 212 +%%EndPageSetup +q 7 7 323 205 rectclip +1 0 0 -1 0 219 cm q +0.980392 0.858824 0.678431 rg +7.5 49.5 321.867 67.5 re f +0 g +0.75 w +0 J +0 j +[] 0.0 d +10 M q 1 0 0 1 0 0 cm +7.5 49.5 321.867 67.5 re S Q +q 1 0 0 1 0 0 cm +7.5 78 m 329.367 78 l S Q +BT +9.75 0 0 -9.75 154.885071 62.625 Tm +/f-0-0 1 Tf +(\253trait\273)Tj +/f-1-0 1 Tf +-1.33374 -1.153846 Td +(ECSCanvas)Tj +/f-0-0 1 Tf +-13.398062 -1.769231 Td +[(+drawCirlce\(coord: Point, radius: Double, color: Color)55(, lineWidth:\ + Double\))]TJ +0 -1.153846 Td +[(+def drawLine\(from: Point, to: Point, color: Color)55(, lineWidth: Dou\ +ble\))]TJ +0 -1.153846 Td +(+clear\(\))Tj +ET +0.988235 0.917647 0.639216 rg +129 151.5 79.375 18 re f +0 g +q 1 0 0 1 0 0 cm +129 151.5 79.375 18 re S Q +BT +9.75 0 0 -9.75 133.734192 166.125 Tm +/f-1-0 1 Tf +(ScalaFXCanvas)Tj +ET +0.988235 0.917647 0.639216 rg +147.75 193.5 41.438 18 re f +0 g +q 1 0 0 1 0 0 cm +147.75 193.5 41.438 18 re S Q +BT +9.75 0 0 -9.75 151.939087 208.125 Tm +/f-1-0 1 Tf +(Canvas)Tj +ET +0.980392 0.858824 0.678431 rg +147.75 7.5 41.438 18 re f +0 g +q 1 0 0 1 0 0 cm +147.75 7.5 41.438 18 re S Q +BT +9.75 0 0 -9.75 152.21521 22.125 Tm +/f-1-0 1 Tf +(System)Tj +ET +q 1 0 0 1 0 0 cm +168 25.5 m 168 49.5 l S Q +q 1 0 0 1 0 0 cm +164.844 41.879 m 168 49.5 l 171.156 41.879 l S Q +q 1 0 0 1 0 0 cm +168 169.5 m 168 193.5 l S Q +q 1 0 0 1 0 0 cm +164.844 185.879 m 168 193.5 l 171.156 185.879 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +168 151.5 m 168 117 l S Q +1 g +174.312 132.242 m 168 117 l 161.688 132.242 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +174.312 132.242 m 168 117 l 161.688 132.242 l 174.312 132.242 l S Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/doc/img/From.eps b/doc/img/From.eps new file mode 100644 index 00000000..6b6758d8 --- /dev/null +++ b/doc/img/From.eps @@ -0,0 +1,1120 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.17.4 (https://cairographics.org) +%%CreationDate: Thu Oct 14 19:49:28 2021 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 7 7 549 232 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%BeginResource: font LiberationSans +11 dict begin +/FontType 42 def +/FontName /LiberationSans def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 32 /space put +Encoding 40 /parenleft put +Encoding 41 /parenright put +Encoding 43 /plus put +Encoding 44 /comma put +Encoding 45 /hyphen put +Encoding 58 /colon put +Encoding 60 /less put +Encoding 62 /greater put +Encoding 65 /A put +Encoding 66 /B put +Encoding 67 /C put +Encoding 69 /E put +Encoding 76 /L put +Encoding 84 /T put +Encoding 85 /U put +Encoding 86 /V put +Encoding 87 /W put +Encoding 91 /bracketleft put +Encoding 93 /bracketright put +Encoding 97 /a put +Encoding 98 /b put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 102 /f put +Encoding 103 /g put +Encoding 105 /i put +Encoding 108 /l put +Encoding 109 /m put +Encoding 110 /n put +Encoding 111 /o put +Encoding 112 /p put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 117 /u put +Encoding 119 /w put +Encoding 120 /x put +Encoding 121 /y put +Encoding 171 /guillemotleft put +Encoding 187 /guillemotright put +/CharStrings 43 dict dup begin +/.notdef 0 def +/guillemotleft 1 def +/t 2 def +/r 3 def +/a 4 def +/i 5 def +/guillemotright 6 def +/plus 7 def +/f 8 def +/o 9 def +/m 10 def +/parenleft 11 def +/e 12 def +/l 13 def +/colon 14 def +/space 15 def +/A 16 def +/parenright 17 def +/B 18 def +/x 19 def +/c 20 def +/u 21 def +/d 22 def +/n 23 def +/g 24 def +/bracketleft 25 def +/L 26 def +/less 27 def +/C 28 def +/s 29 def +/bracketright 30 def +/T 31 def +/p 32 def +/hyphen 33 def +/greater 34 def +/W 35 def +/comma 36 def +/U 37 def +/b 38 def +/E 39 def +/y 40 def +/V 41 def +/w 42 def +end readonly def +/sfnts [ +<000100000009008000030010637674204ada4bfa000020e8000002886670676d7e61b6110000 +2370000007b4676c79667f5acd0b0000009c0000204c686561640b008bb100002b2400000036 +686865610d9403a800002b5c00000024686d7478b0f50fab00002b80000000ac6c6f63610002 +7df800002c2c000000b06d617870039a03e400002cdc0000002070726570fdae474900002cfc +00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e900000000020053008d042003ac0008001100394020050806010f0a0e110a01110804131209 +000300ef5b0c0f032f036f037f030403002f5d332b1100331112011739113311331133113331 +302501350133150901152101350133150901150376feae0152a8feae0154fd83feb00150a7fe +b101518d016d3f01731ffe8cfe911d016d3f01731ffe8cfe911d0001001ffff0022a052c0014 +004540240d14140b0f0f09040416150e05080550590b0f09010c030940080f02125059021680 +16015d003f2b00183f1acd5f5e5d332b11003311120139113333113332113331302506232235 +11233533373315331523111416333237022a595dd87d843578c8c8333f24440818f502d283f2 +f283fd554e3f0e0000000001008800000288044e00130023401006131300000c14150f060a10 +040f0015003f3f3f3333111201393911331133313033113427331615333e0133321715262322 +0615118e06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4fdcc000000020057 +ffec0473044e00230030008e40562029290707150e0f2e03030f151a0432311d1851591d1620 +001107295159070711003f0e010f0e6f0e020b030e0e11110b50591110002450590016c03201 +a03201903201803201703201603201503201303201a032015d7171717171717171003f2b0018 +3f2b110033182f5f5e5d711112392f2b11120039183f2b111201173911331133113311331133 +31300522263534363f0135342623220607271221321615111416333237150623222627230e01 +27323e013d01070e02151416019ea3a4ddf6f37078796e0bbc2e0184ccce2a3b1a214447645b +060645b75a639a59c57f83465f14ac96a8b406043b8472525a110124bbb1fe2e505107701069 +707c67875a9d535904023064515860000000000200890000013d05cc00030007006e40480307 +070004040809050f0415010053590100ff0901e00901df0901c00901b009019f090180090170 +09011f0901000901f00901df0901c00901b00901a009019009014f09011f09015d7171717171 +717172727272727272727272003f2b00183f3f11120139113333113331301335331503113311 +89b4b4b40520acacfae0043afbc600020053008d042003ac000800110039402003080c110401 +0d0a0a1101080413120a000500ef5b0e0f052f056f057f050405002f5d332b11003311120117 +391133113311331133313025233509013533011501233509013533011502cea80152feb0a601 +52fcddaa0152feb0a8014f8d1d016f01741ffe8d3ffe931d016f01741ffe8d3f0001006400b4 +0447049e000b004340260900000603030d0ca90201030f025f02020c060200040504ad5909d6 +070137078707020705b3003f335d5d332b110033335f5e5d5f5d111201391133331133313001 +1123112135211133112115029f93fe5801a89301a80260fe5401ac9201acfe5492000001001d +0000023c05ca0015008f40680d1301060102021504150417160a0f50590a0000030603505913 +060f01151f172f174f175f177f178f179f17070f173f177f17af17bf17df17ef17073b5f17bf +17027f178f179f17030f172f17af17df17ef170517405664481740272c482017301760170340 +17015d712b2b5d71725e5d71003f3f332b110033183f2b111201393211123911333311333231 +300111231123353335343633321715262322061d0133150169b4989882864b342d23453ed303 +b7fc4903b7837a94820c8908465c6183000000020056ffec041d044e000a00160048402c1106 +0b0006001718080e50590810031450590316a018019018018018017018016018015018013018 +01df18015d71717171717171003f2b00183f2b11120139391133113331300110022322021110 +213212033426232206151416333236041dfaeeedf201e5f8eabd859d9e8d8b95a28b021efee4 +feea012101110230feeffee1e0cbcfdcd6d7d00000000001008800000623044e0029017e40ff +182900002109212012080920092b2a1c2550591c10181100151504505915100c0f2109001564 +2b014b2b013f2b012b2b011f2b010f2b01eb2b01df2b01bb2b01ab2b018b2b017b2b016f2b01 +3b2b011f2b010b2b016aeb2b01cb2b01bb2b01af2b018b2b017f2b015b2b014f2b011b2b01fb +2b01ef2b01df2b01cb2b01bb2b01af2b01942b01642b014b2b012b2b011b2b01042b01f42b01 +db2b01ab2b018b2b017f2b016b2b01342b011b2b010f2b0139fb2b01db2b01bb2b01a02b0194 +2b01742b015b2b014b2b012b2b011f2b010b2b01fb2b01eb2b01cb2b01a42b017b2b015b2b01 +4b2b011b2b01f42b01d02b0102c02b01a02b01902b01602b014f2b400b01302b012f2b01002b +01085e5d5d5d5d5d5d5d5d5f5d5d717171717171717172727272727272727272725e5d5d5d5d +5d5d5d5d5d7171717171717171717171717272727272727272725e5d5d5d5d5d5d5d5d5d5d71 +7171717171003f32323f3f2b1112003939183f2b111201393911333311331112391133333130 +21113426232206151123113427331e0217333e0133321617333e013332161511231134262322 +061511030056707386b306aa01020302033a966c7b8f1c03389f71a495b25670768302ae9d78 +b0a0fd8d0353bd2a052c394f735a626b6d60b2cbfd2f02ae9d78afa1fd8d00000001007ffe58 +029e05cc000e0022401007000b0a03040a0400030f100a1b0300003f3f111201173911331133 +113331301310123733060211101217232602117fb5bcaebbafadbdaebdb40214012101cccbd0 +fe2cfeeafeebfe2ed3cc01cd011f00020057ffec0418044e0012001900774046131106071900 +000c0c0711031b1a06060003190050590d190114041919090f0f1650590f10090350590916d0 +1b01c01b01a01b01901b01801b01701b01601b01501b01301b01717171717171717171003f2b +00183f2b11120039182f5f5e5d2b11120039182f111201173911331133113311333130011416 +33323637170221220211101233201115272e012322060701149a94758d199e61fea8f0fbfbe9 +01ddba0f908783990601f7baca5e482dff00011e011a010c011efdc1188aab9daf9900000001 +008a0000013e05cc000300764051030000050401000015f00501e00501df0501c00501b00501 +9f05018005017005011f05010f0501f00501df0501c00501b00501a005019005014f0501ff05 +01e00501d00501c005018005017005011f05015d5d5d5d5d5d5d717171717171717272727272 +7272727272003f3f1112013911333130331133118ab405ccfa340000000200bb0000017e043a +0003000700274013030707040004090804059c5b0401009c5b010f003f2b00182f2b11120139 +391133113331301335331503353315bbc3c3c3036bcfcffc95cfcf0000020004000005520581 +00070010005b40360d01000c02030605080003040408070312110c025f590c0c080503040012 +b01201501201f01201c012019012016012013012012f12015d5d5d5d5d5d7171003f323f3339 +2f2b111201173911333211333312393912393931302103210323013309010706070321032627 +048fa1fd7ea2c6023fd90236fd5b091931b4020fb51c1c019cfe640581fa7f04f11c5382fe31 +01d1455700000001000cfe58022b05cc000e00224010070003040b0a00040a030f100a00031b +003f3f11120117391133113311333130011002072336121110022733161211022bb5bcaebcae +afbbaebdb40210fedffe34cbd201d10117011701d2d1ccfe33fee1000000000300a8000004ea +0581000d0016001e0068403a0b1308131b1b040e081700000804031f200b131a131a5f591324 +13024d0f1301033e1301040f130110051313040505125f590503041b5f590412003f2b00183f +2b11120039182f5f5e5d5f5d5f712b2b11120039111201173911331133113311331112393130 +0114042321112120111406071e01013426232111213236133429011121323604eafeeef4fdc4 +020001f08c80a8b6feee9c94febf0141999751fea2fe9c0173afa0018dbcd10581feaa7daa1d +14b901fa7262fe4273fdfff9fe048200000000010017000003ea043a000b015440a0000b0809 +0a04010706050203030507090b050d0c840d01760d01440d540d640d03360d01240d01160d01 +040d01f60d01e40d01d60d01c40d01b60d01a40d01760d860d960d03640d01060d160d260d46 +0d560d0567060d460d560d860d960dc60dd60de60d08990dd90d02640d01560d01440d01360d +01240d01160d01040d01d60de60df60d03c40d01060d260d360d460d0437660da60db60de60d +f60d050db8ffc040363d4248390d01220d0101000d100d02f40d01c00dd00de00d03b40d0180 +0d900da00d03740d01600d01540d01400d01340d01200d010db8ffc04022121848a00d010200 +0d100d500d700d800d900d06070a04010407030208060f000215003f333f331217391133015e +5d5f5d2b71717171717171717171725f72722b725e5d5d5d7171717171717171725e5d5d5d5d +5d5d5d5d5d717171717171711112173911331133113333331133113331302109012309013309 +013309010321feddfedbc20181fe91c7010e010cc9fe91018601bcfe44022c020efe5b01a5fd +f4fdd20000010057ffec03ca044e001900664045000d1413060707130d031a1b101750591f14 +7f148f14df140414141010200670068006d006e0060500061006600670068006c006d0060709 +0306060a0a0350590a161f1b015d003f2b110033182f5f5e5d713f332f5d2b11120117391133 +11331133313001141633323637170e0123220211101233321617072e01232206011388896081 +0fb615e0ace3eff0e0a6db1cb90e72698f800222d8d0686c0c9cba011f01130111011fac970e +5a6abe00000000010085ffec03eb043a001a005f403b1208080b01190b191c1b120516055059 +16160d1509000fd01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a0 +1c01701c015d5d5d5d5d5d5d7171727272003f323f3f2b110033111201393911331133113331 +300111141e01333236351133111417232e0227230e012322263511013a2a5c598296b406aa01 +020302033ea379b2a5043afd526b7634b29e0273fcadbd2a052c394f705db1cc02d100020056 +ffec03ef05cc00160022005640311d000e0e0f17060f06242312150e00000b03080820505908 +10031a505903169024017024011f2401ff2401e02401c024015d5d5d717171003f2b00183f2b +1112003939183f3f1112013939113311331133333130250e0123220211102132161733271133 +111417232e0135011416333236353426232206033532a57acdc1018e7ba4320202b406ac0307 +fdda7887998a8a978879ae685a0114011802365a627901c1fb13a93610742a0170e3c4d4dfd7 +c8c900010088000003ee044e001a0061403c1209090a001a0a1a1b1c1216001605505916100d +0f0a0015d01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a01c0170 +1c015d5d5d5d5d5d5d7171727272003f323f3f2b111200391112013939113311331133313021 +11342e01232206151123113427331e0217333e01333216151103392a5c598296b406aa010203 +02033ea379b2a502ae6b7634b29efd8d0353bd2a052c394f705db1ccfd2f00020056fe5703ef +044b0020002e009f4064211709091f0403281111031f03302f1c0f170a140e1425505914100e +2b50590e16000750591504010604010b04001b403001203001cf3001b0300190300120300100 +300150df3001c030014f3001a030018030012f30010f3001f03001d030010f3001085e5d5d5d +717171717272725e5d5d5d5d5d7171003f325e5d5d2b00183f2b00183f2b1112003939183f11 +12011739113311331133113333313001222627371e0133201135230e01232202111012333216 +1733343637330615111003342e0123220615141633323e010224b1d21eb5127b64010d0233b2 +77c7bbc9cd73a92e020804ab06b34883538a7e768f558448fe578b801a4b51013bae68690108 +011b011f011169611e940736aafcc5fe3803c684bf65c8e0dec264bb000000010092fe570229 +05cc00070026401405000603000308090104f55901000005f559001b003f2b00183f2b111201 +1739113331301311211523113315920197e9e9fe57077581f98d81000000000100a80000042f +05810005001f400e030000040607010300035f590012003f2b00183f11120139391133313033 +1133112115a8bf02c80581fb1b9c00010065009a044804aa0006003c40270306040004070805 +3f067f068f06030603300270028002030201000f043f046f049f04cf04050400192f5d3333cd +5d32cd5d3211120117393130133501150901156503e3fca6035a023bcd01a29afe92fe919900 +00010068ffec057905960019005e4039031017160809091610031a1b0f17010d031717131300 +5f59130400081008400850089008a008d008e008080c0308080c0c065f590c13201b015d003f +2b110033182f5f5e5d3f2b110033182f5f5e5d11120117391133113311333130012200111000 +3320131706042322240235100021320417072e010318eafefc010fe70128959c57fec5d0d5fe +c9a3016c0142e1012e47b531d904fafed3fefafefdfec501254eb6beb10149e10151017eb0ad +3c7b8200000000010039ffec03b6044b002a0064403c070622151c1b0d00001b1506042b2c0d +220318181f50591c1810030a5059070316102c01002c01f02c01e02c01c02c01602c01802c01 +3f2c01102c015d5d5d717171717272003f332b00183f332b1112003939111201173911331133 +11331133313001140623222627371e013332363534262f012e0235343633321617072e012322 +0615141e01171e0303b6e7d0cadb219f179080897f5862819b834ad3cab3d31ca20f836e7a74 +305e978f7e4928012b99a6858d1f5751545440501a22284d6e50949b7e8b14484d4a4b2e3c2a +25243d4a610000010010fe5701a705cc00070026401402070401070309080504f55905000001 +f559001b003f2b00183f2b111201173911333130133533112335211110e9e90197fe57810673 +81f88b0000000001002e000004b405810007013040d90102040207030908000405045f590503 +01127b09014b09013b0901240901fb0901cb0901bb09019b09018b09017f0901025f09014f09 +013009010f090167df0901cf0901b009018f09015f09014f09010f0901f00901df0901cf0901 +af09019f09017009015f09014009011f0901ef0901df09019f09016f09015f09013f09011f09 +0100090137ef0901d009019009018009016f09015009012f0901000901d00901af0901900901 +7f09016f0901500901400901200901100901ff0901e00901bf0901a009019009016009014009 +013f09012009010f0901075e5d5d5d5d5d5d5d5d5d5d71717171717171717172727272727272 +725e5d5d5d5d5d5d5d5d717171717171717171727272727272725e5d5d5d5d5f5d5d5d5d5d5d +71717171003f3f2b110033111201173911333130011123112135211502d0befe1c048604e5fb +1b04e59c9c00000000020084fe57041d044d00170024005d403718001f110808090009262511 +041502151b505915100c0f081b022250590216b026013f26019026017026011f2601ff2601e0 +2601c026015d5d5d7171717272003f2b00183f3f3f2b11120039391112013939113311333311 +33313001102122272316151123113427331e0215333e0133321203342623220e011514163332 +36041dfe72fa560504b406ae01040504309e81c8c6bd7a856b793f8899867b0222fdcabc08a2 +fe590506a73604316613645dfef4fedde2c25abf99d5cac500000001005b01d0024f02700003 +001f4011000304050100bb599f01cf01022f010101002f5d712b11120139393130133521155b +01f401d0a0a000010065009a044804aa0006003c402706020003040708033004700480040304 +013f007f008f00030006050f023f026f029f02cf02050200192f5d3333cd5d32cd5d32111201 +173931303735090135011565035afca603e39a99016f016e9afe5ecd00000001000900000786 +0581001901fc40ff1819080101010014071101081001111004080707010b03070d0a09090d04 +1419051b1a8b1b011bc07c7f48391b012a1b01191b010a1b01f91b01ea1b01d91b01ca1b01b8 +1b01891b991ba91b03781b01691b013a1b4a1b5a1b03291b011a1b010c1b0168fd1b01ec1b01 +dd1b01cc1b01bd1b01ab1b019c1b018b1b017c1b016b1b015c1b014b1b013c1b012b1b011c1b +010b1b01fc1b01eb1b01dc1b01cb1b01bc1b01ab1b019c1b01008d1b017f1b016d1b015f1b01 +4d1b012f1b3f1b021d1b010f1b01fd1b01ef1b01dd1b01cf1b01bd1b01af1b019d1b018f1b01 +6d1b7d1b025b1b014d1b013b1b012d1b011b1b010d1b0138fb1b01ed1b01db1b01cd1b406f01 +bb1b01ad1b019b1b018d1b017b1b016d1b014b1b5b1b02391b012b1b01191b010b1b01f91b01 +eb1b01dd1b01cb1b01bd1b01ab1b019d1b018b1b017d1b016b1b015d1b014b1b013d1b01012b +1b011f1b01025f1b7f1b9f1bbf1bdf1bff1b06001b01081810040903140d0d010812003f3333 +11333f333333015e5d5d5f71715f717171717171717171717171717272727272727272727272 +727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d71717171717171715f717171717171717272 +72727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d717171712b711112173911 +3311335f5e5d331133335d5d1133335d1133313021230326270e010323013313161736121333 +131617373e01013305e7e4f4182e1a24ffe4fe61c7fd2d26183ff6b7f53820091b220108c703 +7f54d9749cfc640581fc81a8b26e01040367fc93d79523739103b2000000000100b8fefa0181 +00db0009002240110405000805080a0b0005a85b08009b5b08002f2b2b111201393911331133 +313025151406072336352335018126287b5e58dba86a8e41887edb0000000001009effec0529 +058100130049402c0d100704100415140e0503000a5f590013201501c01501b01501a0150180 +15017015016015015015012015015d5d5d5d5d5d5d5d71003f2b00183f331112013939113311 +333130052224263511331114163332363511331114060402dbadfefe8ebfc4b9bed3be91fef7 +147ef0a60381fc8fc1c8cfc70364fc91abf88300000000020084ffec041d05cc00170023005d +40371e050e0e0d18000d00242505110215151b505915100d000a15022150590216b025013f25 +019025017025011f2501ff2501e02501c025015d5d5d7171717272003f2b00183f3f3f2b1112 +0039391112013939113311331133333130011021222627231406072336351133111407333e01 +333212033426232206151416333236041dfe727ba333020802ae06b4040432a57acdc1bd7887 +988b889988790222fdca59631f7f0a36a904edfe594158685afeecfee2e3c4d0e2d5cbc90001 +00a8000004fe0581000b00544032050909000a030700040c0d05085f598f0501ba0501790589 +05020f050108030505000101045f59010300095f590012200d015d003f2b00183f2b11120039 +182f5f5e5d5d5d712b1112011739113311333130331121152111211521112115a8042dfc9203 +32fcce039705819cfe3c9afe159c000000010005fe5703fc043a001601e440ff13080f11120a +0909030f1204181708130f131711090f00055059001b92180182180174180164180152180142 +1801341801241801121801021801f41801e41801d21801c21801b41801a41801921801821801 +74180164180156180142180134180124180116180102180167f41801e41801d61801c21801b4 +1801a41801961801821801741801641801561801421801341801241801161801021801f41801 +e41801d61801c2180101b01801a0180194180184180170180160180154180144180130180120 +1801141801041801f01801e01801d41801c41801b01801a01801941801841801701801601801 +54180144180130180120180114180104180137e018405a01d41801c41801a018019418018418 +01601801541801441801201801141801041801e01801d41801c41801a0180194180184180160 +180102501801301801201801001801c018019018018018015018012f1801101801001801075e +5d5d5d5d5d5d5d717171715f717171717171717272727272727272727272725e5d5d5d5d5d5d +5d5d5d5d5d5d5d5d5d5d7171717171717171717171715f717171717272727272727272727272 +72727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d71717171717171717171003f2b00183f +3311333311331112011739113311331133333130132227351633323f010133131e0217371333 +010e02bf4a32262ea86211fe53c0e4050e4c0346edbefe6043748dfe570b8706f72b0435fdaa +0e27de0dc502b1fbc6ada9530000000100090000054d05810008003e40260708010005030202 +0508030a09200a500a02300a600a900ac00af00a052f0a01070203050112003f333f33015d5d +7111121739113311333311333130212301330117370133030ec6fdc1c9018654540184c90581 +fc20f9f903e000000001fffd000005cc043a001401ae40ff01001107060c0f0e0313090c0311 +03140807140114160808010b0815030e1303080f010c11030715761601661601541601461601 +361601241601161601041601f41601e61601c41601b21601a416019616018616016616015416 +0144160136160114160106160169f61601e21601d41601c61601b61601961601841601741601 +661601461601361601241601161601061601f41601e61601b61601a416019416018616016916 +01561601441601361601061601e41601d61601c41601b61601a6160189160172160101601601 +54160124160104160138f41601d41601c41601a416018016017416014b160130160124160114 +1601fb1601c41601a0160194164030017b16016416014416013416011b1601f01601e41601cb +1601b416019416018416016416013f160102101601001601085e5d5d5f5d5d5d5d5d5d5d5d71 +7171717171717171727272727272727272725e5d5d5d5d5f5d5d5d5d5d5d5d71717171717171 +7171717172727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d717171717171 +7171003f17333f17331101335e5d11335d111217393332113333113333113333313021230327 +0e010323013313161737133313173713330496d1bd240926b9d0fed1b2b7072411e2c1bd2e1f +cdb002fda92da9fd30043afd2118ae4a035bfd19be8b031a000005cc05cc007d058100150079 +058100150000000000000000000000000000043a001400770000ffec00000000ffec00000000 +ffec0000fe570000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000008000000000000b400bd00af00a00000000000000000000000000088007e +000000ac00000000000000000000000000bf00c300ab00000000009b008d0000000000000000 +00000000000000000000000000000000000000b900aa00000000000000940099008700000000 +0000000000000000000000000000000000000000006a0083008d00a400b40000000000000000 +00000060006a0079009800ac00b800a700000122013300c3006b00000000000000db00c90000 +000000000000000000000000000000000000000001e101c9009200a8006b009200b7006b009b +0000027b02f200920252006e02d703810082008900a0009f0169008f0000016000a4015b005e +0082000000000000005e0065006f0000000000000000000000000000008a009000a5007a0080 +000000000000000000000581fff3000dfcb300830089008f00960069007105cc000ffc1efff2 +003404e6000dfed400bf031f00a700ae00b500000000008100000000000000000748036a02b6 +0202fd930000009100670091006101d90000028d034100000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +06810468001404cb0000ffecffd3fe7f008300db00aa00ba00a000cf40475b5a595855545352 +51504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c282726 +25242322211f181411100f0e0d0b0a090807060504030201002c20b0016045b0032520114661 +23452361482d2c20451868442d2c45234660b0206120b04660b004262348482d2c4523462361 +b0206020b02661b02061b004262348482d2c45234660b0406120b06660b004262348482d2c45 +23462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd4423 +20b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651582320b00d442359 +21212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a432343650a2d2c00 +b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c2045b0 +0325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b0 +0743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361592d +2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845 +441b2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c01b0 +05251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243b001525821212121 +211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b0005058b0 +0161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013515b58b002254620 +6861b00325b003253f2321381b2111592d2c2045b00325465058b0022546206861b00325b003 +253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b08051 +580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423648bb81555621bb2 +00802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004254964234569b040 +8b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c4b535820b0032549 +646920b00526b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b00e2344b0 +0ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c452345602345602345602376 +6818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1302f +4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b003254569 +5358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c45232045 +8a60442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb01643 +58b00326458a586466b01f601b64b020606620581b21b04059b001615923586559b029234423 +10b029e01b2121212121592d2cb0024354584b53234b515a58381b2121591b21212121592d2c +b0164358b004254564b020606620581b21b04059b0016123581b6559b0292344b00525b00825 +082058021b0359b0042510b005252046b0042523423cb00425b0072508b0072510b006252046 +b00425b0016023423c2058011b0059b0042510b00525b029e0b02920456544b0072510b00625 +b029e0b00525b00825082058021b0359b00525b003254348b00425b0072508b00625b00325b0 +016043481b2159212121212121212d2c02b00425202046b004252342b0052508b00325454821 +2121212d2c02b0032520b0042508b0022543482121212d2c452320451820b000502058236523 +59236820b040505821b04059235865598a60442d2c4b53234b515a5820458a60441b2121592d +2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b5458381b21 +21592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb00243 +5458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b515a +5823381b2121592d2c00b0022549b000535820b04038111b21592d2c01462346602346612320 +1020468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52 +587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188535a58b910000020 +885458b202010243604259b12401885158b920000040885458b2020202436042b12401885458 +b2022002436042004b014b5258b2020802436042591bb940000080885458b202040243604259 +b94000008063b80100885458b202080243604259b94000010063b80200885458b20210024360 +4259b12601885158b94000020063b80400885458b202400243604259b94000040063b8080088 +5458b2028002436042595959595959b10002435458400a0540084009400c020d021bb1010243 +5458b2054008ba010000090100b30c010d011bb18002435258b2054008b80180b109401bb205 +4008ba01800009014059b9400000808855b94000020063b8040088555a58b30c000d011bb30c +000d0159595942424242422d2c451868234b51582320452064b04050587c59688a6059442d2c +b00016b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201b001233f +00b002233fb10102060cb006236542b0072342b00116012d2cb080b0024350b001b00243545b +58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d0001000000021999d5f9f2a25f0f +3cf5001f080000000000c840f99a00000000dd7b2e16fba6fd930a6a07d70000000800020001 +0000000000010000073efe4e00430ab4fba6fa7a0a6a00010000000000000000000000000000 +002b060000cd047300530239001f02aa00880473005701c700890473005304ac00640239001d +0473005606aa008802aa007f0473005701c7008a023900bb023900000556000402aa000c0556 +00a804000017040000570473008504730056047300880473005602390092047300a804ac0065 +05c70068040000390239001004e3002e0473008402aa005b04ac0065078d0009023900b805c7 +009e04730084055600a8040000050556000905c7fffd000000000000004c000000d40000015c +000001c0000002e000000374000003f80000046c00000540000005dc000007d4000008340000 +090800000998000009e4000009e400000a8c00000af000000bc800000d5c00000e1c00000ed0 +00000f940000104800001178000011c40000120000001264000013280000140c000014580000 +15b000001680000016b80000171c0000197c000019c800001a5800001b2400001ba800001de0 +00001e4c0000204c00010000002b01520054005c000600020010002f005c000002a402040004 +000141210009013f000101390055013e000101390055014201400014001f01410140001f001f +013b0033013a00550138003301390055004001070001001f01070001009f010440aa01c0fd01 +affd0100fd010a4ffb0120fb01f550281ff246281ff1462a1ff0462b1f5fef7fef020fef4fef +5fef8fefafef050be5e41e1fe3e2461f0fe20140e246161fe1e0461fcfe0dfe0efe00340e033 +3646e046181feeedff1fed01e855ec48eb55ea320055e9e8e855e7480055e600ff1fdd3ddf55 +df010355de3d0355dc03ff1f0fd51fd5020fd51fd50240ca181b46cfc201bdc03c1fc150261f +bcbe281fffb90150b870b880b803b8ffc040ffb81232461fb73fb74fb76fb77fb79fb7afb707 +18b60170b2a0b2b0b2030fb20190b501b0b5010fb501080fb33fb3efb30380b090b002b0b0c0 +b0d0b0032faf3faf02a0adb0ad02c0add0ad022fac3fac029fab01c0aad0aa024fa98fa9022f +a96fa9bfa9ffa9049c9b241f509b016f9601bf960196461d1f9594171f0f941f947f948f94ff +94053091409102809101708f808f02908f01c08fd08f024f8c5f8c6f8c038646ff1f9f850184 +83311f74733f1f7350261f6f6e3c1f6e46351f1a01185519331855073303550603ff1f605026 +1f5f50261f5c46311f5b5a481f5a46311f1332125505010355043203556c03010c033c034c03 +6c037c0305ef51ff4064510240513538464051252846cf50014946201f4846351f4746351faf +4601df46ef46028046011632155511010f5510320f55020100550100011f1f0f3f0f5f0f7f0f +040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b1 +54532b2b4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b58b101 +018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101db11600 +425973747374752b2b2b2b2b017374752b2b2b00742b2b7373752b2b2b012b2b2b002b2b2b2b +2b2b012b2b002b2b012b732b00747374757374732b012b747500732b73740173737400737474 +737473015e73737473730073732b7373012b002b012b00732b74752b2b2b2b2b2b2b2b2b2b2b +012b2b742b2b5e732b002b5e7374012b2b2b002b73735e73737301737373002b2b2b2b2b2b18 +5e0000> +] def +/f-0-0 currentdict end definefont pop +%%EndResource +%%BeginResource: font LiberationSans-Bold +11 dict begin +/FontType 42 def +/FontName /LiberationSans-Bold def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 65 /A put +Encoding 67 /C put +Encoding 69 /E put +Encoding 70 /F put +Encoding 83 /S put +Encoding 84 /T put +Encoding 86 /V put +Encoding 87 /W put +Encoding 97 /a put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 103 /g put +Encoding 105 /i put +Encoding 108 /l put +Encoding 109 /m put +Encoding 110 /n put +Encoding 111 /o put +Encoding 112 /p put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 117 /u put +Encoding 119 /w put +Encoding 120 /x put +Encoding 121 /y put +/CharStrings 27 dict dup begin +/.notdef 0 def +/F 1 def +/r 2 def +/o 3 def +/m 4 def +/E 5 def +/n 6 def +/t 7 def +/i 8 def +/e 9 def +/s 10 def +/W 11 def +/l 12 def +/d 13 def +/V 14 def +/w 15 def +/S 16 def +/y 17 def +/C 18 def +/a 19 def +/A 20 def +/p 21 def +/T 22 def +/x 23 def +/c 24 def +/u 25 def +/g 26 def +end readonly def +/sfnts [ +<000100000009008000030010637674206d5f6ba100001854000002886670676d7e61b6110000 +1adc000007b4676c7966a14ac29a0000009c000017b8686561640b8df5290000229000000036 +686865610e18038e000022c800000024686d7478827708ce000022ec0000006c6c6f63610001 +283400002358000000706d61787004330534000023c800000020707265708aa104b9000023e8 +00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e90000000001008900000498058100090048402a01050506080206030a0b01045f590f01010b +0301400d31480101050707005f5907030512300b01200b015d5d003f3f2b11120039182f2b5f +5e5d2b11120117391133113331300111211521112111211501b002d1fd2ffed9040f049dfe4c +e4fdfb0581e400010087000002fe044f0016003e402508161600000f18170d125059080d1005 +0f00159f18017f1801d01801af18015f18012f18015d5d5d5d7171003f3f3f332b1112013939 +1133113331303311342627211e0115333e02333217152623220615118f0503010c030a042940 +5842362144346975033c59772e12b71e725d2d0feb0faaa7fded000000020050ffec0493044e +000b00150030401a11060c0006001716090f4f59091003144f5903167017016017017171003f +2b00183f2b111201393911331133313001100021220011100021200001342623201114163320 +0493fedcfefefdfee00120010301090117feda7e78ff007d760103021efef9fed5012c010601 +05012bfedffef1c1aefe91b5bd000000000100870000069e044f00260093405e172600001f08 +1f1e1007081e08282722031403505910171a0314100c0f1f080015e42801d428018428015428 +013b2801db2801bb28019b28015428013b28012f2801021f2801002801e02801d02801b02801 +9f28018028016028012f28015d5d5d5d5d5d5d71715f7171717171717272727272003f32323f +3f17332b11003311120139391133331133111239113333313021111023220615112111342627 +211e0115333e01333217333e0133321615112111102322060711030ca4556bfee70503010c03 +0a04349b6cf83506379a779ea6fee9a4526905025f011dae8afdbc0348576f2c13a51f7c70ec +7e6ed7c9fd51025f011d9f8cfdaf00010089000005060581000b0074404a050909000b00010b +060a030700040c0d05085f590f057f059f05030f058f05ff05030f03051615490f0501140505 +160c490505000101045f59010300095f590012400d01300d01200d015d5d5d003f2b00183f2b +11120039182f2b5f5e5d2b5f5e5d712b11120117395f5e5d1133113331303311211521112115 +21112115890454fcd302f0fd1003560581e4fe9ee4fe8de400000001008700000464044f0018 +004f402f00181007070808181a1910141403505914100c0f080015a01a01901a01f01a01b01a +01a01a01901a01701a01ef1a015d71717171717272003f323f3f2b1100331112013939113311 +331133313021111023220615112111342627211e0115333e013332161511034cc1667dfee705 +03010c030a0439ac77acb8025f011daf89fdbc0348576f2c13a51f7c70d4ccfd510000010019 +ffee029105380015003b401d130c0c0a0d080d040416170d0506054f590a060808060f00114f +590016003f2b00183f332f11332b110033111201391133331133331133313005222635112335 +33373315331523111416333237150601a47c86899758b0cdcd3c3f213d68128789027ebefefe +befdce4f4b0eae2200000002008f000001a805cc00030007005640360307070004040809050f +0415010053590100500901400901b00901a009017f09016009011f0901ef0901d00901c00901 +b009018009015d5d5d5d5d71717171717272003f2b00183f3f11120139113333113331301335 +2115011121118f0119fee7011904fdcfcffb03043afbc60000020050ffec042d044e00120019 +006f4043170a1011160b0b0303110a031b1a160b525916211011480f16010e05161600060613 +52590610000e51597f1001101001101000169f1b016f1b015f1b014f1b012f1b015d5d5d5d5d +003f322f5d5d2b00183f2b11120039182f5f5e5d2b2b11120117391133113311331133313005 +22001110003332121115211416333237050201220607212e01024af4fefa010af4e9f6fd4a75 +6c9527010973fea0636b0301a4086e1401210115010c0120fecbfed6089ea18117feda03b18a +7c83830000010048ffec041f044f002800724045070621141b1a0d00001a140604292a210d17 +03171e5159c21b01601b01030f1b1f1b020a041b1b1710030a5159140724070207070316502a +01b02a01302a01402a012f2a015d5d717172003f332f5d2b00183f332f5f5e5d5f5d5d2b1112 +00393911120117391133113311331133313001140423222627371e01333236353426272e0235 +343633321617072e01232206151416171e03041ffeffe3dfed27f7156780766c5768eea657ef +dbc1eb1df90c5e6664644d5b7fc57747013c9db38d95254d403c40343d152f51815e9bad968e +1a4241333c2f37121a374c77000100020000078b05810017014040e51617010013100f040807 +0c0a09090c0413170519186b19015f19013419011b1901f41901db1901cf1901b419018b1901 +0419241944196419046afb1901d41901bb19019019018419016b19015019014419012b190104 +1901eb1901c419018b19ab1902141934195419741904fb1901d41901bb1901af19019419017b +19016f19015019014419012b190104190139b419d419f419039b19017419014b195b19023019 +012419010b1901f0190102e01901cf1901a019014f196f198f1903101901f01901df1901b019 +019f19017019010f194f195f190308160f040903130c250c010c080012003f32325d11333f33 +3333015e5d5d5d5d5d5d71717171715f71727272727272725e5d5d5d5d5d5d5d5d5d5d5d7171 +7171727272727272727272725e5d5d5d5d5d5d71717171111217391133113333113333113333 +1133313029010326270e010321012113173e0113211316133f011321061ffea2bf2318181ec6 +fea2fe95012bcc2e1c35ad014ab215321935aa012b032f909d8389fcb00581fc72dc8bfd02e2 +fd1254fed874e60310000001008f000001a805cc00030046402d030000050401000015500501 +400501b00501a005017f05016005011f0501ef0501d00501c00501b005018005015d5d5d5d5d +71717171717272003f3f1112013911333130331121118f011905ccfa340000020054ffec045c +05cc00160021003e402017031212131d091309222312000c1a4f590f0c10061f4f5903061600 +1570230171003f3f332b00183f332b00183f1112013939113311331133333130212e01352306 +23220211101233321617332711211114170134262322061510333236034c040b045bffbdced9 +c773a72d0202011908fee37572716edd6f7a0f7928c401270109010d0125605fb2018bfb2064 +880223afbdb7bcfe90c300000001000e000005480581000a0038401f090a010006030202060a +030c0bc00c019f0c01600c012f0c01090203060112003f333f33015d5d5d5d11121739113311 +333311333130290101210116173f0101210342fed5fdf7013401221b2f1533012101310581fc +7758b256b403890000000001fffa0000063d043a001401ba40ff0100110e0d0407060a0a0411 +030813141416090808158f16017916016b16015d16014f16013b16012d16011b16010d1601f9 +1601eb1601dd1601cf1601a916b916029b16018d16017f16016b16015d16014b16013d16011b +162b16020d160168ff1601d916e91602cb1601bd1601ab16019d16018916017b16016d16014b +165b16023d16012b16011916010b1601fb1601ed1601db1601cd1601b91601ab16019916018b +16016d167d16025b16014916012b163b16021d1601010f1601bb16db16eb1603af16016b168b +16024f165f16023416010b161b160238eb1601df1601cb1601b416019b16017f168f16026416 +014b16013f16011b1601fb1601e416403f01cb1601bf16019416a416027b16016f16012b164b +1602fb1601ef160102c016d016028f16af160270160116400a0d4800160108130d04080f110a +0a070015003f323211333f333333015e5d2b5d5d5d5f5d5d7171717171717171727272727272 +727272725e5d5d5d5d5d5d715f71717171717171717171717171727272727272727272727272 +72725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d717171717171717171113311331133113312173911 +3333113333113333313029010326270703210121133f0113211316173713210521fed7ac0c23 +34aefed7fee80108b20e19aa012da60e1b1c9c010402942db1e0fd6e043afcc54a75027cfd84 +348b8402b7000001003bffec05060596002a0052402f0c001d1c2216070606161c00042c2b0c +22031919205f591d1d1904030a5f5910072007300703300740070207070313003f332f5d712b +00183f332f2b111200393911120117391133113311331133313001140421202427251e013320 +35342e01272e0435342421200417052e01232015141e01171e030506fecdfed7fef1fecc2c01 +1d1da89501354781b79e7c644627011f01120106010726fee216877efef43970abcbaf663601 +96cfdbc0c32f7065bc3c4e3425252d3d56744bbfcba4bd275b5ca8374631252b496187000001 +0010fe570468043a001501ba40ff0b0a13090e1112120e030a041617110a0f130e0900055059 +001b96170186170173170163170100501701421701321701241701141701061701f21701e017 +01d01701c21701b41701a4170196170182170174170160170152170142170134170126170112 +170104170167f41701e21701d21701c41701b41701a217019417018417017617016617015417 +01441701321701221701141701061701f61701d41701c61701b01701a2170192170184170176 +1701661701401701321701221701141701061701f61701d41701c21701b2170101a017019017 +0184170160170154170144170130170120170114170104170137f41701cb1701b41701741701 +041701403bf41701e41701cb1701bb1701ab17019417017417013b170124170100170102f017 +01e01701bf1701801701701701501701301701101701001701075e5d5d5d5d5d5d5d5d5d5f71 +71717171717171717172727272725e5d5d5d5d5d5d5d5d5d5d5f5d5d5d5d7171717171717171 +717171717171727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d +5d7171717171715f71717171003f2b00182f33333f3311120117391133113333113331300122 +27351633323e013701211316173f011321010e01011b654c352c3c4f3f27fe540129aa283d19 +41a00126fe5456b9fe570dc808265869042ffe056de15feb01fffb8dd0a0000000010054ffec +058f05960018005240321609100f0203090f03031a190c135f5910100c040002100202000240 +028002c002d002050b0302020606005f590613301a015d003f2b110033182f5f5e5d713f332f +2b1112011739113311331133313025201305060423200011100021320417052e012322061514 +12031b010b68010153febfe0feacfe8d01660154f801383ffefc21c183c8cfd5d4010c61ccc7 +0181015a015b0174c7c1476a7df8eff3ff000002003cffec0480044e00260033006d403f2427 +270707150e0f2c03030f1503353406285259060600590e690e022d0e01030f0e1f0e0209040e +12120b51591210192f002f4f5924210016bf35014f35015d71003f32322b110033183f2b1100 +335f5e5d5f5d5d1239182f2b11120117391133113311331133113331300522263534363f0135 +342623220607253e0133321615111416333237150e0323222627230613070e0215141633323e +013501899db0dbd0e94a544e4909fedb1bebcbcdde2930201e1928282d1e6a650a0676599062 +522b473b426d3e14ab9ba8b00204376a6747520e9ea3cabafe765b450698060a06046865d502 +09020423483c4d4b487f4700000200330000059105810007000f020740ff0d01000c02080300 +070304060508040807031011070c025f590d08050c0c06050304001286110174110164110153 +1101431101341101251101161101021101f31101e41101d41101c51101b61101a31101931101 +84110175110166110154110145110134110124110115110104110168f51101e51101d41101c5 +1101b3110100a011019211018411017411016211015011014211013211012411011611010211 +01f01101e21101d41101c41101b21101a4110190110182110174110162110152110144110136 +1101241101101101021101f41101e41101d61101c41101b21101a21101941101861101761101 +64110152110144110134110126110114110106406f110138f21101e41101d61101c21101b411 +01a6110184110176110164110154110146110126110112110101001101f41101c41101b01101 +a01101941101741101641101501101441101341101141101e41101c41101b411019411018411 +0170110164110144110110110102001101085e5d5f5d5d5d5d5d5d5d5d5d7171717171717171 +717171725f727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d717171 +7171717171717171717171717172727272727272727272725f72727272725e5d5d5d5d5d5d5d +5d5d5d5d5d5d5d5d5d717171717171717171003f323f33392f1239332b00182f111201173911 +333311331133111239391139393130210321032101210901070e0103210327046d7dfde77dfe +d90202015c0200fd52060a1c9e01958b2b0168fe980581fa7f04a816245cfe34019588000000 +00020087fe57048f045100170021003c40201800121d09090b000b2322151a4f591215100e0f +0a1b03204f5906031670230171003f332b00183f3f3f332b1112013939113311333311333130 +011002232226272316151121113427211e0115333633321201102322061514163332048fd9c6 +72a92d0606fee70801110507045ffbbdd0fedbdf7077776ee10222fef1fed9635d1e98fe6104 +ea9960126a34c7feddfef4016cc4b0afbf00000000010017000004cd05810007014440e80102 +040207030908000405045f5905030112500901400901340901240901040901f40901e40901c0 +0901b40901a409018b09017009016409015409013b090124090104090168fb0901e40901cb09 +01a00901900901840901540901440901340901040901f40901db0901cb0901b409018b090174 +09015b09013b09012409010b0901fb0901eb0901d00901c409019b09014409011b09010b0901 +37f40901cb0901bb09019b09018b09017b09016f09014b09013b09012b0901040901db0901ab +09018b09015b09014b09010b0901ff090102df0901cf09018f09017009013009012009010009 +01075e5d5d5d5d5d5d5d5f5d71717171717172727272727272727272725e5d5d5d5d5d5d5d5d +71717171717171717171727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d7171717171 +003f3f2b11003311120117391133313001112111213521150305fed9fe3904b6049dfb63049d +e4e400000001000e00000464043a000b00404024000b08090a04010706050203030507090b05 +0d0c050f0015f00d01e00d019f0d014f0d015d5d5d71003f3f11120117391133113311333333 +113311333130210b01210901211b012109010333fcfefed5018cfe87012fe7e60131fe87018f +0188fe78022f020bfe9e0162fdf8fdce000000010050ffec0437044e00180042402414150a09 +0f03030915031a19060d4f590a0a061000146014020d0314140000114f590016003f2b110033 +182f5f5e5d3f332f2b1112011739113311331133313005220011100033321617052e01232211 +1033323637050e020252f6fef4010ef8bffa20fee50c6058d9dd506c0d011a0f81d214012501 +06010c012bc0a90e5363fe95fe8a65640d6fae5f00000001007fffec045c043a0016004f402f +0e0707080016081618170e121203505912160c1507000fa01801901801f01801b01801a01801 +901801701801ef18015d71717171717272003f323f3f2b110033111201393911331133113331 +30011110333236351121111417212635230e0123222635110198c0667d011908fef40c0538ad +77acb8043afda1fee3af890244fcb88a6890477b70d3cc02af0000020054fe4e045a044f0021 +002b0061403a18220a0a1f0403271212031f032d2c1b0f15254f591715100f294f590c0f1500 +075159560466047604032204320402050415040204001b702d0171003f325d5d5d2b00183f33 +2b00183f332b00183f1112011739113311331133113333313001222627251e013332363d0137 +230623220211101233321733343637210615111404033426232211103332360254c6f11c0119 +0f6350756c02025dffbdd0d6ccec5b050905010a06fefa0f776ee1df7077fe4e978c21414a90 +8e396bc7011c010801090120c32378136c8efce1e7ec03dea7bbfe98fe9fbb00000005cc05cc +007d058100150079058100150000000000000000000000000000043a001400770000ffec0000 +0000ffec00000000ffec0000fe57fff700000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000800000000000119012500f500eb0000000000000000 +000000c100d300ba00b000cf0000000000000000000000000127012901060000011200e400f4 +00c60000000000000000000000000000000000000000000000000119011f014c0000000000df +00d100c500b500000000000000000000000000000000000000000000010200a901fd00d80119 +008000b701fd00000000013f00db015d012500aa00800075008d01fc0179012100a001100000 +000001310119010e0104000000000000000000000000000000000000013d01ff00e001060094 +00e00094014400e005730319000000d802c5009c038102cd00cb00f4004e028d000000ff00d7 +00cc01300145007300b400a60000000000730080008d000000000000000000000000030000a2 +00980083008d000000000000000005aefebc0581fd300011fff600b600bc00c60000007f008a +0060000000000000000000f001ee0190000002190108011500000000000000be000000000000 +00000748036a02b60202fd930000009100670091006101d90000028d03410000000000000000 +00000000000000aafe6ffe6801050093009800e20151008f00be00aefeb9fea4005e00af02d5 +005500f200a604150601000003e1001002fa000ffed401eafff300b8000000000363000bfd0f +fff500000000000006810477001504d90000ffecffc5fe7f007500cd00f2010200d501194047 +5b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531 +302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201002c20b00160 +45b003252011466123452361482d2c20451868442d2c45234660b0206120b04660b004262348 +482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b0406120b06660b0 +04262348482d2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c +20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651 +582320b00d44235921212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a +432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab102 +00080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360 +442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364 +615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b +23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b001 +6023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243 +b001525821212121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70 +456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013 +515b58b0022546206861b00325b003253f2321381b2111592d2c2045b00325465058b0022546 +206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb840 +00622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423 +648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004 +254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c +4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00e +f68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c45234560 +23456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b21 +21592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b +515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f +45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb333003400 +5944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b001615923 +586559b02923442310b029e01b2121212121592d2cb0024354584b53234b515a58381b212159 +1b21212121592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b029 +2344b00525b00825082058021b0359b0042510b005252046b0042523423cb00425b0072508b0 +072510b006252046b00425b0016023423c2058011b0059b0042510b00525b029e0b029204565 +44b0072510b00625b029e0b00525b00825082058021b0359b00525b003254348b00425b00725 +08b00625b00325b0016043481b2159212121212121212d2c02b00425202046b004252342b005 +2508b003254548212121212d2c02b0032520b0042508b0022543482121212d2c452320451820 +b00050205823652359236820b040505821b04059235865598a60442d2c4b53234b515a582045 +8a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb0 +00214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b21 +2121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a +08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c0146 +23466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a235358 +3c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188 +535a58b910000020885458b202010243604259b12401885158b920000040885458b202020243 +6042b12401885458b2022002436042004b014b5258b2020802436042591bb940000080885458 +b202040243604259b94000008063b80100885458b202080243604259b94000010063b8020088 +5458b202100243604259b12601885158b94000020063b80400885458b202400243604259b940 +00040063b80800885458b2028002436042595959595959b10002435458400a0540084009400c +020d021bb10102435458b2054008ba010000090100b30c010d011bb18002435258b2054008b8 +0180b109401bb2054008ba01800009014059b9400000808855b94000020063b8040088555a58 +b30c000d011bb30c000d0159595942424242422d2c451868234b51582320452064b04050587c +59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b0 +0b234201b001233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b00243 +50b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d000100000002 +19998cd47ee35f0f3cf5001f080000000000c849682600000000dd7b292bfc25fcfd0a6f0844 +00010008000200010000000000010000073efe4e00430aaafc25fa7a0a6f0001000000000000 +0000000000000000001b060000cd04e30089031d008704e30050071d00870556008904e30087 +02aa00190239008f0473005004730048078d00020239008f04e300540556000e0639fffa0556 +003b0473001005c700540473003c05c7003304e3008704e300170473000e0473005004e3007f +04e30054000000000000004c000000c000000148000001d4000002dc00000380000004200000 +04a000000520000005f0000006dc0000087c000008dc00000988000009f800000c0800000ce4 +00000ef400000fa4000010a8000012fc000013a8000015140000159400001630000016cc0000 +17b800010000001b01520054005c000600020010002f005c0000034d0354000400014155013f +000101390055013e000101390055014201400014001f01410140001f001f013b0033013a0055 +013800330139005500a4013900f4013900020132003d0131005501310001012f00550130003d +012f0055012c012900ff001f01290001012a00550128003d0127005501270001012a00550126 +003d0125005501250001012a00550123012200ff001f01220001012a0055012b003d012a0055 +005001070001002f0107000100af0104405001d0fd01bffd0110fd016ffb0140fb0180f590f5 +a0f503f1f0351f2ff09ff0025fef012fef5fef6fef9fefdfef05e6e4201fe5e43d1fe2e0271f +e1e03d1fdf3ddd55de3d035500dd30dd02dd0103552f410b011e00010010011e0020011e0040 +011e0003ffc0011e4028191c46dc03ff1f00db01da043c1fd4d21c1fd3d2261f60d190d1c0d1 +0360d190d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ffc0b4d10a0d460fb80116400f01bfbe26 +1f40bb29414640bb222746b801214026b63d1f00b8016fb801b8b70a1f00b70100b720b740b7 +60b770b70540b760b790b7d0b7f0b705b80120400d483d1f00b560b502a0b5d0b502b8ffc040 +0eb50b0e460fb25fb202b1033c1f2f410b0119003f0119004f01190003008f01190001004001 +1940282629461faf2faf3faf9faf040faf0140af0e164600ad70ad80ad03e0adf0ad02abaa35 +1faa50261fb9011b011ab23c1f00b8011ab6010fa9010fa801bc01170113003c001f0115407e +503c1f9e9b271f9d9b271f9c9b271f809b019846281f9f97af97029646351f0f941f94029390 +261f9291261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f8d010f8c01408c0b0f460f891f890286 +850f1f5f850136824682027650261f7550261f7450261f7350261f2970011b7001037001f470 +01d670e67002687001597001b8fff0407d700a0d466f6e481f6e46321f1a0118551933185507 +3303550603ff1f6150261f605f321f5f50261f5e5a481f5c46271f5b5a781f5a46311f133212 +5505010355043203556f03010f033f034f036f037f03055f53014053282c4640531e22464053 +1318466b527b528b5203514f1c1f504f1c1f194f294f02594f694f02b80112402d46251f4946 +191f4846211f4746351ff846019846011c481b551632155511010f5510320f55020100550100 +ff1fb80111b21b091fb80110402d1b091f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0f +ff0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff524bb00750 +5bb00188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb03253 +58b0601d594bb0645358b0401d594bb0805358b0101db11600425973747374752b2b2b2b2b2b +2b2b0173742b2b2b2b0073742b2b732b2b2b7373752b2b2b012b2b2b002b2b2b2b2b2b2b2b01 +2b2b2b73737373747474002b2b2b2b0173732b73002b73732b732b2b73012b732b00732b2b2b +2b2b7373732b012b2b0073742b73742b73742b73012b73742b007374752b73742b2b2b012b00 +732b2b7374012b2b002b732b2b73752b732b2b012b2b002b2b737401732b0073737373737301 +737373002b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> +] def +/f-1-0 currentdict end definefont pop +%%EndResource +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 7 7 549 232 +%%EndPageSetup +q 7 7 542 225 rectclip +1 0 0 -1 0 239 cm q +0.980392 0.858824 0.678431 rg +262.043 32.25 98.41 45 re f +0 g +0.75 w +0 J +0 j +[] 0.0 d +10 M q 1 0 0 1 0 0 cm +262.043 32.25 98.41 45 re S Q +q 1 0 0 1 0 0 cm +262.043 60.75 m 360.453 60.75 l S Q +BT +9.75 0 0 -9.75 297.698181 45.375 Tm +/f-0-0 1 Tf +(\253trait\273)Tj +/f-1-0 1 Tf +0.223145 -1.153846 Td +(From)Tj +/f-0-0 1 Tf +-3.495662 -1.769231 Td +[(+from\(elem: )55(A\): B)]TJ +ET +0.980392 0.858824 0.678431 rg +353.949 7.5 13.254 27.75 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +353.949 7.5 13.254 27.75 re S Q +BT +9.75 0 0 -9.75 357.700195 20.625 Tm +/f-0-0 1 Tf +(A)Tj +0 -1.153846 Td +(B)Tj +ET +0.988235 0.917647 0.639216 rg +22.043 43.5 93.781 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +22.043 43.5 93.781 18 re S Q +BT +9.75 0 0 -9.75 25.638428 58.125 Tm +/f-1-0 1 Tf +[(EntitiesFromW)18(orld)]TJ +ET +0.988235 0.917647 0.639216 rg +322.043 183 219.547 35.25 re f +0 g +q 1 0 0 1 0 0 cm +322.043 183 219.547 35.25 re S Q +q 1 0 0 1 0 0 cm +322.043 201.75 m 541.59 201.75 l S Q +BT +9.75 0 0 -9.75 397.321838 197.625 Tm +/f-1-0 1 Tf +[(V)18(iewFromW)18(orld)]TJ +/f-0-0 1 Tf +-7.336482 -1.769231 Td +[(+excluding[LB <: CList]\(using cltB: ClistT)111(ag[B]\))]TJ +ET +0.988235 0.917647 0.639216 rg +493.629 169.5 54.711 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +493.629 169.5 54.711 16.5 re S Q +BT +9.75 0 0 -9.75 497.380737 182.625 Tm +/f-0-0 1 Tf +[(LA)55( <: CList)]TJ +ET +0.988235 0.917647 0.639216 rg +22.57 91.5 93.254 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +22.57 91.5 93.254 18 re S Q +BT +9.75 0 0 -9.75 25.636047 106.125 Tm +/f-1-0 1 Tf +[(SystemFromW)18(orld)]TJ +ET +0.988235 0.917647 0.639216 rg +20.406 67.5 95.418 18 re f +0 g +q 1 0 0 1 0 0 cm +20.406 67.5 95.418 18 re S Q +BT +9.75 0 0 -9.75 23.741272 82.125 Tm +/f-1-0 1 Tf +[(ClearAllFromW)18(orld)]TJ +ET +0.988235 0.917647 0.639216 rg +29.531 141 132.793 18 re f +0 g +q 1 0 0 1 0 0 cm +29.531 141 132.793 18 re S Q +BT +9.75 0 0 -9.75 41.42981 155.625 Tm +/f-1-0 1 Tf +(ComponentsFromEntity)Tj +ET +0.988235 0.917647 0.639216 rg +120.867 127.5 48.207 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +120.867 127.5 48.207 16.5 re S Q +BT +9.75 0 0 -9.75 124.615723 140.625 Tm +/f-0-0 1 Tf +[(L)37( <: CList)]TJ +ET +0.988235 0.917647 0.639216 rg +12.922 177 149.402 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +12.922 177 149.402 18 re S Q +BT +9.75 0 0 -9.75 24.993347 191.625 Tm +/f-1-0 1 Tf +[(ComponentT)74(ypeFromEntity)]TJ +ET +0.988235 0.917647 0.639216 rg +91.055 163.5 78.02 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +91.055 163.5 78.02 16.5 re S Q +BT +9.75 0 0 -9.75 94.803955 176.625 Tm +/f-0-0 1 Tf +(C <: Component)Tj +ET +0.988235 0.917647 0.639216 rg +7.5 213 154.824 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +7.5 213 154.824 18 re S Q +BT +9.75 0 0 -9.75 19.844604 227.625 Tm +/f-1-0 1 Tf +[(ComponentsT)74(ypeFromEntity)]TJ +ET +0.988235 0.917647 0.639216 rg +120.867 199.5 48.207 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +120.867 199.5 48.207 16.5 re S Q +BT +9.75 0 0 -9.75 124.615723 212.625 Tm +/f-0-0 1 Tf +[(L)37( <: CList)]TJ +ET +0.988235 0.917647 0.639216 rg +399.395 146.25 142.195 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +399.395 146.25 142.195 18 re S Q +BT +9.75 0 0 -9.75 411.569275 160.875 Tm +/f-1-0 1 Tf +[(ExcludingV)18(iewFromW)18(orld)]TJ +ET +0.988235 0.917647 0.639216 rg +493.629 121.5 54.711 27.75 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +493.629 121.5 54.711 27.75 re S Q +BT +9.75 0 0 -9.75 497.380737 134.625 Tm +/f-0-0 1 Tf +[(LA)55( <: CList)]TJ +0 -1.153846 Td +(LB <: CList)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +115.793 49.5 m 262.043 49.5 l S Q +1 g +246.797 55.812 m 262.043 49.5 l 246.797 43.188 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +246.797 55.812 m 262.043 49.5 l 246.797 43.188 l 246.797 55.812 l S Q +BT +9.75 0 0 -9.75 141.666138 40.125 Tm +/f-0-0 1 Tf +[(A)55( -> W)18(orld, B -> Unit)]TJ +0 1.307692 Td +(\253bind\273)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +115.793 103.5 m 142.043 103.5 l 142.043 49.5 l 262.043 49.5 l S Q +1 g +246.797 55.812 m 262.043 49.5 l 246.797 43.188 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +246.797 55.812 m 262.043 49.5 l 246.797 43.188 l 246.797 55.812 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +162.293 185.25 m 286.043 185.25 l S Q +1 g +292.355 92.492 m 286.043 77.25 l 279.727 92.492 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +292.355 92.492 m 286.043 77.25 l 279.727 92.492 l 292.355 92.492 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +162.293 149.25 m 286.043 149.25 l S Q +1 g +292.355 92.492 m 286.043 77.25 l 279.727 92.492 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +292.355 92.492 m 286.043 77.25 l 279.727 92.492 l 292.355 92.492 l S Q +BT +9.75 0 0 -9.75 182.916138 142.875 Tm +/f-0-0 1 Tf +[(A)55( -> Entity)74(, B -> Unit)]TJ +0 1.230769 Td +(\253bind\273)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +340.043 182.25 m 340.043 77.25 l S Q +1 g +346.355 92.492 m 340.043 77.25 l 333.727 92.492 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +346.355 92.492 m 340.043 77.25 l 333.727 92.492 l 346.355 92.492 l S Q +BT +9.75 0 0 -9.75 380.916138 100.125 Tm +/f-0-0 1 Tf +[(A)55( -> W)18(orld, B -> V)18(iew[LA])]TJ +0 1.307692 Td +(\253bind\273)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +454.043 145.5 m 454.043 109.5 l 340.043 109.5 l S Q +1 g +346.355 92.492 m 340.043 77.25 l 333.727 92.492 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +346.355 92.492 m 340.043 77.25 l 333.727 92.492 l 346.355 92.492 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +162.293 223.5 m 286.043 223.5 l 286.043 77.25 l S Q +1 g +292.355 92.492 m 286.043 77.25 l 279.727 92.492 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +292.355 92.492 m 286.043 77.25 l 279.727 92.492 l 292.355 92.492 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +115.793 79.5 m 142.043 79.5 l S Q +1 g +246.797 55.812 m 262.043 49.5 l 246.797 43.188 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +246.797 55.812 m 262.043 49.5 l 246.797 43.188 l 246.797 55.812 l S Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/doc/img/Sequence.eps b/doc/img/Sequence.eps index 55a03c24..2c222d9c 100644 --- a/doc/img/Sequence.eps +++ b/doc/img/Sequence.eps @@ -1,10 +1,10 @@ %!PS-Adobe-3.0 EPSF-3.0 %%Creator: cairo 1.17.4 (https://cairographics.org) -%%CreationDate: Sat Aug 14 12:09:48 2021 +%%CreationDate: Thu Oct 14 18:00:20 2021 %%Pages: 1 %%DocumentData: Clean7Bit %%LanguageLevel: 2 -%%BoundingBox: 7 8 458 410 +%%BoundingBox: 7 7 458 428 %%EndComments %%BeginProlog 50 dict begin @@ -74,10 +74,13 @@ /Encoding 256 array def 0 1 255 { Encoding exch /.notdef put } for Encoding 69 /E put +Encoding 73 /I put Encoding 83 /S put Encoding 87 /W put +Encoding 97 /a put Encoding 100 /d put Encoding 101 /e put +Encoding 103 /g put Encoding 105 /i put Encoding 108 /l put Encoding 109 /m put @@ -88,29 +91,32 @@ Encoding 114 /r put Encoding 115 /s put Encoding 116 /t put Encoding 121 /y put -/CharStrings 16 dict dup begin +/CharStrings 19 dict dup begin /.notdef 0 def /W 1 def /o 2 def /r 3 def /l 4 def /d 5 def -/S 6 def -/y 7 def -/s 8 def -/t 9 def -/e 10 def -/m 11 def -/E 12 def -/n 13 def -/i 14 def -/p 15 def +/I 6 def +/t 7 def +/e 8 def +/a 9 def +/i 10 def +/n 11 def +/g 12 def +/S 13 def +/y 14 def +/s 15 def +/m 16 def +/E 17 def +/p 18 def end readonly def /sfnts [ -<000100000009008000030010637674206d5f6ba100000d48000002886670676d7e61b6110000 -0fd0000007b4676c79666b58433b0000009c00000cac686561640ac93d4f0000178400000036 -686865610e180383000017bc00000024686d74784a740632000017e0000000406c6f63610000 -6dc000001820000000446d617870042805340000186400000020707265708aa104b900001884 +<000100000009008000030010637674206d5f6ba100000fb8000002886670676d7e61b6110000 +1240000007b4676c7966d579b1740000009c00000f1c686561640b8df529000019f400000036 +686865610e18038600001a2c00000024686d74785603074b00001a500000004c6c6f63610000 +8b7800001a9c000000506d617870042b053400001aec00000020707265708aa104b900001b0c 00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd 2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 e9000000000100020000078b05810017014040e51617010013100f0408070c0a09090c041317 @@ -138,42 +144,66 @@ e9000000000100020000078b05810017014040e51617010013100f0408070c0a09090c041317 16001570230171003f3f332b00183f332b00183f1112013939113311331133333130212e0135 230623220211101233321617332711211114170134262322061510333236034c040b045bffbd ced9c773a72d0202011908fee37572716edd6f7a0f7928c401270109010d0125605fb2018bfb -2064880223afbdb7bcfe90c300000001003bffec05060596002a0052402f0c001d1c22160706 -06161c00042c2b0c22031919205f591d1d1904030a5f59100720073007033007400702070703 -13003f332f5d712b00183f332f2b111200393911120117391133113311331133313001140421 -202427251e01332035342e01272e0435342421200417052e01232015141e01171e030506fecd -fed7fef1fecc2c011d1da89501354781b79e7c644627011f01120106010726fee216877efef4 -3970abcbaf66360196cfdbc0c32f7065bc3c4e3425252d3d56744bbfcba4bd275b5ca8374631 -252b4961870000010010fe570468043a001501ba40ff0b0a13090e1112120e030a041617110a -0f130e0900055059001b96170186170173170163170100501701421701321701241701141701 -061701f21701e01701d01701c21701b41701a417019617018217017417016017015217014217 -0134170126170112170104170167f41701e21701d21701c41701b41701a21701941701841701 -761701661701541701441701321701221701141701061701f61701d41701c61701b01701a217 -01921701841701761701661701401701321701221701141701061701f61701d41701c21701b2 -170101a0170190170184170160170154170144170130170120170114170104170137f41701cb -1701b41701741701041701403bf41701e41701cb1701bb1701ab17019417017417013b170124 -170100170102f01701e01701bf1701801701701701501701301701101701001701075e5d5d5d -5d5d5d5d5d5d5f7171717171717171717172727272725e5d5d5d5d5d5d5d5d5d5d5f5d5d5d5d -7171717171717171717171717171727272727272727272727272727272725e5d5d5d5d5d5d5d -5d5d5d5d5d5d5d5d5d7171717171715f71717171003f2b00182f33333f331112011739113311 -333311333130012227351633323e013701211316173f011321010e01011b654c352c3c4f3f27 -fe540129aa283d1941a00126fe5456b9fe570dc808265869042ffe056de15feb01fffb8dd0a0 -000000010048ffec041f044f002800724045070621141b1a0d00001a140604292a210d170317 -1e5159c21b01601b01030f1b1f1b020a041b1b1710030a5159140724070207070316502a01b0 -2a01302a01402a012f2a015d5d717172003f332f5d2b00183f332f5f5e5d5f5d5d2b11120039 -3911120117391133113311331133313001140423222627371e01333236353426272e02353436 -33321617072e01232206151416171e03041ffeffe3dfed27f7156780766c5768eea657efdbc1 -eb1df90c5e6664644d5b7fc57747013c9db38d95254d403c40343d152f51815e9bad968e1a42 -41333c2f37121a374c7700010019ffee029105380015003b401d130c0c0a0d080d040416170d -0506054f590a060808060f00114f590016003f2b00183f332f11332b11003311120139113333 -113333113331300522263511233533373315331523111416333237150601a47c86899758b0cd -cd3c3f213d68128789027ebefefebefdce4f4b0eae22000000020050ffec042d044e00120019 -006f4043170a1011160b0b0303110a031b1a160b525916211011480f16010e05161600060613 -52590610000e51597f1001101001101000169f1b016f1b015f1b014f1b012f1b015d5d5d5d5d -003f322f5d5d2b00183f2b11120039182f5f5e5d2b2b11120117391133113311331133313005 -22001110003332121115211416333237050201220607212e01024af4fefa010af4e9f6fd4a75 -6c9527010973fea0636b0301a4086e1401210115010c0120fecbfed6089ea18117feda03b18a -7c838300000100870000069e044f00260093405e172600001f081f1e1007081e082827220314 +2064880223afbdb7bcfe90c3000000010089000001b005810003006640450300000405010300 +12e00501b00501a00501900501800501500501400501000501f00501c00501b00501a0050170 +05016005011f0501e00501d00501c00501b005018005015d5d5d5d5d71717171717171727272 +7272727272003f3f1112013911333130331121118901270581fa7f0000010019ffee02910538 +0015003b401d130c0c0a0d080d040416170d0506054f590a060808060f00114f590016003f2b +00183f332f11332b110033111201391133331133331133313005222635112335333733153315 +23111416333237150601a47c86899758b0cdcd3c3f213d68128789027ebefefebefdce4f4b0e +ae22000000020050ffec042d044e00120019006f4043170a1011160b0b0303110a031b1a160b +525916211011480f16010e0516160006061352590610000e51597f1001101001101000169f1b +016f1b015f1b014f1b012f1b015d5d5d5d5d003f322f5d5d2b00183f2b11120039182f5f5e5d +2b2b111201173911331133113311333130052200111000333212111521141633323705020122 +0607212e01024af4fefa010af4e9f6fd4a756c9527010973fea0636b0301a4086e1401210115 +010c0120fecbfed6089ea18117feda03b18a7c8383000002003cffec0480044e00260033006d +403f2427270707150e0f2c03030f1503353406285259060600590e690e022d0e01030f0e1f0e +0209040e12120b51591210192f002f4f5924210016bf35014f35015d71003f32322b11003318 +3f2b1100335f5e5d5f5d5d1239182f2b11120117391133113311331133113331300522263534 +363f0135342623220607253e0133321615111416333237150e0323222627230613070e021514 +1633323e013501899db0dbd0e94a544e4909fedb1bebcbcdde2930201e1928282d1e6a650a06 +76599062522b473b426d3e14ab9ba8b00204376a6747520e9ea3cabafe765b450698060a0604 +6865d50209020423483c4d4b487f47000002008f000001a805cc000300070056403603070700 +04040809050f0415010053590100500901400901b00901a009017f09016009011f0901ef0901 +d00901c00901b009018009015d5d5d5d5d71717171717272003f2b00183f3f11120139113333 +1133313013352115011121118f0119fee7011904fdcfcffb03043afbc6000001008700000464 +044f0018004f402f00181007070808181a1910141403505914100c0f080015a01a01901a01f0 +1a01b01a01a01a01901a01701a01ef1a015d71717171717272003f323f3f2b11003311120139 +39113311331133313021111023220615112111342627211e0115333e013332161511034cc166 +7dfee70503010c030a0439ac77acb8025f011daf89fdbc0348576f2c13a51f7c70d4ccfd5100 +00020054fe4e045a044f0021002b0061403a18220a0a1f0403271212031f032d2c1b0f15254f +591715100f294f590c0f1500075159560466047604032204320402050415040204001b702d01 +71003f325d5d5d2b00183f332b00183f332b00183f1112011739113311331133113333313001 +222627251e013332363d01372306232202111012333217333436372106151114040334262322 +11103332360254c6f11c01190f6350756c02025dffbdd0d6ccec5b050905010a06fefa0f776e +e1df7077fe4e978c21414a908e396bc7011c010801090120c32378136c8efce1e7ec03dea7bb +fe98fe9fbb0000000001003bffec05060596002a0052402f0c001d1c2216070606161c00042c +2b0c22031919205f591d1d1904030a5f5910072007300703300740070207070313003f332f5d +712b00183f332f2b111200393911120117391133113311331133313001140421202427251e01 +332035342e01272e0435342421200417052e01232015141e01171e030506fecdfed7fef1fecc +2c011d1da89501354781b79e7c644627011f01120106010726fee216877efef43970abcbaf66 +360196cfdbc0c32f7065bc3c4e3425252d3d56744bbfcba4bd275b5ca8374631252b49618700 +00010010fe570468043a001501ba40ff0b0a13090e1112120e030a041617110a0f130e090005 +5059001b96170186170173170163170100501701421701321701241701141701061701f21701 +e01701d01701c21701b41701a417019617018217017417016017015217014217013417012617 +0112170104170167f41701e21701d21701c41701b41701a21701941701841701761701661701 +541701441701321701221701141701061701f61701d41701c61701b01701a217019217018417 +01761701661701401701321701221701141701061701f61701d41701c21701b2170101a01701 +90170184170160170154170144170130170120170114170104170137f41701cb1701b4170174 +1701041701403bf41701e41701cb1701bb1701ab17019417017417013b170124170100170102 +f01701e01701bf1701801701701701501701301701101701001701075e5d5d5d5d5d5d5d5d5d +5f7171717171717171717172727272725e5d5d5d5d5d5d5d5d5d5d5f5d5d5d5d717171717171 +7171717171717171727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d +5d5d5d7171717171715f71717171003f2b00182f33333f331112011739113311333311333130 +012227351633323e013701211316173f011321010e01011b654c352c3c4f3f27fe540129aa28 +3d1941a00126fe5456b9fe570dc808265869042ffe056de15feb01fffb8dd0a0000000010048 +ffec041f044f002800724045070621141b1a0d00001a140604292a210d1703171e5159c21b01 +601b01030f1b1f1b020a041b1b1710030a5159140724070207070316502a01b02a01302a0140 +2a012f2a015d5d717172003f332f5d2b00183f332f5f5e5d5f5d5d2b11120039391112011739 +1133113311331133313001140423222627371e01333236353426272e0235343633321617072e +01232206151416171e03041ffeffe3dfed27f7156780766c5768eea657efdbc1eb1df90c5e66 +64644d5b7fc57747013c9db38d95254d403c40343d152f51815e9bad968e1a4241333c2f3712 +1a374c77000100870000069e044f00260093405e172600001f081f1e1007081e082827220314 03505910171a0314100c0f1f080015e42801d428018428015428013b2801db2801bb28019b28 015428013b28012f2801021f2801002801e02801d02801b028019f28018028016028012f2801 5d5d5d5d5d5d5d71715f7171717171717272727272003f32323f3f17332b1100331112013939 @@ -184,125 +214,118 @@ fdaf00010089000005060581000b0074404a050909000b00010b060a030700040c0d05085f59 0f057f059f05030f058f05ff05030f03051615490f0501140505160c490505000101045f5901 0300095f590012400d01300d01200d015d5d5d003f2b00183f2b11120039182f2b5f5e5d2b5f 5e5d712b11120117395f5e5d113311333130331121152111211521112115890454fcd302f0fd -1003560581e4fe9ee4fe8de400000001008700000464044f0018004f402f0018100707080818 -1a1910141403505914100c0f080015a01a01901a01f01a01b01a01a01a01901a01701a01ef1a -015d71717171717272003f323f3f2b1100331112013939113311331133313021111023220615 -112111342627211e0115333e013332161511034cc1667dfee70503010c030a0439ac77acb802 -5f011daf89fdbc0348576f2c13a51f7c70d4ccfd51000002008f000001a805cc000300070056 -40360307070004040809050f0415010053590100500901400901b00901a009017f0901600901 -1f0901ef0901d00901c00901b009018009015d5d5d5d5d71717171717272003f2b00183f3f11 -1201391133331133313013352115011121118f0119fee7011904fdcfcffb03043afbc6000002 -0087fe57048f045100170021003c40201800121d09090b000b2322151a4f591215100e0f0a1b -03204f5906031670230171003f332b00183f3f3f332b11120139391133113333113331300110 -02232226272316151121113427211e0115333633321201102322061514163332048fd9c672a9 -2d0606fee70801110507045ffbbdd0fedbdf7077776ee10222fef1fed9635d1e98fe6104ea99 -60126a34c7feddfef4016cc4b0afbf00000005cc05cc007d0581001500790581001500000000 -00000000000000000000043a001400770000ffec00000000ffec00000000ffec0000fe57fff7 -0000000000000000000000000000000000000000000000000000000000000000000000000000 +1003560581e4fe9ee4fe8de4000000020087fe57048f045100170021003c40201800121d0909 +0b000b2322151a4f591215100e0f0a1b03204f5906031670230171003f332b00183f3f3f332b +1112013939113311333311333130011002232226272316151121113427211e01153336333212 +01102322061514163332048fd9c672a92d0606fee70801110507045ffbbdd0fedbdf7077776e +e10222fef1fed9635d1e98fe6104ea9960126a34c7feddfef4016cc4b0afbf00000005cc05cc +007d058100150079058100150000000000000000000000000000043a001400770000ffec0000 +0000ffec00000000ffec0000fe57fff700000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 -0800000000000119012500f500eb0000000000000000000000c100d300ba00b000cf00000000 -00000000000000000127012901060000011200e400f400c60000000000000000000000000000 -000000000000000000000119011f014c0000000000df00d100c500b500000000000000000000 -000000000000000000000000010200a901fd00d80119008000b701fd00000000013f00db015d -012500aa00800075008d01fc0179012100a001100000000001310119010e0104000000000000 -000000000000000000000000013d01ff00e00106009400e00094014400e005730319000000d8 -02c5009c038102cd00cb00f4004e028d000000ff00d700cc01300145007300b400a600000000 -00730080008d000000000000000000000000030000a200980083008d000000000000000005ae -febc0581fd300011fff600b600bc00c60000007f008a0060000000000000000000f001ee0190 -000002190108011500000000000000be00000000000000000748036a02b60202fd9300000091 -00670091006101d90000028d0341000000000000000000000000000000aafe6ffe6801050093 -009800e20151008f00be00aefeb9fea4005e00af02d5005500f200a604150601000003e10010 -02fa000ffed401eafff300b8000000000363000bfd0ffff500000000000006810477001504d9 -0000ffecffc5fe7f007500cd00f2010200d5011940475b5a59585554535251504f4e4d4c4b4a -494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f1814 -11100f0e0d0b0a090807060504030201002c20b0016045b003252011466123452361482d2c20 -451868442d2c45234660b0206120b04660b004262348482d2c4523462361b0206020b02661b0 -2061b004262348482d2c45234660b0406120b06660b004262348482d2c4523462361b0406020 -b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd442320b8015a51582320 -b08d44235920b0ed51582320b04d44235920b0042651582320b00d44235921212d2c20204518 -684420b001602045b04676688a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d -2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c2045b00325456164b05051 -5845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b00743650a2d2c2069 -b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361592d2c8a03458a8a87b0 -112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845441b2121592d2c4b -515845441b2121592d2c01b005251023208af500b0016023edec2d2c01b005251023208af500 -b0016123edec2d2c01b0062510f500edec2d2cb00243b001525821212121211b462346608a8a -462320468a608a61b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0 -468c59b0106068013a592d2c2045b0032546524bb013515b58b0022546206861b00325b00325 -3f2321381b2111592d2c2045b00325465058b0022546206861b00325b003253f2321381b2111 -592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b08051580c6423648bb820 -00621bb200402f2b59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b00260 -2d2c0c6423648bb84000626023212d2c4b53588ab004254964234569b0408b61b08062b02061 -6ab00e23442310b00ef61b21238a121120392f592d2c4b535820b0032549646920b00526b006 -2549642361b08062b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00e -ed1b8ab00426111220392320392f2f592d2c4523456023456023456023766818b08062202d2c -b0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1302f4523456160b00160 -69442d2c4b5158b02f2370b01423421b2121592d2c4b515820b0032545695358441b2121591b -2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c452320458a60442d2c452345 -60442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb0164358b00326458a5864 -66b01f601b64b020606620581b21b04059b001615923586559b02923442310b029e01b212121 -2121592d2cb0024354584b53234b515a58381b2121591b21212121592d2cb0164358b0042545 -64b020606620581b21b04059b0016123581b6559b0292344b00525b00825082058021b0359b0 -042510b005252046b0042523423cb00425b0072508b0072510b006252046b00425b001602342 -3c2058011b0059b0042510b00525b029e0b02920456544b0072510b00625b029e0b00525b008 -25082058021b0359b00525b003254348b00425b0072508b00625b00325b0016043481b215921 -2121212121212d2c02b00425202046b004252342b0052508b003254548212121212d2c02b003 -2520b0042508b0022543482121212d2c452320451820b00050205823652359236820b0405058 -21b04059235865598a60442d2c4b53234b515a5820458a60441b2121592d2c4b545820458a60 -441b2121592d2c4b53234b515a58381b2121592d2cb000214b5458381b2121592d2cb0024354 -58b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b2121 -2121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b515a5823381b2121592d -2c00b0022549b000535820b04038111b21592d2c014623466023466123201020468a61b8ff80 -628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb0 -12004b014b54422d2cb1020042b123018851b1400188535a58b910000020885458b202010243 -604259b12401885158b920000040885458b2020202436042b12401885458b202200243604200 -4b014b5258b2020802436042591bb940000080885458b202040243604259b94000008063b801 -00885458b202080243604259b94000010063b80200885458b202100243604259b12601885158 -b94000020063b80400885458b202400243604259b94000040063b80800885458b20280024360 -42595959595959b10002435458400a0540084009400c020d021bb10102435458b2054008ba01 -0000090100b30c010d011bb18002435258b2054008b80180b109401bb2054008ba0180000901 -4059b9400000808855b94000020063b8040088555a58b30c000d011bb30c000d015959594242 -4242422d2c451868234b51582320452064b04050587c59688a6059442d2cb00016b00225b002 -2501b001233e00b002233eb10102060cb00a236542b00b234201b001233f00b002233fb10102 -060cb006236542b0072342b00116012d2cb080b0024350b001b00243545b58212310b0201ac9 -1b8a10ed592d2cb0592b2d2c8a10e52d00010000000219996a60cc2b5f0f3cf5001f08000000 -0000c849682600000000dcb67151fc25fcfd0a6f084400010008000200010000000000010000 -073efe4e00430aaafc25fa7a0a6f000100000000000000000000000000000010060000cd078d -000204e30050031d00870239008f04e300540556003b047300100473004802aa001904730050 -071d00870556008904e300870239008f04e30087000000000000004c000001ec000002780000 -0300000003600000040c000004e8000006f8000007e4000008640000093400000a3c00000ae0 -00000b8000000c0000000cac00010000001001520054005c000600020010002f005c0000034d -0354000400014155013f000101390055013e000101390055014201400014001f01410140001f -001f013b0033013a0055013800330139005500a4013900f4013900020132003d013100550131 -0001012f00550130003d012f0055012c012900ff001f01290001012a00550128003d01270055 -01270001012a00550126003d0125005501250001012a00550123012200ff001f01220001012a -0055012b003d012a0055005001070001002f0107000100af0104405001d0fd01bffd0110fd01 -6ffb0140fb0180f590f5a0f503f1f0351f2ff09ff0025fef012fef5fef6fef9fefdfef05e6e4 -201fe5e43d1fe2e0271fe1e03d1fdf3ddd55de3d035500dd30dd02dd0103552f410b011e0001 -0010011e0020011e0040011e0003ffc0011e4028191c46dc03ff1f00db01da043c1fd4d21c1f -d3d2261f60d190d1c0d10360d190d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ffc0b4d10a0d46 -0fb80116400f01bfbe261f40bb29414640bb222746b801214026b63d1f00b8016fb801b8b70a -1f00b70100b720b740b760b770b70540b760b790b7d0b7f0b705b80120400d483d1f00b560b5 -02a0b5d0b502b8ffc0400eb50b0e460fb25fb202b1033c1f2f410b0119003f0119004f011900 -03008f011900010040011940282629461faf2faf3faf9faf040faf0140af0e164600ad70ad80 -ad03e0adf0ad02abaa351faa50261fb9011b011ab23c1f00b8011ab6010fa9010fa801bc0117 -0113003c001f0115407e503c1f9e9b271f9d9b271f9c9b271f809b019846281f9f97af970296 -46351f0f941f94029390261f9291261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f8d010f8c0140 -8c0b0f460f891f890286850f1f5f850136824682027650261f7550261f7450261f7350261f29 -70011b7001037001f47001d670e67002687001597001b8fff0407d700a0d466f6e481f6e4632 -1f1a01185519331855073303550603ff1f6150261f605f321f5f50261f5e5a481f5c46271f5b -5a781f5a46311f1332125505010355043203556f03010f033f034f036f037f03055f53014053 -282c4640531e224640531318466b527b528b5203514f1c1f504f1c1f194f294f02594f694f02 -b80112402d46251f4946191f4846211f4746351ff846019846011c481b551632155511010f55 -10320f55020100550100ff1fb80111b21b091fb80110402d1b091f1f0f3f0f5f0f7f0f040f0f -2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b -2b4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b58b101018e59 -858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101db11600425973 -747374752b2b2b2b2b2b2b2b0173742b2b2b2b0073742b2b732b2b2b7373752b2b2b012b2b2b -002b2b2b2b2b2b2b2b012b2b2b73737373747474002b2b2b2b0173732b73002b73732b732b2b -73012b732b00732b2b2b2b2b7373732b012b2b0073742b73742b73742b73012b73742b007374 -752b73742b2b2b012b00732b2b7374012b2b002b732b2b73752b732b2b012b2b002b2b737401 -732b0073737373737301737373002b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> +000000000000000000000000000000000800000000000119012500f500eb0000000000000000 +000000c100d300ba00b000cf0000000000000000000000000127012901060000011200e400f4 +00c60000000000000000000000000000000000000000000000000119011f014c0000000000df +00d100c500b500000000000000000000000000000000000000000000010200a901fd00d80119 +008000b701fd00000000013f00db015d012500aa00800075008d01fc0179012100a001100000 +000001310119010e0104000000000000000000000000000000000000013d01ff00e001060094 +00e00094014400e005730319000000d802c5009c038102cd00cb00f4004e028d000000ff00d7 +00cc01300145007300b400a60000000000730080008d000000000000000000000000030000a2 +00980083008d000000000000000005aefebc0581fd300011fff600b600bc00c60000007f008a +0060000000000000000000f001ee0190000002190108011500000000000000be000000000000 +00000748036a02b60202fd930000009100670091006101d90000028d03410000000000000000 +00000000000000aafe6ffe6801050093009800e20151008f00be00aefeb9fea4005e00af02d5 +005500f200a604150601000003e1001002fa000ffed401eafff300b8000000000363000bfd0f +fff500000000000006810477001504d90000ffecffc5fe7f007500cd00f2010200d501194047 +5b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531 +302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201002c20b00160 +45b003252011466123452361482d2c20451868442d2c45234660b0206120b04660b004262348 +482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b0406120b06660b0 +04262348482d2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c +20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651 +582320b00d44235921212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a +432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab102 +00080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360 +442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364 +615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b +23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b001 +6023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243 +b001525821212121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70 +456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013 +515b58b0022546206861b00325b003253f2321381b2111592d2c2045b00325465058b0022546 +206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb840 +00622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423 +648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004 +254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c +4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00e +f68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c45234560 +23456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b21 +21592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b +515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f +45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb333003400 +5944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b001615923 +586559b02923442310b029e01b2121212121592d2cb0024354584b53234b515a58381b212159 +1b21212121592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b029 +2344b00525b00825082058021b0359b0042510b005252046b0042523423cb00425b0072508b0 +072510b006252046b00425b0016023423c2058011b0059b0042510b00525b029e0b029204565 +44b0072510b00625b029e0b00525b00825082058021b0359b00525b003254348b00425b00725 +08b00625b00325b0016043481b2159212121212121212d2c02b00425202046b004252342b005 +2508b003254548212121212d2c02b0032520b0042508b0022543482121212d2c452320451820 +b00050205823652359236820b040505821b04059235865598a60442d2c4b53234b515a582045 +8a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb0 +00214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b21 +2121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a +08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c0146 +23466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a235358 +3c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188 +535a58b910000020885458b202010243604259b12401885158b920000040885458b202020243 +6042b12401885458b2022002436042004b014b5258b2020802436042591bb940000080885458 +b202040243604259b94000008063b80100885458b202080243604259b94000010063b8020088 +5458b202100243604259b12601885158b94000020063b80400885458b202400243604259b940 +00040063b80800885458b2028002436042595959595959b10002435458400a0540084009400c +020d021bb10102435458b2054008ba010000090100b30c010d011bb18002435258b2054008b8 +0180b109401bb2054008ba01800009014059b9400000808855b94000020063b8040088555a58 +b30c000d011bb30c000d0159595942424242422d2c451868234b51582320452064b04050587c +59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b0 +0b234201b001233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b00243 +50b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d000100000002 +19997d702c195f0f3cf5001f080000000000c849682600000000dd7b292bfc25fcfd0a6f0844 +00010008000200010000000000010000073efe4e00430aaafc25fa7a0a6f0001000000000000 +00000000000000000013060000cd078d000204e30050031d00870239008f04e3005402390089 +02aa0019047300500473003c0239008f04e3008704e300540556003b0473001004730048071d +00870556008904e30087000000000000004c000001ec0000027800000300000003600000040c +0000048c0000050c000005dc000006e00000076000000800000008ec000009c800000bd80000 +0cc400000dcc00000e7000000f1c00010000001301520054005c000600020010002f005c0000 +034d0354000400014155013f000101390055013e000101390055014201400014001f01410140 +001f001f013b0033013a0055013800330139005500a4013900f4013900020132003d01310055 +01310001012f00550130003d012f0055012c012900ff001f01290001012a00550128003d0127 +005501270001012a00550126003d0125005501250001012a00550123012200ff001f01220001 +012a0055012b003d012a0055005001070001002f0107000100af0104405001d0fd01bffd0110 +fd016ffb0140fb0180f590f5a0f503f1f0351f2ff09ff0025fef012fef5fef6fef9fefdfef05 +e6e4201fe5e43d1fe2e0271fe1e03d1fdf3ddd55de3d035500dd30dd02dd0103552f410b011e +00010010011e0020011e0040011e0003ffc0011e4028191c46dc03ff1f00db01da043c1fd4d2 +1c1fd3d2261f60d190d1c0d10360d190d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ffc0b4d10a +0d460fb80116400f01bfbe261f40bb29414640bb222746b801214026b63d1f00b8016fb801b8 +b70a1f00b70100b720b740b760b770b70540b760b790b7d0b7f0b705b80120400d483d1f00b5 +60b502a0b5d0b502b8ffc0400eb50b0e460fb25fb202b1033c1f2f410b0119003f0119004f01 +190003008f011900010040011940282629461faf2faf3faf9faf040faf0140af0e164600ad70 +ad80ad03e0adf0ad02abaa351faa50261fb9011b011ab23c1f00b8011ab6010fa9010fa801bc +01170113003c001f0115407e503c1f9e9b271f9d9b271f9c9b271f809b019846281f9f97af97 +029646351f0f941f94029390261f9291261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f8d010f8c +01408c0b0f460f891f890286850f1f5f850136824682027650261f7550261f7450261f735026 +1f2970011b7001037001f47001d670e67002687001597001b8fff0407d700a0d466f6e481f6e +46321f1a01185519331855073303550603ff1f6150261f605f321f5f50261f5e5a481f5c4627 +1f5b5a781f5a46311f1332125505010355043203556f03010f033f034f036f037f03055f5301 +4053282c4640531e224640531318466b527b528b5203514f1c1f504f1c1f194f294f02594f69 +4f02b80112402d46251f4946191f4846211f4746351ff846019846011c481b55163215551101 +0f5510320f55020100550100ff1fb80111b21b091fb80110402d1b091f1f0f3f0f5f0f7f0f04 +0f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b154 +532b2b4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b58b10101 +8e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101db1160042 +5973747374752b2b2b2b2b2b2b2b0173742b2b2b2b0073742b2b732b2b2b7373752b2b2b012b +2b2b002b2b2b2b2b2b2b2b012b2b2b73737373747474002b2b2b2b0173732b73002b73732b73 +2b2b73012b732b00732b2b2b2b2b7373732b012b2b0073742b73742b73742b73012b73742b00 +7374752b73742b2b2b012b00732b2b7374012b2b002b732b2b73752b732b2b012b2b002b2b73 +7401732b0073737373737301737373002b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> ] def /f-0-0 currentdict end definefont pop %%EndResource @@ -320,10 +343,21 @@ Encoding 39 /quotesingle put Encoding 40 /parenleft put Encoding 41 /parenright put Encoding 44 /comma put +Encoding 46 /period put +Encoding 49 /one put +Encoding 50 /two put +Encoding 51 /three put +Encoding 52 /four put +Encoding 53 /five put +Encoding 54 /six put +Encoding 58 /colon put +Encoding 82 /R put +Encoding 84 /T put Encoding 97 /a put Encoding 99 /c put Encoding 100 /d put Encoding 101 /e put +Encoding 104 /h put Encoding 105 /i put Encoding 108 /l put Encoding 109 /m put @@ -334,274 +368,322 @@ Encoding 114 /r put Encoding 115 /s put Encoding 116 /t put Encoding 117 /u put -Encoding 118 /v put Encoding 119 /w put Encoding 121 /y put -/CharStrings 23 dict dup begin +/CharStrings 33 dict dup begin /.notdef 0 def -/a 1 def -/p 2 def -/l 3 def -/y 4 def -/parenleft 5 def -/parenright 6 def -/u 7 def -/d 8 def -/t 9 def -/e 10 def -/comma 11 def -/space 12 def -/c 13 def -/s 14 def -/v 15 def -/o 16 def -/m 17 def -/n 18 def -/w 19 def -/r 20 def -/quotesingle 21 def -/i 22 def +/one 1 def +/space 2 def +/colon 3 def +/u 4 def +/p 5 def +/d 6 def +/a 7 def +/t 8 def +/e 9 def +/parenleft 10 def +/l 11 def +/T 12 def +/i 13 def +/m 14 def +/parenright 15 def +/two 16 def +/comma 17 def +/c 18 def +/o 19 def +/s 20 def +/three 21 def +/four 22 def +/five 23 def +/six 24 def +/w 25 def +/r 26 def +/quotesingle 27 def +/y 28 def +/period 29 def +/h 30 def +/R 31 def +/n 32 def end readonly def /sfnts [ -<000100000009008000030010637674204ada4bfa00001328000002886670676d7e61b6110000 -15b0000007b4676c7966bcbcad1c0000009c0000128c686561640a3bd00c00001d6400000036 -686865610d94039400001d9c00000024686d74785555083e00001dc00000005c6c6f63610000 -d99400001e1c000000606d617870038603e400001e7c0000002070726570fdae474900001e9c +<000100000009008000030010637674204ada4bfa000018a0000002886670676d7e61b6110000 +1b28000007b4676c796629f942d20000009c00001804686561640b008bb1000022dc00000036 +686865610d94039e0000231400000024686d74787f960d4b00002338000000846c6f63610001 +75bc000023bc000000886d617870039003e4000024440000002070726570fdae474900002464 00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd 2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 -e900000000020057ffec0473044e00230030008e40562029290707150e0f2e03030f151a0432 -311d1851591d1620001107295159070711003f0e010f0e6f0e020b030e0e11110b5059111000 -2450590016c03201a03201903201803201703201603201503201303201a032015d7171717171 -717171003f2b00183f2b110033182f5f5e5d711112392f2b11120039183f2b11120117391133 -113311331133113331300522263534363f013534262322060727122132161511141633323715 -0623222627230e0127323e013d01070e02151416019ea3a4ddf6f37078796e0bbc2e0184ccce -2a3b1a214447645b060645b75a639a59c57f83465f14ac96a8b406043b8472525a110124bbb1 -fe2e505107701069707c67875a9d53590402306451586000000000020084fe57041d044d0017 -0024005d403718001f110808090009262511041502151b505915100c0f081b022250590216b0 -26013f26019026017026011f2601ff2601e02601c026015d5d5d7171717272003f2b00183f3f -3f2b1112003939111201393911331133331133313001102122272316151123113427331e0215 -333e0133321203342623220e01151416333236041dfe72fa560504b406ae01040504309e81c8 -c6bd7a856b793f8899867b0222fdcabc08a2fe590506a73604316613645dfef4fedde2c25abf -99d5cac500000001008a0000013e05cc000300764051030000050401000015f00501e00501df -0501c00501b005019f05018005017005011f05010f0501f00501df0501c00501b00501a00501 -9005014f0501ff0501e00501d00501c005018005017005011f05015d5d5d5d5d5d5d71717171 -71717172727272727272727272003f3f1112013911333130331133118ab405ccfa3400000001 -0005fe5703fc043a001601e440ff13080f11120a0909030f1204181708130f131711090f0005 -5059001b921801821801741801641801521801421801341801241801121801021801f41801e4 -1801d21801c21801b41801a41801921801821801741801641801561801421801341801241801 -16180102180167f41801e41801d61801c21801b41801a4180196180182180174180164180156 -1801421801341801241801161801021801f41801e41801d61801c2180101b01801a018019418 -01841801701801601801541801441801301801201801141801041801f01801e01801d41801c4 -1801b01801a01801941801841801701801601801541801441801301801201801141801041801 -37e018405a01d41801c41801a018019418018418016018015418014418012018011418010418 -01e01801d41801c41801a0180194180184180160180102501801301801201801001801c01801 -9018018018015018012f1801101801001801075e5d5d5d5d5d5d5d717171715f717171717171 -717272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171 -717171715f71717171727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d -5d5d5d5d71717171717171717171003f2b00183f331133331133111201173911331133113333 -3130132227351633323f010133131e0217371333010e02bf4a32262ea86211fe53c0e4050e4c -0346edbefe6043748dfe570b8706f72b0435fdaa0e27de0dc502b1fbc6ada95300000001007f -fe58029e05cc000e0022401007000b0a03040a0400030f100a1b0300003f3f11120117391133 -1133113331301310123733060211101217232602117fb5bcaebbafadbdaebdb40214012101cc -cbd0fe2cfeeafeebfe2ed3cc01cd011f0001000cfe58022b05cc000e00224010070003040b0a -00040a030f100a00031b003f3f11120117391133113311333130011002072336121110022733 -161211022bb5bcaebcaeafbbaebdb40210fedffe34cbd201d10117011701d2d1ccfe33fee100 -000000010085ffec03eb043a001a005f403b1208080b01190b191c1b12051605505916160d15 -09000fd01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a01c01701c -015d5d5d5d5d5d5d7171727272003f323f3f2b11003311120139391133113311333130011114 -1e01333236351133111417232e0227230e012322263511013a2a5c598296b406aa0102030203 -3ea379b2a5043afd526b7634b29e0273fcadbd2a052c394f705db1cc02d100020056ffec03ef -05cc00160022005640311d000e0e0f17060f06242312150e00000b0308082050590810031a50 -5903169024017024011f2401ff2401e02401c024015d5d5d717171003f2b00183f2b11120039 -39183f3f1112013939113311331133333130250e012322021110213216173327113311141723 -2e0135011416333236353426232206033532a57acdc1018e7ba4320202b406ac0307fdda7887 -998a8a978879ae685a0114011802365a627901c1fb13a93610742a0170e3c4d4dfd7c8c90001 -001ffff0022a052c0014004540240d14140b0f0f09040416150e05080550590b0f09010c0309 -40080f0212505902168016015d003f2b00183f1acd5f5e5d332b110033111201391133331133 -3211333130250623223511233533373315331523111416333237022a595dd87d843578c8c833 -3f24440818f502d283f2f283fd554e3f0e00000000020057ffec0418044e0012001900774046 -131106071900000c0c0711031b1a06060003190050590d190114041919090f0f1650590f1009 -0350590916d01b01c01b01a01b01901b01801b01701b01601b01501b01301b01717171717171 -717171003f2b00183f2b11120039182f5f5e5d2b11120039182f111201173911331133113311 -33313001141633323637170221220211101233201115272e012322060701149a94758d199e61 -fea8f0fbfbe901ddba0f908783990601f7baca5e482dff00011e011a010c011efdc1188aab9d -af990000000100b8fefa018100db0009002240110405000805080a0b0005a85b08009b5b0800 -2f2b2b111201393911331133313025151406072336352335018126287b5e58dba86a8e41887e -db00000000010057ffec03ca044e001900664045000d1413060707130d031a1b101750591f14 -7f148f14df140414141010200670068006d006e0060500061006600670068006c006d0060709 -0306060a0a0350590a161f1b015d003f2b110033182f5f5e5d713f332f5d2b11120117391133 -11331133313001141633323637170e0123220211101233321617072e01232206011388896081 -0fb615e0ace3eff0e0a6db1cb90e72698f800222d8d0686c0c9cba011f01130111011fac970e -5a6abe00000000010039ffec03b6044b002a0064403c070622151c1b0d00001b1506042b2c0d -220318181f50591c1810030a5059070316102c01002c01f02c01e02c01c02c01602c01802c01 -3f2c01102c015d5d5d717171717272003f332b00183f332b1112003939111201173911331133 -11331133313001140623222627371e013332363534262f012e0235343633321617072e012322 -0615141e01171e0303b6e7d0cadb219f179080897f5862819b834ad3cab3d31ca20f836e7a74 -305e978f7e4928012b99a6858d1f5751545440501a22284d6e50949b7e8b14484d4a4b2e3c2a -25243d4a610000010007000003f9043a000a015c40f8010006090a030202060a030b0c09020f -0601159b0c01840c01600c01540c01440c01200c01140c01040c01e00c01d40c01c40c01a00c -01940c01840c01600c01540c01440c01140c01040c0167d40c01c40c01940c01840c01540c01 -440c01140c01040c01db0c01c40c019b0c01840c015b0c01440c011b0c01040c01db0c01c40c -019b0c018b0c015b0c014b0c011b0c010b0c0137db0c01cb0c019b0c018b0c015b0c014b0c01 -3f0c01200c01140c01040c01e00c01d40c01c40c01a00c01940c01840c01600c01540c01440c -01200c01140c01040c01d40c01c40c01a00c01940c01840c01600c0102500c012f0c01100c01 -000c01075e5d5d5d5d5f5d5d5d5d5d5d71717171717171717171717172727272727272727272 -5e5d5d5d5d5d5d5d5d717171717171717172727272727272725e5d5d5d5d5d5d5d5d5d5d5d71 -71717171717171003f333f331112011739113311331133333130212301331316173f01133302 -65d5fe77c0ee0d382327f6bf043afd4028c5757602c200020056ffec041d044e000a00160048 -402c11060b0006001718080e50590810031450590316a0180190180180180170180160180150 -1801301801df18015d71717171717171003f2b00183f2b111201393911331133313001100223 -22021110213212033426232206151416333236041dfaeeedf201e5f8eabd859d9e8d8b95a28b -021efee4feea012101110230feeffee1e0cbcfdcd6d7d00000000001008800000623044e0029 -017e40ff182900002109212012080920092b2a1c2550591c10181100151504505915100c0f21 -090015642b014b2b013f2b012b2b011f2b010f2b01eb2b01df2b01bb2b01ab2b018b2b017b2b -016f2b013b2b011f2b010b2b016aeb2b01cb2b01bb2b01af2b018b2b017f2b015b2b014f2b01 -1b2b01fb2b01ef2b01df2b01cb2b01bb2b01af2b01942b01642b014b2b012b2b011b2b01042b -01f42b01db2b01ab2b018b2b017f2b016b2b01342b011b2b010f2b0139fb2b01db2b01bb2b01 -a02b01942b01742b015b2b014b2b012b2b011f2b010b2b01fb2b01eb2b01cb2b01a42b017b2b -015b2b014b2b011b2b01f42b01d02b0102c02b01a02b01902b01602b014f2b400b01302b012f -2b01002b01085e5d5d5d5d5d5d5d5d5f5d5d717171717171717172727272727272727272725e -5d5d5d5d5d5d5d5d5d7171717171717171717171717272727272727272725e5d5d5d5d5d5d5d -5d5d5d717171717171003f32323f3f2b1112003939183f2b1112013939113333113311123911 -3333313021113426232206151123113427331e0217333e0133321617333e0133321615112311 -34262322061511030056707386b306aa01020302033a966c7b8f1c03389f71a495b256707683 -02ae9d78b0a0fd8d0353bd2a052c394f735a626b6d60b2cbfd2f02ae9d78afa1fd8d00000001 -0088000003ee044e001a0061403c1209090a001a0a1a1b1c1216001605505916100d0f0a0015 -d01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a01c01701c015d5d -5d5d5d5d5d7171727272003f323f3f2b11120039111201393911331133113331302111342e01 -232206151123113427331e0217333e01333216151103392a5c598296b406aa01020302033ea3 -79b2a502ae6b7634b29efd8d0353bd2a052c394f705db1ccfd2f0001fffd000005cc043a0014 -01ae40ff01001107060c0f0e0313090c031103140807140114160808010b0815030e1303080f -010c11030715761601661601541601461601361601241601161601041601f41601e61601c416 -01b21601a4160196160186160166160154160144160136160114160106160169f61601e21601 -d41601c61601b61601961601841601741601661601461601361601241601161601061601f416 -01e61601b61601a41601941601861601691601561601441601361601061601e41601d61601c4 -1601b61601a616018916017216010160160154160124160104160138f41601d41601c41601a4 -16018016017416014b1601301601241601141601fb1601c41601a0160194164030017b160164 -16014416013416011b1601f01601e41601cb1601b416019416018416016416013f1601021016 -01001601085e5d5d5f5d5d5d5d5d5d5d5d717171717171717171727272727272727272725e5d -5d5d5d5f5d5d5d5d5d5d5d717171717171717171717172727272727272727272727272725e5d -5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171003f17333f17331101335e5d11335d111217 -3933321133331133331133333130212303270e010323013313161737133313173713330496d1 -bd240926b9d0fed1b2b7072411e2c1bd2e1fcdb002fda92da9fd30043afd2118ae4a035bfd19 -be8b031a00000001008800000288044e00130023401006131300000c14150f060a10040f0015 -003f3f3f3333111201393911331133313033113427331615333e01333217152623220615118e -06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4fdcc00000001006803c60120 -058100030019400b0302020405200001000203003fcd5d111201391133313001230333010a8d -15b803c601bb000200890000013d05cc00030007006e40480307070004040809050f04150100 -53590100ff0901e00901df0901c00901b009019f09018009017009011f0901000901f00901df -0901c00901b00901a009019009014f09011f09015d7171717171717172727272727272727272 -003f2b00183f3f1112013911333311333130133533150311331189b4b4b40520acacfae0043a -fbc605cc05cc007d058100150079058100150000000000000000000000000000043a00140077 -0000ffec00000000ffec00000000ffec0000fe57000000000000000000000000000000000000 +e90000000001009c0000040f0581000a002b4014040802020b0c050404030606080100017459 +0018003f2b110033183f33332f3311120139113333313033352111053525331121159c0167fe +c2014da6015799043ce3aae5fb189900000200bb0000017e043a000300070027401303070704 +0004090804059c5b0401009c5b010f003f2b00182f2b11120139391133113331301335331503 +353315bbc3c3c3036bcfcffc95cfcf0000010085ffec03eb043a001a005f403b1208080b0119 +0b191c1b12051605505916160d1509000fd01c01c01c01b01c01f01c01b01c01ff1c01e01c01 +d01c01c01c01b01c01a01c01701c015d5d5d5d5d5d5d7171727272003f323f3f2b1100331112 +01393911331133113331300111141e01333236351133111417232e0227230e01232226351101 +3a2a5c598296b406aa01020302033ea379b2a5043afd526b7634b29e0273fcadbd2a052c394f +705db1cc02d100020084fe57041d044d00170024005d403718001f1108080900092625110415 +02151b505915100c0f081b022250590216b026013f26019026017026011f2601ff2601e02601 +c026015d5d5d7171717272003f2b00183f3f3f2b111200393911120139391133113333113331 +3001102122272316151123113427331e0215333e0133321203342623220e0115141633323604 +1dfe72fa560504b406ae01040504309e81c8c6bd7a856b793f8899867b0222fdcabc08a2fe59 +0506a73604316613645dfef4fedde2c25abf99d5cac5000000020056ffec03ef05cc00160022 +005640311d000e0e0f17060f06242312150e00000b0308082050590810031a50590316902401 +7024011f2401ff2401e02401c024015d5d5d717171003f2b00183f2b1112003939183f3f1112 +013939113311331133333130250e0123220211102132161733271133111417232e0135011416 +333236353426232206033532a57acdc1018e7ba4320202b406ac0307fdda7887998a8a978879 +ae685a0114011802365a627901c1fb13a93610742a0170e3c4d4dfd7c8c900020057ffec0473 +044e00230030008e40562029290707150e0f2e03030f151a0432311d1851591d162000110729 +5159070711003f0e010f0e6f0e020b030e0e11110b50591110002450590016c03201a0320190 +3201803201703201603201503201303201a032015d7171717171717171003f2b00183f2b1100 +33182f5f5e5d711112392f2b11120039183f2b11120117391133113311331133113331300522 +263534363f0135342623220607271221321615111416333237150623222627230e0127323e01 +3d01070e02151416019ea3a4ddf6f37078796e0bbc2e0184ccce2a3b1a214447645b060645b7 +5a639a59c57f83465f14ac96a8b406043b8472525a110124bbb1fe2e505107701069707c6787 +5a9d5359040230645158600000000001001ffff0022a052c0014004540240d14140b0f0f0904 +0416150e05080550590b0f09010c030940080f0212505902168016015d003f2b00183f1acd5f +5e5d332b11003311120139113333113332113331302506232235112335333733153315231114 +16333237022a595dd87d843578c8c8333f24440818f502d283f2f283fd554e3f0e0000000002 +0057ffec0418044e0012001900774046131106071900000c0c0711031b1a0606000319005059 +0d190114041919090f0f1650590f10090350590916d01b01c01b01a01b01901b01801b01701b +01601b01501b01301b01717171717171717171003f2b00183f2b11120039182f5f5e5d2b1112 +0039182f11120117391133113311331133313001141633323637170221220211101233201115 +272e012322060701149a94758d199e61fea8f0fbfbe901ddba0f908783990601f7baca5e482d +ff00011e011a010c011efdc1188aab9daf9900000001007ffe58029e05cc000e002240100700 +0b0a03040a0400030f100a1b0300003f3f111201173911331133113331301310123733060211 +101217232602117fb5bcaebbafadbdaebdb40214012101cccbd0fe2cfeeafeebfe2ed3cc01cd +011f0001008a0000013e05cc000300764051030000050401000015f00501e00501df0501c005 +01b005019f05018005017005011f05010f0501f00501df0501c00501b00501a005019005014f +0501ff0501e00501d00501c005018005017005011f05015d5d5d5d5d5d5d7171717171717172 +727272727272727272003f3f1112013911333130331133118ab405ccfa3400000001002e0000 +04b405810007013040d90102040207030908000405045f59050301127b09014b09013b090124 +0901fb0901cb0901bb09019b09018b09017f0901025f09014f09013009010f090167df0901cf +0901b009018f09015f09014f09010f0901f00901df0901cf0901af09019f09017009015f0901 +4009011f0901ef0901df09019f09016f09015f09013f09011f090100090137ef0901d0090190 +09018009016f09015009012f0901000901d00901af09019009017f09016f0901500901400901 +200901100901ff0901e00901bf0901a009019009016009014009013f09012009010f0901075e +5d5d5d5d5d5d5d5d5d5d71717171717171717172727272727272725e5d5d5d5d5d5d5d5d7171 +71717171717171727272727272725e5d5d5d5d5f5d5d5d5d5d5d71717171003f3f2b11003311 +1201173911333130011123112135211502d0befe1c048604e5fb1b04e59c9c00000000020089 +0000013d05cc00030007006e40480307070004040809050f0415010053590100ff0901e00901 +df0901c00901b009019f09018009017009011f0901000901f00901df0901c00901b00901a009 +019009014f09011f09015d7171717171717172727272727272727272003f2b00183f3f111201 +3911333311333130133533150311331189b4b4b40520acacfae0043afbc60001008800000623 +044e0029017e40ff182900002109212012080920092b2a1c2550591c10181100151504505915 +100c0f21090015642b014b2b013f2b012b2b011f2b010f2b01eb2b01df2b01bb2b01ab2b018b +2b017b2b016f2b013b2b011f2b010b2b016aeb2b01cb2b01bb2b01af2b018b2b017f2b015b2b +014f2b011b2b01fb2b01ef2b01df2b01cb2b01bb2b01af2b01942b01642b014b2b012b2b011b +2b01042b01f42b01db2b01ab2b018b2b017f2b016b2b01342b011b2b010f2b0139fb2b01db2b +01bb2b01a02b01942b01742b015b2b014b2b012b2b011f2b010b2b01fb2b01eb2b01cb2b01a4 +2b017b2b015b2b014b2b011b2b01f42b01d02b0102c02b01a02b01902b01602b014f2b400b01 +302b012f2b01002b01085e5d5d5d5d5d5d5d5d5f5d5d71717171717171717272727272727272 +7272725e5d5d5d5d5d5d5d5d5d7171717171717171717171717272727272727272725e5d5d5d +5d5d5d5d5d5d5d717171717171003f32323f3f2b1112003939183f2b11120139391133331133 +111239113333313021113426232206151123113427331e0217333e0133321617333e01333216 +1511231134262322061511030056707386b306aa01020302033a966c7b8f1c03389f71a495b2 +5670768302ae9d78b0a0fd8d0353bd2a052c394f735a626b6d60b2cbfd2f02ae9d78afa1fd8d +00000001000cfe58022b05cc000e00224010070003040b0a00040a030f100a00031b003f3f11 +120117391133113311333130011002072336121110022733161211022bb5bcaebcaeafbbaebd +b40210fedffe34cbd201d10117011701d2d1ccfe33fee1000000000100670000040c0596001e +003e40201c000e0f08151d150f00041f20081c0e12120b7359120701001c001c74590018003f +2b11120039183f2b11003312391112011739113311331133313033353e053534262322060727 +3e0133321615140e01070e01072115673393a29f804f887973950db814f7c2d5e54b94d17388 +1e02df7f75b3917c7c885674807d7111a9c8c9b952a2a2aa5e9746990000000100b8fefa0181 +00db0009002240110405000805080a0b0005a85b08009b5b08002f2b2b111201393911331133 +313025151406072336352335018126287b5e58dba86a8e41887edb00000000010057ffec03ca +044e001900664045000d1413060707130d031a1b101750591f147f148f14df14041414101020 +0670068006d006e0060500061006600670068006c006d00607090306060a0a0350590a161f1b +015d003f2b110033182f5f5e5d713f332f5d2b11120117391133113311333130011416333236 +37170e0123220211101233321617072e012322060113888960810fb615e0ace3eff0e0a6db1c +b90e72698f800222d8d0686c0c9cba011f01130111011fac970e5a6abe00000000020056ffec +041d044e000a00160048402c11060b0006001718080e50590810031450590316a01801901801 +801801701801601801501801301801df18015d71717171717171003f2b00183f2b1112013939 +1133113331300110022322021110213212033426232206151416333236041dfaeeedf201e5f8 +eabd859d9e8d8b95a28b021efee4feea012101110230feeffee1e0cbcfdcd6d7d00000000001 +0039ffec03b6044b002a0064403c070622151c1b0d00001b1506042b2c0d220318181f50591c +1810030a5059070316102c01002c01f02c01e02c01c02c01602c01802c013f2c01102c015d5d +5d717171717272003f332b00183f332b11120039391112011739113311331133113331300114 +0623222627371e013332363534262f012e0235343633321617072e0123220615141e01171e03 +03b6e7d0cadb219f179080897f5862819b834ad3cab3d31ca20f836e7a74305e978f7e492801 +2b99a6858d1f5751545440501a22284d6e50949b7e8b14484d4a4b2e3c2a25243d4a61000001 +004effec0419059600280063403907061b1c15220c00002225101c0606292a25111011107459 +111813824d111813014d0f110110051111031b1f1f1873591f0703097359070319003f332b00 +183f2b1100331239182f5f5e5d2b2b2b11120039111201173911331133113311333130011406 +2322262737162132363534262b013533323635342623220607273e0133321615140607151e01 +0419f8e6d6ff18ba24010f889bb1a7666294a3858377930cb514f7c2d4eb97909eb00185c3d6 +c1bd11fa868473819c817271837a6f0eadc2c5b087a91e0411b200000002002f000004370581 +000a00120036401a1105120202080105011314000411047359081111010b06060118003f3f33 +12392f332b11003311120139391133331133113331300111231121350133113315010e010701 +0f01210371aafd680285bdc6fe9002340dfe97361001f2013ffec1013f8c03b6fc4c8e037706 +5e13fdec4a14000000010052ffec041d0581001c005e40351213181714140013070618130c00 +00161306041d1e1a0f73591a1a03141417745914060309735967070116070173078307020703 +19003f335d5d5d2b00183f2b11120039182f2b11120117391133113311331112391133111239 +31300114002322262737163332363534262322060723132115210336333216041dfef7ebc5f2 +20b639ec91a4a58c497e3fb02f0321fd831b75aed0f701cbdfff00aca315d1af9985a42e3702 +f699fe415af400020068ffec04190596001600220050402b1d11060c0b1700000b0603232411 +1a141a755914140309090e73590f0c8f0c020a050c0907032073590319003f2b00183f335f5e +5d2b11120039182f2b1100331112011739113311331133333130011402232202111000332013 +0726232202113e013332160734262322061514163332360419f2d5eefc0106f2013f53ac35b3 +9aa931b273c3e5b796867e9ba17e829401cddffefe01620152016e0188fee11facfee1fef05b +5ff4d699a69381a3d0af00000001fffd000005cc043a001401ae40ff01001107060c0f0e0313 +090c031103140807140114160808010b0815030e1303080f010c110307157616016616015416 +01461601361601241601161601041601f41601e61601c41601b21601a4160196160186160166 +160154160144160136160114160106160169f61601e21601d41601c61601b616019616018416 +01741601661601461601361601241601161601061601f41601e61601b61601a4160194160186 +1601691601561601441601361601061601e41601d61601c41601b61601a61601891601721601 +0160160154160124160104160138f41601d41601c41601a416018016017416014b1601301601 +241601141601fb1601c41601a0160194164030017b16016416014416013416011b1601f01601 +e41601cb1601b416019416018416016416013f160102101601001601085e5d5d5f5d5d5d5d5d +5d5d5d717171717171717171727272727272727272725e5d5d5d5d5f5d5d5d5d5d5d5d717171 +717171717171717172727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d7171 +717171717171003f17333f17331101335e5d11335d1112173933321133331133331133333130 +212303270e010323013313161737133313173713330496d1bd240926b9d0fed1b2b7072411e2 +c1bd2e1fcdb002fda92da9fd30043afd2118ae4a035bfd19be8b031a00000001008800000288 +044e00130023401006131300000c14150f060a10040f0015003f3f3f33331112013939113311 +33313033113427331615333e01333217152623220615118e06aa08042b70662425243c707603 +3e728ab8258b660aa50ac1b4fdcc00000001006803c60120058100030019400b030202040520 +0001000203003fcd5d111201391133313001230333010a8d15b803c601bb00010005fe5703fc +043a001601e440ff13080f11120a0909030f1204181708130f131711090f00055059001b9218 +01821801741801641801521801421801341801241801121801021801f41801e41801d21801c2 +1801b41801a41801921801821801741801641801561801421801341801241801161801021801 +67f41801e41801d61801c21801b41801a4180196180182180174180164180156180142180134 +1801241801161801021801f41801e41801d61801c2180101b01801a018019418018418017018 +01601801541801441801301801201801141801041801f01801e01801d41801c41801b01801a0 +180194180184180170180160180154180144180130180120180114180104180137e018405a01 +d41801c41801a01801941801841801601801541801441801201801141801041801e01801d418 +01c41801a0180194180184180160180102501801301801201801001801c01801901801801801 +5018012f1801101801001801075e5d5d5d5d5d5d5d717171715f717171717171717272727272 +727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171717171715f71 +717171727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d7171 +7171717171717171003f2b00183f331133331133111201173911331133113333313013222735 +1633323f010133131e0217371333010e02bf4a32262ea86211fe53c0e4050e4c0346edbefe60 +43748dfe570b8706f72b0435fdaa0e27de0dc502b1fbc6ada9530000000100bb0000017e00db +00030017400a030000040500019b5b00002f2b111201391133313033353315bbc3dbdb000000 +0001008e000003ee05cc00180060403b1511111208071207191a13000003120715030d505903 +10d01a01c01a01b01a01f01a01b01a01ff1a01e01a01d01a01c01a01b01a01a01a01701a015d +5d5d5d5d5d5d7171727272003f2b00183f3312393f11120139391133113311333130013e0133 +321615112311342e01232206151123113311140607013d3aa37db0a7b52a60557f99b4b40701 +03816a63afcefd2f02ae726f34b095fd8205ccfe7e3d820a000200a8000005680581000d0016 +0057402f010c0c1309130303040e09000d0d09040317180c0213025f591313000505125f5905 +030400128018017018012018015d5d5d003f323f2b11120039182f2b11003311120117391133 +113311331133111239113331302101211123112132041514060701033426232111213236048c +fe92fe49bf0297ee0103b7a10190f8a79dfe3b01cd97a50249fdb70581d5be9dd61cfda103ec +7b81fdf88d0000010088000003ee044e001a0061403c1209090a001a0a1a1b1c121600160550 +5916100d0f0a0015d01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01 +a01c01701c015d5d5d5d5d5d5d7171727272003f323f3f2b1112003911120139391133113311 +3331302111342e01232206151123113427331e0217333e01333216151103392a5c598296b406 +aa01020302033ea379b2a502ae6b7634b29efd8d0353bd2a052c394f705db1ccfd2f05cc05cc +007d058100150079058100150000000000000000000000000000043a001400770000ffec0000 +0000ffec00000000ffec0000fe57000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000008000000000000b400bd00af00a00000 -000000000000000000000088007e000000ac00000000000000000000000000bf00c300ab0000 -0000009b008d000000000000000000000000000000000000000000000000000000b900aa0000 -00000000009400990087000000000000000000000000000000000000000000000000006a0083 -008d00a400b4000000000000000000000060006a0079009800ac00b800a700000122013300c3 -006b00000000000000db00c90000000000000000000000000000000000000000000001e101c9 -009200a8006b009200b7006b009b0000027b02f200920252006e02d703810082008900a0009f -0169008f0000016000a4015b005e0082000000000000005e0065006f00000000000000000000 -00000000008a009000a5007a0080000000000000000000000581fff3000dfcb300830089008f -00960069007105cc000ffc1efff2003404e6000dfed400bf031f00a700ae00b5000000000081 -00000000000000000748036a02b60202fd930000009100670091006101d90000028d03410000 +0000000000000000000000000000000008000000000000b400bd00af00a00000000000000000 +000000000088007e000000ac00000000000000000000000000bf00c300ab00000000009b008d +000000000000000000000000000000000000000000000000000000b900aa0000000000000094 +00990087000000000000000000000000000000000000000000000000006a0083008d00a400b4 +000000000000000000000060006a0079009800ac00b800a700000122013300c3006b00000000 +000000db00c90000000000000000000000000000000000000000000001e101c9009200a8006b +009200b7006b009b0000027b02f200920252006e02d703810082008900a0009f0169008f0000 +016000a4015b005e0082000000000000005e0065006f0000000000000000000000000000008a +009000a5007a0080000000000000000000000581fff3000dfcb300830089008f009600690071 +05cc000ffc1efff2003404e6000dfed400bf031f00a700ae00b5000000000081000000000000 +00000748036a02b60202fd930000009100670091006101d90000028d03410000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000006810468001404cb0000ffecffd3fe7f008300db00aa00ba -00a000cf40475b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a -393837363531302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201 -002c20b0016045b003252011466123452361482d2c20451868442d2c45234660b0206120b046 -60b004262348482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b040 -6120b06660b004262348482d2c4523462361b0406020b02661b04061b004262348482d2c0110 -203c003c2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d4423 -5920b0042651582320b00d44235921212d2c20204518684420b001602045b04676688a456044 -2d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b1 -0228453ab10200080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c -2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062 -602b0c642364615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b0 -2c234445b02b23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023 -208af500b0016023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f500ed -ec2d2cb00243b001525821212121211b462346608a8a462320468a608a61b8ff806223201023 -8ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b003 -2546524bb013515b58b0022546206861b00325b003253f2321381b2111592d2c2045b0032546 -5058b0022546206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c -6423648bb84000622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0 -c051580c6423648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c -4b53588ab004254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a1211 -20392f592d2c4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344 -b0042610b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f59 -2d2c4523456023456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045 -b04061441b2121592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b -2121592d2c4b515820b0032545695358441b2121591b2121592d2c45b01443b0006063b00160 -69442d2cb02f45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b13420 -1bb3330034005944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b040 -59b001615923586559b02923442310b029e01b2121212121592d2cb0024354584b53234b515a -58381b2121591b21212121592d2cb0164358b004254564b020606620581b21b04059b0016123 -581b6559b0292344b00525b00825082058021b0359b0042510b005252046b0042523423cb004 -25b0072508b0072510b006252046b00425b0016023423c2058011b0059b0042510b00525b029 -e0b02920456544b0072510b00625b029e0b00525b00825082058021b0359b00525b003254348 -b00425b0072508b00625b00325b0016043481b2159212121212121212d2c02b00425202046b0 -04252342b0052508b003254548212121212d2c02b0032520b0042508b0022543482121212d2c -452320451820b00050205823652359236820b040505821b04059235865598a60442d2c4b5323 -4b515a5820458a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b -2121592d2cb000214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb0024354 -58b0472b1b212121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b2121 -21592d2c208a08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038111b -21592d2c014623466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a23 -49648a2353583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b12301 -8851b1400188535a58b910000020885458b202010243604259b12401885158b9200000408854 -58b2020202436042b12401885458b2022002436042004b014b5258b2020802436042591bb940 -000080885458b202040243604259b94000008063b80100885458b202080243604259b9400001 -0063b80200885458b202100243604259b12601885158b94000020063b80400885458b2024002 -43604259b94000040063b80800885458b2028002436042595959595959b10002435458400a05 -40084009400c020d021bb10102435458b2054008ba010000090100b30c010d011bb180024352 -58b2054008b80180b109401bb2054008ba01800009014059b9400000808855b94000020063b8 -040088555a58b30c000d011bb30c000d0159595942424242422d2c451868234b515823204520 -64b04050587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060c -b00a236542b00b234201b001233f00b002233fb10102060cb006236542b0072342b00116012d -2cb080b0024350b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d -0001000000021999142b7f845f0f3cf5001f080000000000c840f99a00000000dcb67271fba6 -fd930a6a07d700000008000200010000000000010000073efe4e00430ab4fba6fa7a0a6a0001 -00000000000000000000000000000017060000cd047300570473008401c7008a0400000502aa -007f02aa000c04730085047300560239001f04730057023900b8023900000400005704000039 -040000070473005606aa00880473008805c7fffd02aa00880187006801c70089000000000000 -004c0000016c0000023c000002cc0000050400000564000005c80000067c00000740000007c8 -0000089c000008e8000008e8000009a800000a8c00000c1800000cb400000eac00000f600000 -1160000011c4000011f80000128c00010000001701520054005c000600020010002f005c0000 -02a402040004000141210009013f000101390055013e000101390055014201400014001f0141 -0140001f001f013b0033013a00550138003301390055004001070001001f01070001009f0104 -40aa01c0fd01affd0100fd010a4ffb0120fb01f550281ff246281ff1462a1ff0462b1f5fef7f -ef020fef4fef5fef8fefafef050be5e41e1fe3e2461f0fe20140e246161fe1e0461fcfe0dfe0 -efe00340e0333646e046181feeedff1fed01e855ec48eb55ea320055e9e8e855e7480055e600 -ff1fdd3ddf55df010355de3d0355dc03ff1f0fd51fd5020fd51fd50240ca181b46cfc201bdc0 -3c1fc150261fbcbe281fffb90150b870b880b803b8ffc040ffb81232461fb73fb74fb76fb77f -b79fb7afb70718b60170b2a0b2b0b2030fb20190b501b0b5010fb501080fb33fb3efb30380b0 -90b002b0b0c0b0d0b0032faf3faf02a0adb0ad02c0add0ad022fac3fac029fab01c0aad0aa02 -4fa98fa9022fa96fa9bfa9ffa9049c9b241f509b016f9601bf960196461d1f9594171f0f941f -947f948f94ff94053091409102809101708f808f02908f01c08fd08f024f8c5f8c6f8c038646 -ff1f9f85018483311f74733f1f7350261f6f6e3c1f6e46351f1a011855193318550733035506 -03ff1f6050261f5f50261f5c46311f5b5a481f5a46311f1332125505010355043203556c0301 -0c033c034c036c037c0305ef51ff4064510240513538464051252846cf50014946201f484635 -1f4746351faf4601df46ef46028046011632155511010f5510320f55020100550100011f1f0f -3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f0001801601 -0501b80190b154532b2b4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000 -555a5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358 -b0101db11600425973747374752b2b2b2b2b017374752b2b2b00742b2b7373752b2b2b012b2b -2b002b2b2b2b2b2b012b2b002b2b012b732b00747374757374732b012b747500732b73740173 -737400737474737473015e73737473730073732b7373012b002b012b00732b74752b2b2b2b2b -2b2b2b2b2b2b012b2b742b2b5e732b002b5e7374012b2b2b002b73735e73737301737373002b -2b2b2b2b2b185e0000> +000000000000000006810468001404cb0000ffecffd3fe7f008300db00aa00ba00a000cf4047 +5b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531 +302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201002c20b00160 +45b003252011466123452361482d2c20451868442d2c45234660b0206120b04660b004262348 +482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b0406120b06660b0 +04262348482d2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c +20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651 +582320b00d44235921212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a +432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab102 +00080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360 +442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364 +615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b +23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b001 +6023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb00243 +b001525821212121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70 +456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524bb013 +515b58b0022546206861b00325b003253f2321381b2111592d2c2045b00325465058b0022546 +206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb840 +00622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423 +648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004 +254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c +4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00e +f68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c45234560 +23456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b21 +21592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b +515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f +45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb333003400 +5944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b001615923 +586559b02923442310b029e01b2121212121592d2cb0024354584b53234b515a58381b212159 +1b21212121592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b029 +2344b00525b00825082058021b0359b0042510b005252046b0042523423cb00425b0072508b0 +072510b006252046b00425b0016023423c2058011b0059b0042510b00525b029e0b029204565 +44b0072510b00625b029e0b00525b00825082058021b0359b00525b003254348b00425b00725 +08b00625b00325b0016043481b2159212121212121212d2c02b00425202046b004252342b005 +2508b003254548212121212d2c02b0032520b0042508b0022543482121212d2c452320451820 +b00050205823652359236820b040505821b04059235865598a60442d2c4b53234b515a582045 +8a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb0 +00214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b21 +2121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a +08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c0146 +23466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a235358 +3c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188 +535a58b910000020885458b202010243604259b12401885158b920000040885458b202020243 +6042b12401885458b2022002436042004b014b5258b2020802436042591bb940000080885458 +b202040243604259b94000008063b80100885458b202080243604259b94000010063b8020088 +5458b202100243604259b12601885158b94000020063b80400885458b202400243604259b940 +00040063b80800885458b2028002436042595959595959b10002435458400a0540084009400c +020d021bb10102435458b2054008ba010000090100b30c010d011bb18002435258b2054008b8 +0180b109401bb2054008ba01800009014059b9400000808855b94000020063b8040088555a58 +b30c000d011bb30c000d0159595942424242422d2c451868234b51582320452064b04050587c +59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b0 +0b234201b001233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b00243 +50b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d000100000002 +1999e39168005f0f3cf5001f080000000000c840f99a00000000dd7b2e16fba6fd930a6a07d7 +00000008000200010000000000010000073efe4e00430ab4fba6fa7a0a6a0001000000000000 +00000000000000000021060000cd0473009c02390000023900bb047300850473008404730056 +047300570239001f0473005702aa007f01c7008a04e3002e01c7008906aa008802aa000c0473 +0067023900b80400005704730056040000390473004e0473002f047300520473006805c7fffd +02aa00880187006804000005023900bb0473008e05c700a804730088000000000000004c0000 +00a4000000a4000000f0000001a4000002740000033800000458000004e0000005b400000614 +000006a4000007fc0000089000000a8800000aec00000b8800000bd400000c9400000d300000 +0e1400000ef000000f7400001030000010f4000012f4000013580000138c000015c4000015f4 +000016a4000017500000180400010000002101520054005c000600020010002f005c000002a4 +02040004000141210009013f000101390055013e000101390055014201400014001f01410140 +001f001f013b0033013a00550138003301390055004001070001001f01070001009f010440aa +01c0fd01affd0100fd010a4ffb0120fb01f550281ff246281ff1462a1ff0462b1f5fef7fef02 +0fef4fef5fef8fefafef050be5e41e1fe3e2461f0fe20140e246161fe1e0461fcfe0dfe0efe0 +0340e0333646e046181feeedff1fed01e855ec48eb55ea320055e9e8e855e7480055e600ff1f +dd3ddf55df010355de3d0355dc03ff1f0fd51fd5020fd51fd50240ca181b46cfc201bdc03c1f +c150261fbcbe281fffb90150b870b880b803b8ffc040ffb81232461fb73fb74fb76fb77fb79f +b7afb70718b60170b2a0b2b0b2030fb20190b501b0b5010fb501080fb33fb3efb30380b090b0 +02b0b0c0b0d0b0032faf3faf02a0adb0ad02c0add0ad022fac3fac029fab01c0aad0aa024fa9 +8fa9022fa96fa9bfa9ffa9049c9b241f509b016f9601bf960196461d1f9594171f0f941f947f +948f94ff94053091409102809101708f808f02908f01c08fd08f024f8c5f8c6f8c038646ff1f +9f85018483311f74733f1f7350261f6f6e3c1f6e46351f1a01185519331855073303550603ff +1f6050261f5f50261f5c46311f5b5a481f5a46311f1332125505010355043203556c03010c03 +3c034c036c037c0305ef51ff4064510240513538464051252846cf50014946201f4846351f47 +46351faf4601df46ef46028046011632155511010f5510320f55020100550100011f1f0f3f0f +5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501 +b80190b154532b2b4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a +5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b010 +1db11600425973747374752b2b2b2b2b017374752b2b2b00742b2b7373752b2b2b012b2b2b00 +2b2b2b2b2b2b012b2b002b2b012b732b00747374757374732b012b747500732b737401737374 +00737474737473015e73737473730073732b7373012b002b012b00732b74752b2b2b2b2b2b2b +2b2b2b2b012b2b742b2b5e732b002b5e7374012b2b2b002b73735e73737301737373002b2b2b +2b2b2b185e0000> ] def /f-1-0 currentdict end definefont pop %%EndResource %%EndSetup %%Page: 1 1 %%BeginPageSetup -%%PageBoundingBox: 7 8 458 410 +%%PageBoundingBox: 7 7 458 428 %%EndPageSetup -q 7 8 451 402 rectclip -1 0 0 -1 0 417 cm q +q 7 7 451 421 rectclip +1 0 0 -1 0 435 cm q 1 g 115.5 7.5 53.801 29.25 re f 0 g @@ -618,106 +700,116 @@ BT ET [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -142.875 37.5 m 142.875 409.5 l S Q +142.875 37.5 m 142.875 427.5 l S Q 1 g -217.5 78.75 53.801 29.25 re f +199.5 75 87.398 29.25 re f 0 g [] 0.0 d q 1 0 0 1 0 0 cm -217.5 78.75 53.801 29.25 re S Q +199.5 75 87.398 29.25 re S Q BT -9.75 0 0 -9.75 228.147949 93.375 Tm +9.75 0 0 -9.75 207.081482 89.625 Tm /f-0-0 1 Tf -(System)Tj +(IteratingSystem)Tj ET [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -244.875 108.75 m 244.875 409.5 l S Q +244.125 105 m 244.125 427.5 l S Q 1 g -343.5 168.75 53.801 29.25 re f +343.5 193.5 53.801 29.25 re f 0 g [] 0.0 d q 1 0 0 1 0 0 cm -343.5 168.75 53.801 29.25 re S Q +343.5 193.5 53.801 29.25 re S Q BT -9.75 0 0 -9.75 358.208862 183.375 Tm +9.75 0 0 -9.75 358.208862 208.125 Tm /f-0-0 1 Tf (Entity)Tj ET [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -370.875 198.75 m 370.875 409.5 l S Q +370.875 223.5 m 370.875 427.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -142.5 133.5 m 239.25 133.5 l S Q -231.629 136.656 m 239.25 133.5 l 231.629 130.344 l f +142.5 157.5 m 238.5 157.5 l S Q +230.879 160.656 m 238.5 157.5 l 230.879 154.344 l f q 1 0 0 1 0 0 cm -231.629 136.656 m 239.25 133.5 l 231.629 130.344 l 231.629 136.656 l S Q +230.879 160.656 m 238.5 157.5 l 230.879 154.344 l 230.879 160.656 l S Q BT -9.75 0 0 -9.75 168.466003 130.875 Tm +9.75 0 0 -9.75 144.375 151.875 Tm /f-1-0 1 Tf -(apply\(\))Tj +[(1 : update\(deltaT)37(ime\))]TJ ET 1 g -239.25 133.5 9.75 240 re f +238.5 157.5 9.75 210 re f 0 g q 1 0 0 1 0 0 cm -239.25 133.5 9.75 240 re S Q +238.5 157.5 9.75 210 re S Q q 1 0 0 1 0 0 cm -249 223.5 m 271.5 223.5 l 271.5 238.5 l 254.25 238.5 l S Q -261.871 235.344 m 254.25 238.5 l 261.871 241.656 l f +248.25 247.5 m 270.75 247.5 l 270.75 262.5 l 253.5 262.5 l S Q +261.121 259.344 m 253.5 262.5 l 261.121 265.656 l f q 1 0 0 1 0 0 cm -261.871 235.344 m 254.25 238.5 l 261.871 241.656 l 261.871 235.344 l S Q +261.121 259.344 m 253.5 262.5 l 261.121 265.656 l 261.121 259.344 l S Q BT -9.75 0 0 -9.75 277.125 235.125 Tm +9.75 0 0 -9.75 271.875 259.125 Tm /f-1-0 1 Tf -(update\(e, cs, v\))Tj +(2 : update\(e, comps\))Tj ET 1 g -244.5 238.5 9.75 21 re f +243.75 262.5 9.75 21 re f 0 g q 1 0 0 1 0 0 cm -244.5 238.5 9.75 21 re S Q +243.75 262.5 9.75 21 re S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -249 259.5 m 271.5 259.5 l 271.5 274.5 l 249 274.5 l S Q +248.25 283.5 m 270.75 283.5 l 270.75 298.5 l 248.25 298.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -256.621 271.344 m 249 274.5 l 256.621 277.656 l S Q +255.871 295.344 m 248.25 298.5 l 255.871 301.656 l S Q BT -9.75 0 0 -9.75 277.125 271.125 Tm +9.75 0 0 -9.75 276.375 295.125 Tm /f-1-0 1 Tf -(components)Tj +(3 : comps)Tj ET q 1 0 0 1 0 0 cm -249 307.5 m 365.25 307.5 l S Q -357.629 310.656 m 365.25 307.5 l 357.629 304.344 l f +248.25 331.5 m 365.25 331.5 l S Q +357.629 334.656 m 365.25 331.5 l 357.629 328.344 l f q 1 0 0 1 0 0 cm -357.629 310.656 m 365.25 307.5 l 357.629 304.344 l 357.629 310.656 l S Q +357.629 334.656 m 365.25 331.5 l 357.629 328.344 l 357.629 334.656 l S Q BT -9.75 0 0 -9.75 259.875 304.875 Tm +9.75 0 0 -9.75 270.375 327.375 Tm /f-1-0 1 Tf -(update\(components\))Tj +(4 : update\(comps\))Tj ET 1 g -365.25 307.5 9.75 24 re f +365.25 331.5 9.75 24 re f 0 g q 1 0 0 1 0 0 cm -365.25 307.5 9.75 24 re S Q +365.25 331.5 9.75 24 re S Q [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -370.5 331.5 m 249 331.5 l S Q +370.5 355.5 m 248.25 355.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -256.621 328.344 m 249 331.5 l 256.621 334.656 l S Q +255.871 352.344 m 248.25 355.5 l 255.871 358.656 l S Q +BT +9.75 0 0 -9.75 301.125 367.875 Tm +/f-1-0 1 Tf +(5)Tj +ET [ 2.25 2.25] 0 d q 1 0 0 1 0 0 cm -244.5 373.5 m 142.5 373.5 l S Q +243.75 367.5 m 142.5 367.5 l S Q [] 0.0 d q 1 0 0 1 0 0 cm -150.121 370.344 m 142.5 373.5 l 150.121 376.656 l S Q +150.121 364.344 m 142.5 367.5 l 150.121 370.656 l S Q +BT +9.75 0 0 -9.75 184.875 379.875 Tm +/f-1-0 1 Tf +(6)Tj +ET q 1 0 0 1 0 0 cm -7.5 61.5 450 330 re S Q +7.5 61.5 450 354 re S Q 1 g 7.5 61.5 m 7.5 78 l 106.43 78 l 114.68 69.75 l 114.68 61.5 l 7.5 61.5 l f @@ -733,16 +825,33 @@ BT [()9378(loop)]TJ ET q 1 0 0 1 0 0 cm -25.5 151.5 420 204 re S Q +19.5 121.5 426 282 re S Q +1 g +19.5 121.5 m 19.5 138 l 128.496 138 l 136.746 129.75 l 136.746 121.5 l +19.5 121.5 l f +0 g +q 1 0 0 1 0 0 cm +19.5 121.5 m 19.5 138 l 128.496 138 l 136.746 129.75 l 136.746 121.5 l +19.5 121.5 l S Q +BT +9.75 0 0 -9.75 38.047485 134.625 Tm +/f-1-0 1 Tf +(system.shouldRun\(\))Tj +/f-0-0 1 Tf +-1.517691 0 Td +(alt)Tj +ET +q 1 0 0 1 0 0 cm +31.5 175.5 402 216 re S Q 1 g -25.5 151.5 m 25.5 168 l 119.57 168 l 127.82 159.75 l 127.82 151.5 l 25.5 - 151.5 l f +31.5 175.5 m 31.5 192 l 125.57 192 l 133.82 183.75 l 133.82 175.5 l 31.5 + 175.5 l f 0 g q 1 0 0 1 0 0 cm -25.5 151.5 m 25.5 168 l 119.57 168 l 127.82 159.75 l 127.82 151.5 l 25.5 - 151.5 l S Q +31.5 175.5 m 31.5 192 l 125.57 192 l 133.82 183.75 l 133.82 175.5 l 31.5 + 175.5 l S Q BT -9.75 0 0 -9.75 52.183594 164.625 Tm +9.75 0 0 -9.75 58.183594 188.625 Tm /f-1-0 1 Tf (world's entities)Tj /f-0-0 1 Tf diff --git a/doc/img/SystemBuilder.eps b/doc/img/SystemBuilder.eps new file mode 100644 index 00000000..3e8213d2 --- /dev/null +++ b/doc/img/SystemBuilder.eps @@ -0,0 +1,969 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.17.4 (https://cairographics.org) +%%CreationDate: Tue Oct 12 22:35:18 2021 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 151 7 705 296 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%BeginResource: font LiberationSans-Bold +11 dict begin +/FontType 42 def +/FontName /LiberationSans-Bold def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 66 /B put +Encoding 69 /E put +Encoding 83 /S put +Encoding 97 /a put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 103 /g put +Encoding 105 /i put +Encoding 108 /l put +Encoding 109 /m put +Encoding 110 /n put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 117 /u put +Encoding 120 /x put +Encoding 121 /y put +/CharStrings 19 dict dup begin +/.notdef 0 def +/S 1 def +/y 2 def +/s 3 def +/t 4 def +/e 5 def +/m 6 def +/B 7 def +/u 8 def +/i 9 def +/l 10 def +/d 11 def +/r 12 def +/E 13 def +/x 14 def +/c 15 def +/n 16 def +/g 17 def +/a 18 def +end readonly def +/sfnts [ +<000100000009008000030010637674206d5f6ba100000f10000002886670676d7e61b6110000 +1198000007b4676c79662b2e54c20000009c00000e74686561640b8df5290000194c00000036 +686865610e1803860000198400000024686d74785607074f000019a80000004c6c6f63610000 +9884000019f4000000506d617870042b053400001a4400000020707265708aa104b900001a64 +00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e90000000001003bffec05060596002a0052402f0c001d1c2216070606161c00042c2b0c2203 +1919205f591d1d1904030a5f5910072007300703300740070207070313003f332f5d712b0018 +3f332f2b111200393911120117391133113311331133313001140421202427251e0133203534 +2e01272e0435342421200417052e01232015141e01171e030506fecdfed7fef1fecc2c011d1d +a89501354781b79e7c644627011f01120106010726fee216877efef43970abcbaf66360196cf +dbc0c32f7065bc3c4e3425252d3d56744bbfcba4bd275b5ca8374631252b4961870000010010 +fe570468043a001501ba40ff0b0a13090e1112120e030a041617110a0f130e0900055059001b +96170186170173170163170100501701421701321701241701141701061701f21701e01701d0 +1701c21701b41701a41701961701821701741701601701521701421701341701261701121701 +04170167f41701e21701d21701c41701b41701a2170194170184170176170166170154170144 +1701321701221701141701061701f61701d41701c61701b01701a21701921701841701761701 +661701401701321701221701141701061701f61701d41701c21701b2170101a0170190170184 +170160170154170144170130170120170114170104170137f41701cb1701b417017417010417 +01403bf41701e41701cb1701bb1701ab17019417017417013b170124170100170102f01701e0 +1701bf1701801701701701501701301701101701001701075e5d5d5d5d5d5d5d5d5d5f717171 +7171717171717172727272725e5d5d5d5d5d5d5d5d5d5d5f5d5d5d5d71717171717171717171 +71717171727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d71 +71717171715f71717171003f2b00182f33333f33111201173911331133331133313001222735 +1633323e013701211316173f011321010e01011b654c352c3c4f3f27fe540129aa283d1941a0 +0126fe5456b9fe570dc808265869042ffe056de15feb01fffb8dd0a0000000010048ffec041f +044f002800724045070621141b1a0d00001a140604292a210d1703171e5159c21b01601b0103 +0f1b1f1b020a041b1b1710030a5159140724070207070316502a01b02a01302a01402a012f2a +015d5d717172003f332f5d2b00183f332f5f5e5d5f5d5d2b1112003939111201173911331133 +11331133313001140423222627371e01333236353426272e0235343633321617072e01232206 +151416171e03041ffeffe3dfed27f7156780766c5768eea657efdbc1eb1df90c5e6664644d5b +7fc57747013c9db38d95254d403c40343d152f51815e9bad968e1a4241333c2f37121a374c77 +00010019ffee029105380015003b401d130c0c0a0d080d040416170d0506054f590a06080806 +0f00114f590016003f2b00183f332f11332b1100331112013911333311333311333130052226 +3511233533373315331523111416333237150601a47c86899758b0cdcd3c3f213d6812878902 +7ebefefebefdce4f4b0eae22000000020050ffec042d044e00120019006f4043170a1011160b +0b0303110a031b1a160b525916211011480f16010e0516160006061352590610000e51597f10 +01101001101000169f1b016f1b015f1b014f1b012f1b015d5d5d5d5d003f322f5d5d2b00183f +2b11120039182f5f5e5d2b2b1112011739113311331133113331300522001110003332121115 +211416333237050201220607212e01024af4fefa010af4e9f6fd4a756c9527010973fea0636b +0301a4086e1401210115010c0120fecbfed6089ea18117feda03b18a7c838300000100870000 +069e044f00260093405e172600001f081f1e1007081e08282722031403505910171a0314100c +0f1f080015e42801d428018428015428013b2801db2801bb28019b28015428013b28012f2801 +021f2801002801e02801d02801b028019f28018028016028012f28015d5d5d5d5d5d5d71715f +7171717171717272727272003f32323f3f17332b110033111201393911333311331112391133 +33313021111023220615112111342627211e0115333e01333217333e01333216151121111023 +22060711030ca4556bfee70503010c030a04349b6cf83506379a779ea6fee9a4526905025f01 +1dae8afdbc0348576f2c13a51f7c70ec7e6ed7c9fd51025f011d9f8cfdaf000300890000056a +0581000e0017001f008540510c1309131b1b040f0918000009040321200c141b141b5f590f14 +1f1402140514160c491414040505135f590503041c5f590412a0210190210180210170210160 +21015021014021013021013021012021015d5d7171717171717171003f2b00183f2b11120039 +182f2b5f5e5d2b11120039111201173911331133113311331112393130011404290111212004 +151406071e010134262321112132361334290111213236056afee0ff00fd3f02850102010985 +88abb3fe867977feb001527d7152fee4fe8a01818e830192c0d20581b3af78a51d14af01d55f +50fea357fe09c6fe6c6700000001007fffec045c043a0016004f402f0e070708001608161817 +0e121203505912160c1507000fa01801901801f01801b01801a01801901801701801ef18015d +71717171717272003f323f3f2b11003311120139391133113311333130011110333236351121 +111417212635230e0123222635110198c0667d011908fef40c0538ad77acb8043afda1fee3af +890244fcb88a6890477b70d3cc02af000002008f000001a805cc000300070056403603070700 +04040809050f0415010053590100500901400901b00901a009017f09016009011f0901ef0901 +d00901c00901b009018009015d5d5d5d5d71717171717272003f2b00183f3f11120139113333 +1133313013352115011121118f0119fee7011904fdcfcffb03043afbc6000001008f000001a8 +05cc00030046402d030000050401000015500501400501b00501a005017f05016005011f0501 +ef0501d00501c00501b005018005015d5d5d5d5d71717171717272003f3f1112013911333130 +331121118f011905ccfa340000020054ffec045c05cc00160021003e402017031212131d0913 +09222312000c1a4f590f0c10061f4f59030616001570230171003f3f332b00183f332b00183f +1112013939113311331133333130212e01352306232202111012333216173327112111141701 +34262322061510333236034c040b045bffbdced9c773a72d0202011908fee37572716edd6f7a +0f7928c401270109010d0125605fb2018bfb2064880223afbdb7bcfe90c30000000100870000 +02fe044f0016003e402508161600000f18170d125059080d10050f00159f18017f1801d01801 +af18015f18012f18015d5d5d5d7171003f3f3f332b1112013939113311333130331134262721 +1e0115333e02333217152623220615118f0503010c030a0429405842362144346975033c5977 +2e12b71e725d2d0feb0faaa7fded000000010089000005060581000b0074404a050909000b00 +010b060a030700040c0d05085f590f057f059f05030f058f05ff05030f03051615490f050114 +0505160c490505000101045f59010300095f590012400d01300d01200d015d5d5d003f2b0018 +3f2b11120039182f2b5f5e5d2b5f5e5d712b11120117395f5e5d113311333130331121152111 +211521112115890454fcd302f0fd1003560581e4fe9ee4fe8de400000001000e00000464043a +000b00404024000b08090a04010706050203030507090b050d0c050f0015f00d01e00d019f0d +014f0d015d5d5d71003f3f11120117391133113311333333113311333130210b01210901211b +012109010333fcfefed5018cfe87012fe7e60131fe87018f0188fe78022f020bfe9e0162fdf8 +fdce000000010050ffec0437044e00180042402414150a090f03030915031a19060d4f590a0a +061000146014020d0314140000114f590016003f2b110033182f5f5e5d3f332f2b1112011739 +113311331133313005220011100033321617052e012322111033323637050e020252f6fef401 +0ef8bffa20fee50c6058d9dd506c0d011a0f81d21401250106010c012bc0a90e5363fe95fe8a +65640d6fae5f00000001008700000464044f0018004f402f00181007070808181a1910141403 +505914100c0f080015a01a01901a01f01a01b01a01a01a01901a01701a01ef1a015d71717171 +717272003f323f3f2b1100331112013939113311331133313021111023220615112111342627 +211e0115333e013332161511034cc1667dfee70503010c030a0439ac77acb8025f011daf89fd +bc0348576f2c13a51f7c70d4ccfd510000020054fe4e045a044f0021002b0061403a18220a0a +1f0403271212031f032d2c1b0f15254f591715100f294f590c0f150007515956046604760403 +2204320402050415040204001b702d0171003f325d5d5d2b00183f332b00183f332b00183f11 +12011739113311331133113333313001222627251e013332363d013723062322021110123332 +1733343637210615111404033426232211103332360254c6f11c01190f6350756c02025dffbd +d0d6ccec5b050905010a06fefa0f776ee1df7077fe4e978c21414a908e396bc7011c01080109 +0120c32378136c8efce1e7ec03dea7bbfe98fe9fbb0000000002003cffec0480044e00260033 +006d403f2427270707150e0f2c03030f1503353406285259060600590e690e022d0e01030f0e +1f0e0209040e12120b51591210192f002f4f5924210016bf35014f35015d71003f32322b1100 +33183f2b1100335f5e5d5f5d5d1239182f2b1112011739113311331133113311333130052226 +3534363f0135342623220607253e0133321615111416333237150e0323222627230613070e02 +15141633323e013501899db0dbd0e94a544e4909fedb1bebcbcdde2930201e1928282d1e6a65 +0a0676599062522b473b426d3e14ab9ba8b00204376a6747520e9ea3cabafe765b450698060a +06046865d50209020423483c4d4b487f470005cc05cc007d0581001500790581001500000000 +00000000000000000000043a001400770000ffec00000000ffec00000000ffec0000fe57fff7 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0800000000000119012500f500eb0000000000000000000000c100d300ba00b000cf00000000 +00000000000000000127012901060000011200e400f400c60000000000000000000000000000 +000000000000000000000119011f014c0000000000df00d100c500b500000000000000000000 +000000000000000000000000010200a901fd00d80119008000b701fd00000000013f00db015d +012500aa00800075008d01fc0179012100a001100000000001310119010e0104000000000000 +000000000000000000000000013d01ff00e00106009400e00094014400e005730319000000d8 +02c5009c038102cd00cb00f4004e028d000000ff00d700cc01300145007300b400a600000000 +00730080008d000000000000000000000000030000a200980083008d000000000000000005ae +febc0581fd300011fff600b600bc00c60000007f008a0060000000000000000000f001ee0190 +000002190108011500000000000000be00000000000000000748036a02b60202fd9300000091 +00670091006101d90000028d0341000000000000000000000000000000aafe6ffe6801050093 +009800e20151008f00be00aefeb9fea4005e00af02d5005500f200a604150601000003e10010 +02fa000ffed401eafff300b8000000000363000bfd0ffff500000000000006810477001504d9 +0000ffecffc5fe7f007500cd00f2010200d5011940475b5a59585554535251504f4e4d4c4b4a +494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f1814 +11100f0e0d0b0a090807060504030201002c20b0016045b003252011466123452361482d2c20 +451868442d2c45234660b0206120b04660b004262348482d2c4523462361b0206020b02661b0 +2061b004262348482d2c45234660b0406120b06660b004262348482d2c4523462361b0406020 +b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd442320b8015a51582320 +b08d44235920b0ed51582320b04d44235920b0042651582320b00d44235921212d2c20204518 +684420b001602045b04676688a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d +2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c2045b00325456164b05051 +5845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b00743650a2d2c2069 +b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361592d2c8a03458a8a87b0 +112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845441b2121592d2c4b +515845441b2121592d2c01b005251023208af500b0016023edec2d2c01b005251023208af500 +b0016123edec2d2c01b0062510f500edec2d2cb00243b001525821212121211b462346608a8a +462320468a608a61b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0 +468c59b0106068013a592d2c2045b0032546524bb013515b58b0022546206861b00325b00325 +3f2321381b2111592d2c2045b00325465058b0022546206861b00325b003253f2321381b2111 +592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b08051580c6423648bb820 +00621bb200402f2b59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b00260 +2d2c0c6423648bb84000626023212d2c4b53588ab004254964234569b0408b61b08062b02061 +6ab00e23442310b00ef61b21238a121120392f592d2c4b535820b0032549646920b00526b006 +2549642361b08062b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00e +ed1b8ab00426111220392320392f2f592d2c4523456023456023456023766818b08062202d2c +b0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1302f4523456160b00160 +69442d2c4b5158b02f2370b01423421b2121592d2c4b515820b0032545695358441b2121591b +2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c452320458a60442d2c452345 +60442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb0164358b00326458a5864 +66b01f601b64b020606620581b21b04059b001615923586559b02923442310b029e01b212121 +2121592d2cb0024354584b53234b515a58381b2121591b21212121592d2cb0164358b0042545 +64b020606620581b21b04059b0016123581b6559b0292344b00525b00825082058021b0359b0 +042510b005252046b0042523423cb00425b0072508b0072510b006252046b00425b001602342 +3c2058011b0059b0042510b00525b029e0b02920456544b0072510b00625b029e0b00525b008 +25082058021b0359b00525b003254348b00425b0072508b00625b00325b0016043481b215921 +2121212121212d2c02b00425202046b004252342b0052508b003254548212121212d2c02b003 +2520b0042508b0022543482121212d2c452320451820b00050205823652359236820b0405058 +21b04059235865598a60442d2c4b53234b515a5820458a60441b2121592d2c4b545820458a60 +441b2121592d2c4b53234b515a58381b2121592d2cb000214b5458381b2121592d2cb0024354 +58b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b2121 +2121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b515a5823381b2121592d +2c00b0022549b000535820b04038111b21592d2c014623466023466123201020468a61b8ff80 +628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb0 +12004b014b54422d2cb1020042b123018851b1400188535a58b910000020885458b202010243 +604259b12401885158b920000040885458b2020202436042b12401885458b202200243604200 +4b014b5258b2020802436042591bb940000080885458b202040243604259b94000008063b801 +00885458b202080243604259b94000010063b80200885458b202100243604259b12601885158 +b94000020063b80400885458b202400243604259b94000040063b80800885458b20280024360 +42595959595959b10002435458400a0540084009400c020d021bb10102435458b2054008ba01 +0000090100b30c010d011bb18002435258b2054008b80180b109401bb2054008ba0180000901 +4059b9400000808855b94000020063b8040088555a58b30c000d011bb30c000d015959594242 +4242422d2c451868234b51582320452064b04050587c59688a6059442d2cb00016b00225b002 +2501b001233e00b002233eb10102060cb00a236542b00b234201b001233f00b002233fb10102 +060cb006236542b0072342b00116012d2cb080b0024350b001b00243545b58212310b0201ac9 +1b8a10ed592d2cb0592b2d2c8a10e52d0001000000021999d1fed1455f0f3cf5001f08000000 +0000c849682600000000dd7b292bfc25fcfd0a6f084400010008000200010000000000010000 +073efe4e00430aaafc25fa7a0a6f000100000000000000000000000000000013060000cd0556 +003b047300100473004802aa001904730050071d008705c7008904e3007f0239008f0239008f +04e30054031d0087055600890473000e0473005004e3008704e300540473003c000000000000 +004c000001280000033800000424000004a4000005740000067c000007740000081000000890 +000008f00000099c00000a2400000ac800000b4800000be400000c8400000d7000000e740001 +0000001301520054005c000600020010002f005c0000034d0354000400014155013f00010139 +0055013e000101390055014201400014001f01410140001f001f013b0033013a005501380033 +0139005500a4013900f4013900020132003d0131005501310001012f00550130003d012f0055 +012c012900ff001f01290001012a00550128003d0127005501270001012a00550126003d0125 +005501250001012a00550123012200ff001f01220001012a0055012b003d012a005500500107 +0001002f0107000100af0104405001d0fd01bffd0110fd016ffb0140fb0180f590f5a0f503f1 +f0351f2ff09ff0025fef012fef5fef6fef9fefdfef05e6e4201fe5e43d1fe2e0271fe1e03d1f +df3ddd55de3d035500dd30dd02dd0103552f410b011e00010010011e0020011e0040011e0003 +ffc0011e4028191c46dc03ff1f00db01da043c1fd4d21c1fd3d2261f60d190d1c0d10360d190 +d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ffc0b4d10a0d460fb80116400f01bfbe261f40bb29 +414640bb222746b801214026b63d1f00b8016fb801b8b70a1f00b70100b720b740b760b770b7 +0540b760b790b7d0b7f0b705b80120400d483d1f00b560b502a0b5d0b502b8ffc0400eb50b0e +460fb25fb202b1033c1f2f410b0119003f0119004f01190003008f0119000100400119402826 +29461faf2faf3faf9faf040faf0140af0e164600ad70ad80ad03e0adf0ad02abaa351faa5026 +1fb9011b011ab23c1f00b8011ab6010fa9010fa801bc01170113003c001f0115407e503c1f9e +9b271f9d9b271f9c9b271f809b019846281f9f97af97029646351f0f941f94029390261f9291 +261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f8d010f8c01408c0b0f460f891f890286850f1f5f +850136824682027650261f7550261f7450261f7350261f2970011b7001037001f47001d670e6 +7002687001597001b8fff0407d700a0d466f6e481f6e46321f1a011855193318550733035506 +03ff1f6150261f605f321f5f50261f5e5a481f5c46271f5b5a781f5a46311f13321255050103 +55043203556f03010f033f034f036f037f03055f53014053282c4640531e224640531318466b +527b528b5203514f1c1f504f1c1f194f294f02594f694f02b80112402d46251f4946191f4846 +211f4746351ff846019846011c481b551632155511010f5510320f55020100550100ff1fb801 +11b21b091fb80110402d1b091f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f +0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff524bb007505bb00188 +b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb0325358b0601d +594bb0645358b0401d594bb0805358b0101db11600425973747374752b2b2b2b2b2b2b2b0173 +742b2b2b2b0073742b2b732b2b2b7373752b2b2b012b2b2b002b2b2b2b2b2b2b2b012b2b2b73 +737373747474002b2b2b2b0173732b73002b73732b732b2b73012b732b00732b2b2b2b2b7373 +732b012b2b0073742b73742b73742b73012b73742b007374752b73742b2b2b012b00732b2b73 +74012b2b002b732b2b73752b732b2b012b2b002b2b737401732b007373737373730173737300 +2b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> +] def +/f-0-0 currentdict end definefont pop +%%EndResource +%%BeginResource: font LiberationSans +11 dict begin +/FontType 42 def +/FontName /LiberationSans def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 32 /space put +Encoding 40 /parenleft put +Encoding 41 /parenright put +Encoding 43 /plus put +Encoding 44 /comma put +Encoding 45 /hyphen put +Encoding 58 /colon put +Encoding 60 /less put +Encoding 61 /equal put +Encoding 62 /greater put +Encoding 65 /A put +Encoding 66 /B put +Encoding 67 /C put +Encoding 68 /D put +Encoding 69 /E put +Encoding 76 /L put +Encoding 80 /P put +Encoding 83 /S put +Encoding 84 /T put +Encoding 85 /U put +Encoding 86 /V put +Encoding 87 /W put +Encoding 91 /bracketleft put +Encoding 93 /bracketright put +Encoding 97 /a put +Encoding 98 /b put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 102 /f put +Encoding 103 /g put +Encoding 104 /h put +Encoding 105 /i put +Encoding 108 /l put +Encoding 109 /m put +Encoding 110 /n put +Encoding 111 /o put +Encoding 112 /p put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 117 /u put +Encoding 119 /w put +Encoding 120 /x put +Encoding 121 /y put +Encoding 171 /guillemotleft put +Encoding 187 /guillemotright put +/CharStrings 48 dict dup begin +/.notdef 0 def +/plus 1 def +/e 2 def +/x 3 def +/c 4 def +/l 5 def +/u 6 def +/d 7 def +/i 8 def +/n 9 def +/g 10 def +/bracketleft 11 def +/E 12 def +/bracketright 13 def +/parenleft 14 def +/parenright 15 def +/colon 16 def +/space 17 def +/S 18 def +/y 19 def +/s 20 def +/t 21 def +/m 22 def +/B 23 def +/r 24 def +/L 25 def +/comma 26 def +/less 27 def +/C 28 def +/w 29 def +/h 30 def +/f 31 def +/o 32 def +/D 33 def +/a 34 def +/T 35 def +/W 36 def +/V 37 def +/equal 38 def +/greater 39 def +/U 40 def +/p 41 def +/A 42 def +/P 43 def +/b 44 def +/hyphen 45 def +/guillemotleft 46 def +/guillemotright 47 def +end readonly def +/sfnts [ +<000100000009008000030010637674204ada4bfa0000241c000002886670676d7e61b6110000 +26a4000007b4676c7966e083a41d0000009c00002380686561640b008bb100002e5800000036 +686865610d9403ad00002e9000000024686d7478ca87124a00002eb4000000c06c6f63610003 +60d000002f74000000c46d617870039f03e4000030380000002070726570fdae474900003058 +00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e90000000001006400b40447049e000b004340260900000603030d0ca90201030f025f02020c +060200040504ad5909d6070137078707020705b3003f335d5d332b110033335f5e5d5f5d1112 +013911333311333130011123112135211133112115029f93fe5801a89301a80260fe5401ac92 +01acfe54920000020057ffec0418044e0012001900774046131106071900000c0c0711031b1a +06060003190050590d190114041919090f0f1650590f10090350590916d01b01c01b01a01b01 +901b01801b01701b01601b01501b01301b01717171717171717171003f2b00183f2b11120039 +182f5f5e5d2b11120039182f1112011739113311331133113331300114163332363717022122 +0211101233201115272e012322060701149a94758d199e61fea8f0fbfbe901ddba0f90878399 +0601f7baca5e482dff00011e011a010c011efdc1188aab9daf99000000010017000003ea043a +000b015440a0000b08090a04010706050203030507090b050d0c840d01760d01440d540d640d +03360d01240d01160d01040d01f60d01e40d01d60d01c40d01b60d01a40d01760d860d960d03 +640d01060d160d260d460d560d0567060d460d560d860d960dc60dd60de60d08990dd90d0264 +0d01560d01440d01360d01240d01160d01040d01d60de60df60d03c40d01060d260d360d460d +0437660da60db60de60df60d050db8ffc040363d4248390d01220d0101000d100d02f40d01c0 +0dd00de00d03b40d01800d900da00d03740d01600d01540d01400d01340d01200d010db8ffc0 +4022121848a00d0102000d100d500d700d800d900d06070a04010407030208060f000215003f +333f331217391133015e5d5f5d2b71717171717171717171725f72722b725e5d5d5d71717171 +71717171725e5d5d5d5d5d5d5d5d5d7171717171717111121739113311331133333311331133 +31302109012309013309013309010321feddfedbc20181fe91c7010e010cc9fe91018601bcfe +44022c020efe5b01a5fdf4fdd20000010057ffec03ca044e001900664045000d141306070713 +0d031a1b101750591f147f148f14df140414141010200670068006d006e00605000610066006 +70068006c006d00607090306060a0a0350590a161f1b015d003f2b110033182f5f5e5d713f33 +2f5d2b1112011739113311331133313001141633323637170e0123220211101233321617072e +012322060113888960810fb615e0ace3eff0e0a6db1cb90e72698f800222d8d0686c0c9cba01 +1f01130111011fac970e5a6abe0000000001008a0000013e05cc000300764051030000050401 +000015f00501e00501df0501c00501b005019f05018005017005011f05010f0501f00501df05 +01c00501b00501a005019005014f0501ff0501e00501d00501c005018005017005011f05015d +5d5d5d5d5d5d7171717171717172727272727272727272003f3f111201391133313033113311 +8ab405ccfa34000000010085ffec03eb043a001a005f403b1208080b01190b191c1b12051605 +505916160d1509000fd01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c +01a01c01701c015d5d5d5d5d5d5d7171727272003f323f3f2b11003311120139391133113311 +3331300111141e01333236351133111417232e0227230e012322263511013a2a5c598296b406 +aa01020302033ea379b2a5043afd526b7634b29e0273fcadbd2a052c394f705db1cc02d10002 +0056ffec03ef05cc00160022005640311d000e0e0f17060f06242312150e00000b0308082050 +590810031a505903169024017024011f2401ff2401e02401c024015d5d5d717171003f2b0018 +3f2b1112003939183f3f1112013939113311331133333130250e012322021110213216173327 +1133111417232e0135011416333236353426232206033532a57acdc1018e7ba4320202b406ac +0307fdda7887998a8a978879ae685a0114011802365a627901c1fb13a93610742a0170e3c4d4 +dfd7c8c9000200890000013d05cc00030007006e40480307070004040809050f041501005359 +0100ff0901e00901df0901c00901b009019f09018009017009011f0901000901f00901df0901 +c00901b00901a009019009014f09011f09015d7171717171717172727272727272727272003f +2b00183f3f1112013911333311333130133533150311331189b4b4b40520acacfae0043afbc6 +00010088000003ee044e001a0061403c1209090a001a0a1a1b1c1216001605505916100d0f0a +0015d01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a01c01701c01 +5d5d5d5d5d5d5d7171727272003f323f3f2b1112003911120139391133113311333130211134 +2e01232206151123113427331e0217333e01333216151103392a5c598296b406aa0102030203 +3ea379b2a502ae6b7634b29efd8d0353bd2a052c394f705db1ccfd2f00020056fe5703ef044b +0020002e009f4064211709091f0403281111031f03302f1c0f170a140e1425505914100e2b50 +590e16000750591504010604010b04001b403001203001cf3001b03001903001203001003001 +50df3001c030014f3001a030018030012f30010f3001f03001d030010f3001085e5d5d5d7171 +71717272725e5d5d5d5d5d7171003f325e5d5d2b00183f2b00183f2b1112003939183f111201 +1739113311331133113333313001222627371e0133201135230e012322021110123332161733 +343637330615111003342e0123220615141633323e010224b1d21eb5127b64010d0233b277c7 +bbc9cd73a92e020804ab06b34883538a7e768f558448fe578b801a4b51013bae68690108011b +011f011169611e940736aafcc5fe3803c684bf65c8e0dec264bb000000010092fe57022905cc +00070026401405000603000308090104f55901000005f559001b003f2b00183f2b1112011739 +113331301311211523113315920197e9e9fe57077581f98d81000000000100a8000004fe0581 +000b00544032050909000a030700040c0d05085f598f0501ba050179058905020f0501080305 +05000101045f59010300095f590012200d015d003f2b00183f2b11120039182f5f5e5d5d5d71 +2b1112011739113311333130331121152111211521112115a8042dfc920332fcce039705819c +fe3c9afe159c000000010010fe5701a705cc00070026401402070401070309080504f5590500 +0001f559001b003f2b00183f2b111201173911333130133533112335211110e9e90197fe5781 +067381f88b0000000001007ffe58029e05cc000e0022401007000b0a03040a0400030f100a1b +0300003f3f111201173911331133113331301310123733060211101217232602117fb5bcaebb +afadbdaebdb40214012101cccbd0fe2cfeeafeebfe2ed3cc01cd011f0001000cfe58022b05cc +000e00224010070003040b0a00040a030f100a00031b003f3f11120117391133113311333130 +011002072336121110022733161211022bb5bcaebcaeafbbaebdb40210fedffe34cbd201d101 +17011701d2d1ccfe33fee1000000000200bb0000017e043a0003000700274013030707040004 +090804059c5b0401009c5b010f003f2b00182f2b111201393911331133313013353315033533 +15bbc3c3c3036bcfcffc95cfcf000001005dffec04f80596002d008e401f0c001d1c23160605 +05161c00042f2e0c10131648490c590c690c030f0c0123b8fff0403913164846235623662303 +0d23010c040c23031919205f596f1d01591d014b1d0103001d0109051d190403095f59600601 +520601440601060313003f335d5d5d2b00183f335f5e5d5f5d5d5d2b11120039395f5e5d5d2b +5d5d2b111201173911331133113311333130011404212003371e0133323635342e02272e0335 +342421321617072e0123220615141e01171e0504f8fecffeebfdfd52b920d0b3b9c93f729e60 +a7ad643501150102f0fe33bc1fae9aa9b24582c2418176674c2b0185c3d60166257f777f7b45 +56382616254a5b7a4fb5c493b1217065706f41553b2b0f1f2b3a547200010005fe5703fc043a +001601e440ff13080f11120a0909030f1204181708130f131711090f00055059001b92180182 +1801741801641801521801421801341801241801121801021801f41801e41801d21801c21801 +b41801a4180192180182180174180164180156180142180134180124180116180102180167f4 +1801e41801d61801c21801b41801a41801961801821801741801641801561801421801341801 +241801161801021801f41801e41801d61801c2180101b01801a0180194180184180170180160 +1801541801441801301801201801141801041801f01801e01801d41801c41801b01801a01801 +94180184180170180160180154180144180130180120180114180104180137e018405a01d418 +01c41801a01801941801841801601801541801441801201801141801041801e01801d41801c4 +1801a0180194180184180160180102501801301801201801001801c018019018018018015018 +012f1801101801001801075e5d5d5d5d5d5d5d717171715f7171717171717172727272727272 +72727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171717171717171715f717171 +71727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d71717171 +717171717171003f2b00183f3311333311331112011739113311331133333130132227351633 +323f010133131e0217371333010e02bf4a32262ea86211fe53c0e4050e4c0346edbefe604374 +8dfe570b8706f72b0435fdaa0e27de0dc502b1fbc6ada953000000010039ffec03b6044b002a +0064403c070622151c1b0d00001b1506042b2c0d220318181f50591c1810030a505907031610 +2c01002c01f02c01e02c01c02c01602c01802c013f2c01102c015d5d5d717171717272003f33 +2b00183f332b111200393911120117391133113311331133313001140623222627371e013332 +363534262f012e0235343633321617072e0123220615141e01171e0303b6e7d0cadb219f1790 +80897f5862819b834ad3cab3d31ca20f836e7a74305e978f7e4928012b99a6858d1f57515454 +40501a22284d6e50949b7e8b14484d4a4b2e3c2a25243d4a61000001001ffff0022a052c0014 +004540240d14140b0f0f09040416150e05080550590b0f09010c030940080f02125059021680 +16015d003f2b00183f1acd5f5e5d332b11003311120139113333113332113331302506232235 +11233533373315331523111416333237022a595dd87d843578c8c8333f24440818f502d283f2 +f283fd554e3f0e0000000001008800000623044e0029017e40ff182900002109212012080920 +092b2a1c2550591c10181100151504505915100c0f21090015642b014b2b013f2b012b2b011f +2b010f2b01eb2b01df2b01bb2b01ab2b018b2b017b2b016f2b013b2b011f2b010b2b016aeb2b +01cb2b01bb2b01af2b018b2b017f2b015b2b014f2b011b2b01fb2b01ef2b01df2b01cb2b01bb +2b01af2b01942b01642b014b2b012b2b011b2b01042b01f42b01db2b01ab2b018b2b017f2b01 +6b2b01342b011b2b010f2b0139fb2b01db2b01bb2b01a02b01942b01742b015b2b014b2b012b +2b011f2b010b2b01fb2b01eb2b01cb2b01a42b017b2b015b2b014b2b011b2b01f42b01d02b01 +02c02b01a02b01902b01602b014f2b400b01302b012f2b01002b01085e5d5d5d5d5d5d5d5d5f +5d5d717171717171717172727272727272727272725e5d5d5d5d5d5d5d5d5d71717171717171 +71717171717272727272727272725e5d5d5d5d5d5d5d5d5d5d717171717171003f32323f3f2b +1112003939183f2b111201393911333311331112391133333130211134262322061511231134 +27331e0217333e0133321617333e013332161511231134262322061511030056707386b306aa +01020302033a966c7b8f1c03389f71a495b25670768302ae9d78b0a0fd8d0353bd2a052c394f +735a626b6d60b2cbfd2f02ae9d78afa1fd8d0000000300a8000004ea0581000d0016001e0068 +403a0b1308131b1b040e081700000804031f200b131a131a5f59132413024d0f1301033e1301 +040f130110051313040505125f590503041b5f590412003f2b00183f2b11120039182f5f5e5d +5f5d5f712b2b1112003911120117391133113311331133111239313001140423211121201114 +06071e01013426232111213236133429011121323604eafeeef4fdc4020001f08c80a8b6feee +9c94febf0141999751fea2fe9c0173afa0018dbcd10581feaa7daa1d14b901fa7262fe4273fd +fff9fe04820000000001008800000288044e00130023401006131300000c14150f060a10040f +0015003f3f3f3333111201393911331133313033113427331615333e01333217152623220615 +118e06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4fdcc0000000100a80000 +042f05810005001f400e030000040607010300035f590012003f2b00183f1112013939113331 +30331133112115a8bf02c80581fb1b9c000100b8fefa018100db000900224011040500080508 +0a0b0005a85b08009b5b08002f2b2b1112013939113311333130251514060723363523350181 +26287b5e58dba86a8e41887edb00000000010065009a044804aa0006003c4027030604000407 +08053f067f068f06030603300270028002030201000f043f046f049f04cf04050400192f5d33 +33cd5d32cd5d3211120117393130133501150901156503e3fca6035a023bcd01a29afe92fe91 +990000010068ffec057905960019005e4039031017160809091610031a1b0f17010d03171713 +13005f59130400081008400850089008a008d008e008080c0308080c0c065f590c13201b015d +003f2b110033182f5f5e5d3f2b110033182f5f5e5d1112011739113311331133313001220011 +10003320131706042322240235100021320417072e010318eafefc010fe70128959c57fec5d0 +d5fec9a3016c0142e1012e47b531d904fafed3fefafefdfec501254eb6beb10149e10151017e +b0ad3c7b820000000001fffd000005cc043a001401ae40ff01001107060c0f0e0313090c0311 +03140807140114160808010b0815030e1303080f010c11030715761601661601541601461601 +361601241601161601041601f41601e61601c41601b21601a416019616018616016616015416 +0144160136160114160106160169f61601e21601d41601c61601b61601961601841601741601 +661601461601361601241601161601061601f41601e61601b61601a416019416018616016916 +01561601441601361601061601e41601d61601c41601b61601a6160189160172160101601601 +54160124160104160138f41601d41601c41601a416018016017416014b160130160124160114 +1601fb1601c41601a0160194164030017b16016416014416013416011b1601f01601e41601cb +1601b416019416018416016416013f160102101601001601085e5d5d5f5d5d5d5d5d5d5d5d71 +7171717171717171727272727272727272725e5d5d5d5d5f5d5d5d5d5d5d5d71717171717171 +7171717172727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d717171717171 +7171003f17333f17331101335e5d11335d111217393332113333113333113333313021230327 +0e010323013313161737133313173713330496d1bd240926b9d0fed1b2b7072411e2c1bd2e1f +cdb002fda92da9fd30043afd2118ae4a035bfd19be8b031a00000001008e000003ee05cc0018 +0060403b1511111208071207191a13000003120715030d50590310d01a01c01a01b01a01f01a +01b01a01ff1a01e01a01d01a01c01a01b01a01a01a01701a015d5d5d5d5d5d5d717172727200 +3f2b00183f3312393f11120139391133113311333130013e0133321615112311342e01232206 +151123113311140607013d3aa37db0a7b52a60557f99b4b4070103816a63afcefd2f02ae726f +34b095fd8205ccfe7e3d820a0001001d0000023c05ca0015008f40680d130106010202150415 +0417160a0f50590a0000030603505913060f01151f172f174f175f177f178f179f17070f173f +177f17af17bf17df17ef17073b5f17bf17027f178f179f17030f172f17af17df17ef17051740 +5664481740272c48201730176017034017015d712b2b5d71725e5d71003f3f332b110033183f +2b111201393211123911333311333231300111231123353335343633321715262322061d0133 +150169b4989882864b342d23453ed303b7fc4903b7837a94820c8908465c6183000000020056 +ffec041d044e000a00160048402c11060b0006001718080e50590810031450590316a0180190 +1801801801701801601801501801301801df18015d71717171717171003f2b00183f2b111201 +39391133113331300110022322021110213212033426232206151416333236041dfaeeedf201 +e5f8eabd859d9e8d8b95a28b021efee4feea012101110230feeffee1e0cbcfdcd6d7d0000000 +000200a800000565058100090013002c40170f050a0005001415060e5f590603050f5f590512 +2015015d003f2b00183f2b111201393911331133313001140204232111212000031000290111 +213236120565aafec8ccfdf101d201660185c0fee1fef0fef1013a9beb7e02cfdafeb9ae0581 +fe99feb501060113fbb18801000000020057ffec0473044e00230030008e4056202929070715 +0e0f2e03030f151a0432311d1851591d1620001107295159070711003f0e010f0e6f0e020b03 +0e0e11110b50591110002450590016c03201a032019032018032017032016032015032013032 +01a032015d7171717171717171003f2b00183f2b110033182f5f5e5d711112392f2b11120039 +183f2b11120117391133113311331133113331300522263534363f0135342623220607271221 +321615111416333237150623222627230e0127323e013d01070e02151416019ea3a4ddf6f370 +78796e0bbc2e0184ccce2a3b1a214447645b060645b75a639a59c57f83465f14ac96a8b40604 +3b8472525a110124bbb1fe2e505107701069707c67875a9d5359040230645158600000000001 +002e000004b405810007013040d90102040207030908000405045f59050301127b09014b0901 +3b0901240901fb0901cb0901bb09019b09018b09017f0901025f09014f09013009010f090167 +df0901cf0901b009018f09015f09014f09010f0901f00901df0901cf0901af09019f09017009 +015f09014009011f0901ef0901df09019f09016f09015f09013f09011f090100090137ef0901 +d009019009018009016f09015009012f0901000901d00901af09019009017f09016f09015009 +01400901200901100901ff0901e00901bf0901a009019009016009014009013f09012009010f +0901075e5d5d5d5d5d5d5d5d5d5d71717171717171717172727272727272725e5d5d5d5d5d5d +5d5d717171717171717171727272727272725e5d5d5d5d5f5d5d5d5d5d5d71717171003f3f2b +110033111201173911333130011123112135211502d0befe1c048604e5fb1b04e59c9c000000 +00010009000007860581001901fc40ff1819080101010014071101081001111004080707010b +03070d0a09090d041419051b1a8b1b011bc07c7f48391b012a1b01191b010a1b01f91b01ea1b +01d91b01ca1b01b81b01891b991ba91b03781b01691b013a1b4a1b5a1b03291b011a1b010c1b +0168fd1b01ec1b01dd1b01cc1b01bd1b01ab1b019c1b018b1b017c1b016b1b015c1b014b1b01 +3c1b012b1b011c1b010b1b01fc1b01eb1b01dc1b01cb1b01bc1b01ab1b019c1b01008d1b017f +1b016d1b015f1b014d1b012f1b3f1b021d1b010f1b01fd1b01ef1b01dd1b01cf1b01bd1b01af +1b019d1b018f1b016d1b7d1b025b1b014d1b013b1b012d1b011b1b010d1b0138fb1b01ed1b01 +db1b01cd1b406f01bb1b01ad1b019b1b018d1b017b1b016d1b014b1b5b1b02391b012b1b0119 +1b010b1b01f91b01eb1b01dd1b01cb1b01bd1b01ab1b019d1b018b1b017d1b016b1b015d1b01 +4b1b013d1b01012b1b011f1b01025f1b7f1b9f1bbf1bdf1bff1b06001b01081810040903140d +0d010812003f333311333f333333015e5d5d5f71715f71717171717171717171717171727272 +7272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d71717171717171715f71 +717171717171727272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d717171 +712b7111121739113311335f5e5d331133335d5d1133335d1133313021230326270e01032301 +3313161736121333131617373e01013305e7e4f4182e1a24ffe4fe61c7fd2d26183ff6b7f538 +20091b220108c7037f54d9749cfc640581fc81a8b26e01040367fc93d79523739103b2000000 +000100090000054d05810008003e402607080100050302020508030a09200a500a02300a600a +900ac00af00a052f0a01070203050112003f333f33015d5d7111121739113311333311333130 +212301330117370133030ec6fdc1c9018654540184c90581fc20f9f903e00000000200640158 +044703ec00030007003f4028070300040408090504ad590f051f054f055f05cf05050a030501 +400100ad595001d001020f010101002f5d5d2b001a1810ce5f5e5d2b11120117393130133521 +15013521156403e3fc1d03e303589494fe009494000000010065009a044804aa0006003c4027 +06020003040708033004700480040304013f007f008f00030006050f023f026f029f02cf0205 +0200192f5d3333cd5d32cd5d32111201173931303735090135011565035afca603e39a99016f +016e9afe5ecd00000001009effec0529058100130049402c0d100704100415140e0503000a5f +590013201501c01501b01501a015018015017015016015015015012015015d5d5d5d5d5d5d5d +71003f2b00183f33111201393911331133313005222426351133111416333236351133111406 +0402dbadfefe8ebfc4b9bed3be91fef7147ef0a60381fc8fc1c8cfc70364fc91abf883000000 +00020084fe57041d044d00170024005d403718001f110808090009262511041502151b505915 +100c0f081b022250590216b026013f26019026017026011f2601ff2601e02601c026015d5d5d +7171717272003f2b00183f3f3f2b111200393911120139391133113333113331300110212227 +2316151123113427331e0215333e0133321203342623220e01151416333236041dfe72fa5605 +04b406ae01040504309e81c8c6bd7a856b793f8899867b0222fdcabc08a2fe590506a7360431 +6613645dfef4fedde2c25abf99d5cac500000002000400000552058100070010005b40360d01 +000c02030605080003040408070312110c025f590c0c080503040012b01201501201f01201c0 +12019012016012013012012f12015d5d5d5d5d5d7171003f323f33392f2b1112011739113332 +11333312393912393931302103210323013309010706070321032627048fa1fd7ea2c6023fd9 +0236fd5b091931b4020fb51c1c019cfe640581fa7f04f11c5382fe3101d145570000000200a8 +000004ea0581000a0011003c40200f0505060b00060012130f045f590f0f0507070e5f590703 +05122013012013015d71003f3f2b11120039182f2b1112013939113311331133313001140423 +211123112132040710290111212004eafefbe0fe62bf0251ed0104c0feb8fe850183014003d9 +c8ecfddb0581decc0111fdd4000000020084ffec041d05cc00170023005d40371e050e0e0d18 +000d00242505110215151b505915100d000a15022150590216b025013f25019025017025011f +2501ff2501e02501c025015d5d5d7171717272003f2b00183f3f3f2b11120039391112013939 +113311331133333130011021222627231406072336351133111407333e013332120334262322 +06151416333236041dfe727ba333020802ae06b4040432a57acdc1bd7887988b889988790222 +fdca59631f7f0a36a904edfe594158685afeecfee2e3c4d0e2d5cbc90001005b01d0024f0270 +0003001f4011000304050100bb599f01cf01022f010101002f5d712b11120139393130133521 +155b01f401d0a0a000020053008d042003ac0008001100394020050806010f0a0e110a011108 +04131209000300ef5b0c0f032f036f037f030403002f5d332b11003311120117391133113311 +33113331302501350133150901152101350133150901150376feae0152a8feae0154fd83feb0 +0150a7feb101518d016d3f01731ffe8cfe911d016d3f01731ffe8cfe911d00020053008d0420 +03ac000800110039402003080c1104010d0a0a1101080413120a000500ef5b0e0f052f056f05 +7f050405002f5d332b1100331112011739113311331133113331302523350901353301150123 +3509013533011502cea80152feb0a60152fcddaa0152feb0a8014f8d1d016f01741ffe8d3ffe +931d016f01741ffe8d3f05cc05cc007d05810015007905810015000000000000000000000000 +0000043a001400770000ffec00000000ffec00000000ffec0000fe5700000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000008000000000000b4 +00bd00af00a00000000000000000000000000088007e000000ac000000000000000000000000 +00bf00c300ab00000000009b008d000000000000000000000000000000000000000000000000 +000000b900aa0000000000000094009900870000000000000000000000000000000000000000 +00000000006a0083008d00a400b4000000000000000000000060006a0079009800ac00b800a7 +00000122013300c3006b00000000000000db00c9000000000000000000000000000000000000 +0000000001e101c9009200a8006b009200b7006b009b0000027b02f200920252006e02d70381 +0082008900a0009f0169008f0000016000a4015b005e0082000000000000005e0065006f0000 +000000000000000000000000008a009000a5007a0080000000000000000000000581fff3000d +fcb300830089008f00960069007105cc000ffc1efff2003404e6000dfed400bf031f00a700ae +00b500000000008100000000000000000748036a02b60202fd930000009100670091006101d9 +0000028d03410000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000006810468001404cb0000ffecffd3fe7f +008300db00aa00ba00a000cf40475b5a59585554535251504f4e4d4c4b4a4948474645444342 +41403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f181411100f0e0d0b0a09 +0807060504030201002c20b0016045b003252011466123452361482d2c20451868442d2c4523 +4660b0206120b04660b004262348482d2c4523462361b0206020b02661b02061b00426234848 +2d2c45234660b0406120b06660b004262348482d2c4523462361b0406020b02661b04061b004 +262348482d2c0110203c003c2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed +51582320b04d44235920b0042651582320b00d44235921212d2c20204518684420b001602045 +b04676688a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101 +283e01b0282370b10228453ab10200080d2d2c2045b00325456164b050515845441b2121592d +2c49b00e23442d2c2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0008b20b1 +2cc08a8cb8100062602b0c642364615c58b00361592d2c8a03458a8a87b0112bb0292344b029 +7ae4182d2c4565b02c234445b02b23442d2c4b525845441b2121592d2c4b515845441b212159 +2d2c01b005251023208af500b0016023edec2d2c01b005251023208af500b0016123edec2d2c +01b0062510f500edec2d2cb00243b001525821212121211b462346608a8a462320468a608a61 +b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b010606801 +3a592d2c2045b0032546524bb013515b58b0022546206861b00325b003253f2321381b211159 +2d2c2045b00325465058b0022546206861b00325b003253f2321381b2111592d2c00b00743b0 +06430b2d2c21210c6423648bb84000622d2c21b08051580c6423648bb82000621bb200402f2b +59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b002602d2c0c6423648bb8 +4000626023212d2c4b53588ab004254964234569b0408b61b08062b020616ab00e23442310b0 +0ef61b21238a121120392f592d2c4b535820b0032549646920b00526b0062549642361b08062 +b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab004261112 +20392320392f2f592d2c4523456023456023456023766818b08062202d2cb0482b2d2c2045b0 +005458b040442045b04061441b2121592d2c45b1302f4523456160b0016069442d2c4b5158b0 +2f2370b01423421b2121592d2c4b515820b0032545695358441b2121591b2121592d2c45b014 +43b0006063b0016069442d2cb02f45442d2c452320458a60442d2c45234560442d2c4b235158 +b90033ffe0b134201bb3330034005944442d2cb0164358b00326458a586466b01f601b64b020 +606620581b21b04059b001615923586559b02923442310b029e01b2121212121592d2cb00243 +54584b53234b515a58381b2121591b21212121592d2cb0164358b004254564b020606620581b +21b04059b0016123581b6559b0292344b00525b00825082058021b0359b0042510b005252046 +b0042523423cb00425b0072508b0072510b006252046b00425b0016023423c2058011b0059b0 +042510b00525b029e0b02920456544b0072510b00625b029e0b00525b00825082058021b0359 +b00525b003254348b00425b0072508b00625b00325b0016043481b2159212121212121212d2c +02b00425202046b004252342b0052508b003254548212121212d2c02b0032520b0042508b002 +2543482121212d2c452320451820b00050205823652359236820b040505821b0405923586559 +8a60442d2c4b53234b515a5820458a60441b2121592d2c4b545820458a60441b2121592d2c4b +53234b515a58381b2121592d2cb000214b5458381b2121592d2cb002435458b0462b1b212121 +21592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b21212121592d2cb00243 +5458b0492b1b212121592d2c208a08234b538a4b515a5823381b2121592d2c00b0022549b000 +535820b04038111b21592d2c014623466023466123201020468a61b8ff80628ab140408a7045 +60683a2d2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d +2cb1020042b123018851b1400188535a58b910000020885458b202010243604259b124018851 +58b920000040885458b2020202436042b12401885458b2022002436042004b014b5258b20208 +02436042591bb940000080885458b202040243604259b94000008063b80100885458b2020802 +43604259b94000010063b80200885458b202100243604259b12601885158b94000020063b804 +00885458b202400243604259b94000040063b80800885458b2028002436042595959595959b1 +0002435458400a0540084009400c020d021bb10102435458b2054008ba010000090100b30c01 +0d011bb18002435258b2054008b80180b109401bb2054008ba01800009014059b94000008088 +55b94000020063b8040088555a58b30c000d011bb30c000d0159595942424242422d2c451868 +234b51582320452064b04050587c59688a6059442d2cb00016b00225b0022501b001233e00b0 +02233eb10102060cb00a236542b00b234201b001233f00b002233fb10102060cb006236542b0 +072342b00116012d2cb080b0024350b001b00243545b58212310b0201ac91b8a10ed592d2cb0 +592b2d2c8a10e52d0001000000021999e0785c265f0f3cf5001f080000000000c840f99a0000 +0000dd7b2e16fba6fd930a6a07d700000008000200010000000000010000073efe4e00430ab4 +fba6fa7a0a6a000100000000000000000000000000000030060000cd04ac0064047300570400 +00170400005701c7008a047300850473005601c70089047300880473005602390092055600a8 +0239001002aa007f02aa000c023900bb023900000556005d04000005040000390239001f06aa +0088055600a802aa0088047300a8023900b804ac006505c7006805c7fffd0473008e0239001d +0473005605c700a80473005704e3002e078d00090556000904ac006404ac006505c7009e0473 +008405560004055600a80473008402aa005b0473005304730053000000000000004c000000c0 +0000019400000328000003e8000004780000052c000005f00000068400000738000008680000 +08b40000093800000984000009e400000a4800000a9400000a9400000bac00000de400000ec8 +00000f50000011480000122000001284000012c00000130c0000137000001434000016340000 +16e4000017b800001854000018d4000019f400001b4c00001dac00001e1800001e8000001ee4 +00001f7400002044000020ec000021700000223c00002274000022fc00002380000100000030 +01520054005c000600020010002f005c000002a402040004000141210009013f000101390055 +013e000101390055014201400014001f01410140001f001f013b0033013a0055013800330139 +0055004001070001001f01070001009f010440aa01c0fd01affd0100fd010a4ffb0120fb01f5 +50281ff246281ff1462a1ff0462b1f5fef7fef020fef4fef5fef8fefafef050be5e41e1fe3e2 +461f0fe20140e246161fe1e0461fcfe0dfe0efe00340e0333646e046181feeedff1fed01e855 +ec48eb55ea320055e9e8e855e7480055e600ff1fdd3ddf55df010355de3d0355dc03ff1f0fd5 +1fd5020fd51fd50240ca181b46cfc201bdc03c1fc150261fbcbe281fffb90150b870b880b803 +b8ffc040ffb81232461fb73fb74fb76fb77fb79fb7afb70718b60170b2a0b2b0b2030fb20190 +b501b0b5010fb501080fb33fb3efb30380b090b002b0b0c0b0d0b0032faf3faf02a0adb0ad02 +c0add0ad022fac3fac029fab01c0aad0aa024fa98fa9022fa96fa9bfa9ffa9049c9b241f509b +016f9601bf960196461d1f9594171f0f941f947f948f94ff94053091409102809101708f808f +02908f01c08fd08f024f8c5f8c6f8c038646ff1f9f85018483311f74733f1f7350261f6f6e3c +1f6e46351f1a01185519331855073303550603ff1f6050261f5f50261f5c46311f5b5a481f5a +46311f1332125505010355043203556c03010c033c034c036c037c0305ef51ff406451024051 +3538464051252846cf50014946201f4846351f4746351faf4601df46ef460280460116321555 +11010f5510320f55020100550100011f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff +0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff524bb007505b +b00188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb0325358 +b0601d594bb0645358b0401d594bb0805358b0101db11600425973747374752b2b2b2b2b0173 +74752b2b2b00742b2b7373752b2b2b012b2b2b002b2b2b2b2b2b012b2b002b2b012b732b0074 +7374757374732b012b747500732b73740173737400737474737473015e73737473730073732b +7373012b002b012b00732b74752b2b2b2b2b2b2b2b2b2b2b012b2b742b2b5e732b002b5e7374 +012b2b2b002b73735e73737301737373002b2b2b2b2b2b185e0000> +] def +/f-1-0 currentdict end definefont pop +%%EndResource +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 151 7 705 296 +%%EndPageSetup +q 151 7 554 289 rectclip +1 0 0 -1 0 303 cm q +0.988235 0.917647 0.639216 rg +164.25 213 220.363 36.75 re f +0 g +0.75 w +0 J +0 j +[] 0.0 d +10 M q 1 0 0 1 0 0 cm +164.25 213 220.363 36.75 re S Q +q 1 0 0 1 0 0 cm +164.25 231.75 m 384.613 231.75 l S Q +BT +9.75 0 0 -9.75 243.003662 227.625 Tm +/f-0-0 1 Tf +(SystemBuilder)Tj +/f-1-0 1 Tf +-7.692683 -1.923077 Td +(+excluding[E]\(\): ExcludingSystemBuilder[L, E])Tj +ET +0.988235 0.917647 0.639216 rg +343.156 199.5 48.207 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +343.156 199.5 48.207 16.5 re S Q +BT +9.75 0 0 -9.75 346.90686 212.625 Tm +/f-1-0 1 Tf +[(L)37( <: CList)]TJ +ET +0.988235 0.917647 0.639216 rg +434.25 224.25 136.613 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +434.25 224.25 136.613 18 re S Q +BT +9.75 0 0 -9.75 446.990479 238.875 Tm +/f-0-0 1 Tf +(ExcludingSystemBuilder)Tj +ET +0.988235 0.917647 0.639216 rg +528.324 199.5 49.289 27.75 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +528.324 199.5 49.289 27.75 re S Q +BT +9.75 0 0 -9.75 532.075195 212.625 Tm +/f-1-0 1 Tf +[(L)37( <: CList)]TJ +0 -1.153846 Td +(E <: CList)Tj +ET +0.988235 0.917647 0.639216 rg +278.25 277.5 41.438 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +278.25 277.5 41.438 18 re S Q +BT +9.75 0 0 -9.75 282.71521 292.125 Tm +/f-0-0 1 Tf +(System)Tj +ET +0.988235 0.917647 0.639216 rg +434.25 277.5 88.027 18 re f +0 g +q 1 0 0 1 0 0 cm +434.25 277.5 88.027 18 re S Q +BT +9.75 0 0 -9.75 438.621826 292.125 Tm +/f-0-0 1 Tf +(ExcludingSystem)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +302.25 249.75 m 302.25 277.5 l S Q +[] 0.0 d +q 1 0 0 1 0 0 cm +299.094 269.879 m 302.25 277.5 l 305.406 269.879 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +482.25 242.25 m 482.25 277.5 l S Q +[] 0.0 d +q 1 0 0 1 0 0 cm +479.094 269.879 m 482.25 277.5 l 485.406 269.879 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +384.75 235.5 m 434.25 235.5 l S Q +[] 0.0 d +q 1 0 0 1 0 0 cm +426.629 238.656 m 434.25 235.5 l 426.629 232.344 l S Q +0.988235 0.917647 0.639216 rg +242.25 43.5 311.93 69 re f +0 g +q 1 0 0 1 0 0 cm +242.25 43.5 311.93 69 re S Q +q 1 0 0 1 0 0 cm +242.25 62.25 m 554.18 62.25 l S Q +BT +9.75 0 0 -9.75 355.676147 58.125 Tm +/f-0-0 1 Tf +(BaseSystemBuilder)Tj +/f-1-0 1 Tf +-11.248836 -1.769231 Td +[(+withBefore\(f: \(DeltaT)37(ime, W)18(orld, V)18(iew[L]\) => Unit\): Bu\ +ilderT)55(ype)]TJ +0 -1.153846 Td +[(+withAfter\(f: \(DeltaT)37(ime, W)18(orld, V)18(iew[L]\) => Unit\): Bui\ +lderT)55(ype)]TJ +0 -1.153846 Td +[(+withPrecondition\(f: \(\) => Boolean\): BuilderT)55(ype)]TJ +0 -1.153846 Td +[(+withUpdate\(f: \(Entity)74(, L)37( , DeltaT)37(ime\) => Deletable[L]\):\ + SystemT)56(ype)]TJ +ET +0.988235 0.917647 0.639216 rg +403.793 7.5 157.137 39 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +403.793 7.5 157.137 39 re S Q +BT +9.75 0 0 -9.75 407.544434 20.625 Tm +/f-1-0 1 Tf +[(L)37( <: CList)]TJ +0 -1.153846 Td +[(SystemT)55(ype)]TJ +0 -1.153846 Td +[(BuilderT)55(ype <: BaseSystemBuilder)]TJ +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +302.25 212.25 m 302.25 139.5 l 398.25 139.5 l 398.25 112.5 l S Q +1 g +404.562 127.742 m 398.25 112.5 l 391.938 127.742 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +404.562 127.742 m 398.25 112.5 l 391.938 127.742 l 404.562 127.742 l S Q +BT +9.75 0 0 -9.75 178.5 160.875 Tm +/f-1-0 1 Tf +[(SystemT)55(ype <- System[L])]TJ +-2.846154 -1.423077 Td +[(BuilderT)55(ype <- SystemBuilder[L])]TJ +11.615385 -1.538462 Td +[(L)37( <- L)]TJ +-0.423077 4.192308 Td +(\253bind\273)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +500.25 224.25 m 500.25 139.5 l 398.25 139.5 l 398.25 112.5 l S Q +1 g +404.562 127.742 m 398.25 112.5 l 391.938 127.742 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +404.562 127.742 m 398.25 112.5 l 391.938 127.742 l 404.562 127.742 l S Q +BT +9.75 0 0 -9.75 511.875 160.875 Tm +/f-1-0 1 Tf +[(SystemT)55(ype <- ExcludingSystem[L, E])]TJ +0 -1.423077 Td +[(BuilderT)55(ype <- ExcludingSystemBuilder[E, L])]TJ +0 -1.538462 Td +[(L)37( <- L)]TJ +0 4.346154 Td +(\253bind\273)Tj +ET +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/doc/img/View.eps b/doc/img/View.eps new file mode 100644 index 00000000..d3fd40bc --- /dev/null +++ b/doc/img/View.eps @@ -0,0 +1,1300 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.17.4 (https://cairographics.org) +%%CreationDate: Tue Oct 12 22:35:32 2021 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 20 7 334 243 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%BeginResource: font LiberationSans +11 dict begin +/FontType 42 def +/FontName /LiberationSans def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 32 /space put +Encoding 40 /parenleft put +Encoding 41 /parenright put +Encoding 44 /comma put +Encoding 45 /hyphen put +Encoding 58 /colon put +Encoding 60 /less put +Encoding 62 /greater put +Encoding 67 /C put +Encoding 69 /E put +Encoding 73 /I put +Encoding 76 /L put +Encoding 84 /T put +Encoding 97 /a put +Encoding 98 /b put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 105 /i put +Encoding 108 /l put +Encoding 110 /n put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 117 /u put +Encoding 120 /x put +Encoding 121 /y put +Encoding 171 /guillemotleft put +Encoding 187 /guillemotright put +/CharStrings 30 dict dup begin +/.notdef 0 def +/guillemotleft 1 def +/t 2 def +/r 3 def +/a 4 def +/i 5 def +/guillemotright 6 def +/T 7 def +/L 8 def +/colon 9 def +/space 10 def +/C 11 def +/s 12 def +/I 13 def +/n 14 def +/c 15 def +/l 16 def +/u 17 def +/d 18 def +/e 19 def +/less 20 def +/E 21 def +/x 22 def +/hyphen 23 def +/greater 24 def +/parenleft 25 def +/y 26 def +/comma 27 def +/parenright 28 def +/b 29 def +end readonly def +/sfnts [ +<000100000009008000030010637674204ada4bfa0000143c000002886670676d7e61b6110000 +16c4000007b4676c7966af1cabd10000009c000013a0686561640b008bb100001e7800000036 +686865610d94039b00001eb000000024686d747870b60c3400001ed4000000786c6f63610001 +1da800001f4c0000007c6d617870038d03e400001fc80000002070726570fdae474900001fe8 +00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e900000000020053008d042003ac0008001100394020050806010f0a0e110a01110804131209 +000300ef5b0c0f032f036f037f030403002f5d332b1100331112011739113311331133113331 +302501350133150901152101350133150901150376feae0152a8feae0154fd83feb00150a7fe +b101518d016d3f01731ffe8cfe911d016d3f01731ffe8cfe911d0001001ffff0022a052c0014 +004540240d14140b0f0f09040416150e05080550590b0f09010c030940080f02125059021680 +16015d003f2b00183f1acd5f5e5d332b11003311120139113333113332113331302506232235 +11233533373315331523111416333237022a595dd87d843578c8c8333f24440818f502d283f2 +f283fd554e3f0e0000000001008800000288044e00130023401006131300000c14150f060a10 +040f0015003f3f3f3333111201393911331133313033113427331615333e0133321715262322 +0615118e06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4fdcc000000020057 +ffec0473044e00230030008e40562029290707150e0f2e03030f151a0432311d1851591d1620 +001107295159070711003f0e010f0e6f0e020b030e0e11110b50591110002450590016c03201 +a03201903201803201703201603201503201303201a032015d7171717171717171003f2b0018 +3f2b110033182f5f5e5d711112392f2b11120039183f2b111201173911331133113311331133 +31300522263534363f0135342623220607271221321615111416333237150623222627230e01 +27323e013d01070e02151416019ea3a4ddf6f37078796e0bbc2e0184ccce2a3b1a214447645b +060645b75a639a59c57f83465f14ac96a8b406043b8472525a110124bbb1fe2e505107701069 +707c67875a9d535904023064515860000000000200890000013d05cc00030007006e40480307 +070004040809050f0415010053590100ff0901e00901df0901c00901b009019f090180090170 +09011f0901000901f00901df0901c00901b00901a009019009014f09011f09015d7171717171 +717172727272727272727272003f2b00183f3f11120139113333113331301335331503113311 +89b4b4b40520acacfae0043afbc600020053008d042003ac000800110039402003080c110401 +0d0a0a1101080413120a000500ef5b0e0f052f056f057f050405002f5d332b11003311120117 +391133113311331133313025233509013533011501233509013533011502cea80152feb0a601 +52fcddaa0152feb0a8014f8d1d016f01741ffe8d3ffe931d016f01741ffe8d3f0001002e0000 +04b405810007013040d90102040207030908000405045f59050301127b09014b09013b090124 +0901fb0901cb0901bb09019b09018b09017f0901025f09014f09013009010f090167df0901cf +0901b009018f09015f09014f09010f0901f00901df0901cf0901af09019f09017009015f0901 +4009011f0901ef0901df09019f09016f09015f09013f09011f090100090137ef0901d0090190 +09018009016f09015009012f0901000901d00901af09019009017f09016f0901500901400901 +200901100901ff0901e00901bf0901a009019009016009014009013f09012009010f0901075e +5d5d5d5d5d5d5d5d5d5d71717171717171717172727272727272725e5d5d5d5d5d5d5d5d7171 +71717171717171727272727272725e5d5d5d5d5f5d5d5d5d5d5d71717171003f3f2b11003311 +1201173911333130011123112135211502d0befe1c048604e5fb1b04e59c9c000000000100a8 +0000042f05810005001f400e030000040607010300035f590012003f2b00183f111201393911 +333130331133112115a8bf02c80581fb1b9c000200bb0000017e043a00030007002740130307 +07040004090804059c5b0401009c5b010f003f2b00182f2b1112013939113311333130133533 +1503353315bbc3c3c3036bcfcffc95cfcf0000010068ffec057905960019005e403903101716 +0809091610031a1b0f17010d0317171313005f59130400081008400850089008a008d008e008 +080c0308080c0c065f590c13201b015d003f2b110033182f5f5e5d3f2b110033182f5f5e5d11 +1201173911331133113331300122001110003320131706042322240235100021320417072e01 +0318eafefc010fe70128959c57fec5d0d5fec9a3016c0142e1012e47b531d904fafed3fefafe +fdfec501254eb6beb10149e10151017eb0ad3c7b8200000000010039ffec03b6044b002a0064 +403c070622151c1b0d00001b1506042b2c0d220318181f50591c1810030a5059070316102c01 +002c01f02c01e02c01c02c01602c01802c013f2c01102c015d5d5d717171717272003f332b00 +183f332b111200393911120117391133113311331133313001140623222627371e0133323635 +34262f012e0235343633321617072e0123220615141e01171e0303b6e7d0cadb219f17908089 +7f5862819b834ad3cab3d31ca20f836e7a74305e978f7e4928012b99a6858d1f575154544050 +1a22284d6e50949b7e8b14484d4a4b2e3c2a25243d4a6100000100bd0000017c05810003008c +406103000004050103001240050130050120050110050100050139f00501b00501a005017005 +01600501500501400501000501f00501c00501b00501a00501500501400501100501000501f0 +0501af05019005017005016005015005014005012005015d5d5d5d5d5d5d5d71717171717171 +7172727272727272725e5d5d5d5d5d003f3f111201391133313033113311bdbf0581fa7f0001 +0088000003ee044e001a0061403c1209090a001a0a1a1b1c1216001605505916100d0f0a0015 +d01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a01c01701c015d5d +5d5d5d5d5d7171727272003f323f3f2b11120039111201393911331133113331302111342e01 +232206151123113427331e0217333e01333216151103392a5c598296b406aa01020302033ea3 +79b2a502ae6b7634b29efd8d0353bd2a052c394f705db1ccfd2f00010057ffec03ca044e0019 +00664045000d1413060707130d031a1b101750591f147f148f14df1404141410102006700680 +06d006e0060500061006600670068006c006d00607090306060a0a0350590a161f1b015d003f +2b110033182f5f5e5d713f332f5d2b1112011739113311331133313001141633323637170e01 +23220211101233321617072e012322060113888960810fb615e0ace3eff0e0a6db1cb90e7269 +8f800222d8d0686c0c9cba011f01130111011fac970e5a6abe0000000001008a0000013e05cc +000300764051030000050401000015f00501e00501df0501c00501b005019f05018005017005 +011f05010f0501f00501df0501c00501b00501a005019005014f0501ff0501e00501d00501c0 +05018005017005011f05015d5d5d5d5d5d5d7171717171717172727272727272727272003f3f +1112013911333130331133118ab405ccfa34000000010085ffec03eb043a001a005f403b1208 +080b01190b191c1b12051605505916160d1509000fd01c01c01c01b01c01f01c01b01c01ff1c +01e01c01d01c01c01c01b01c01a01c01701c015d5d5d5d5d5d5d7171727272003f323f3f2b11 +0033111201393911331133113331300111141e01333236351133111417232e0227230e012322 +263511013a2a5c598296b406aa01020302033ea379b2a5043afd526b7634b29e0273fcadbd2a +052c394f705db1cc02d100020056ffec03ef05cc00160022005640311d000e0e0f17060f0624 +2312150e00000b0308082050590810031a505903169024017024011f2401ff2401e02401c024 +015d5d5d717171003f2b00183f2b1112003939183f3f1112013939113311331133333130250e +0123220211102132161733271133111417232e0135011416333236353426232206033532a57a +cdc1018e7ba4320202b406ac0307fdda7887998a8a978879ae685a0114011802365a627901c1 +fb13a93610742a0170e3c4d4dfd7c8c900020057ffec0418044e001200190077404613110607 +1900000c0c0711031b1a06060003190050590d190114041919090f0f1650590f100903505909 +16d01b01c01b01a01b01901b01801b01701b01601b01501b01301b0171717171717171717100 +3f2b00183f2b11120039182f5f5e5d2b11120039182f11120117391133113311331133313001 +141633323637170221220211101233201115272e012322060701149a94758d199e61fea8f0fb +fbe901ddba0f908783990601f7baca5e482dff00011e011a010c011efdc1188aab9daf990000 +00010065009a044804aa0006003c402703060400040708053f067f068f060306033002700280 +02030201000f043f046f049f04cf04050400192f5d3333cd5d32cd5d32111201173931301335 +01150901156503e3fca6035a023bcd01a29afe92fe919900000100a8000004fe0581000b0054 +4032050909000a030700040c0d05085f598f0501ba050179058905020f050108030505000101 +045f59010300095f590012200d015d003f2b00183f2b11120039182f5f5e5d5d5d712b111201 +1739113311333130331121152111211521112115a8042dfc920332fcce039705819cfe3c9afe +159c000000010017000003ea043a000b015440a0000b08090a04010706050203030507090b05 +0d0c840d01760d01440d540d640d03360d01240d01160d01040d01f60d01e40d01d60d01c40d +01b60d01a40d01760d860d960d03640d01060d160d260d460d560d0567060d460d560d860d96 +0dc60dd60de60d08990dd90d02640d01560d01440d01360d01240d01160d01040d01d60de60d +f60d03c40d01060d260d360d460d0437660da60db60de60df60d050db8ffc040363d4248390d +01220d0101000d100d02f40d01c00dd00de00d03b40d01800d900da00d03740d01600d01540d +01400d01340d01200d010db8ffc04022121848a00d0102000d100d500d700d800d900d06070a +04010407030208060f000215003f333f331217391133015e5d5f5d2b71717171717171717171 +725f72722b725e5d5d5d7171717171717171725e5d5d5d5d5d5d5d5d5d717171717171711112 +173911331133113333331133113331302109012309013309013309010321feddfedbc20181fe +91c7010e010cc9fe91018601bcfe44022c020efe5b01a5fdf4fdd2000001005b01d0024f0270 +0003001f4011000304050100bb599f01cf01022f010101002f5d712b11120139393130133521 +155b01f401d0a0a000010065009a044804aa0006003c40270602000304070803300470048004 +0304013f007f008f00030006050f023f026f029f02cf02050200192f5d3333cd5d32cd5d3211 +1201173931303735090135011565035afca603e39a99016f016e9afe5ecd00000001007ffe58 +029e05cc000e0022401007000b0a03040a0400030f100a1b0300003f3f111201173911331133 +113331301310123733060211101217232602117fb5bcaebbafadbdaebdb40214012101cccbd0 +fe2cfeeafeebfe2ed3cc01cd011f00010005fe5703fc043a001601e440ff13080f11120a0909 +030f1204181708130f131711090f00055059001b921801821801741801641801521801421801 +341801241801121801021801f41801e41801d21801c21801b41801a418019218018218017418 +0164180156180142180134180124180116180102180167f41801e41801d61801c21801b41801 +a41801961801821801741801641801561801421801341801241801161801021801f41801e418 +01d61801c2180101b01801a01801941801841801701801601801541801441801301801201801 +141801041801f01801e01801d41801c41801b01801a018019418018418017018016018015418 +0144180130180120180114180104180137e018405a01d41801c41801a0180194180184180160 +1801541801441801201801141801041801e01801d41801c41801a01801941801841801601801 +02501801301801201801001801c018019018018018015018012f1801101801001801075e5d5d +5d5d5d5d5d717171715f717171717171717272727272727272727272725e5d5d5d5d5d5d5d5d +5d5d5d5d5d5d5d5d7171717171717171717171715f7171717172727272727272727272727272 +7272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d71717171717171717171003f2b00183f3311 +333311331112011739113311331133333130132227351633323f010133131e0217371333010e +02bf4a32262ea86211fe53c0e4050e4c0346edbefe6043748dfe570b8706f72b0435fdaa0e27 +de0dc502b1fbc6ada9530000000100b8fefa018100db0009002240110405000805080a0b0005 +a85b08009b5b08002f2b2b111201393911331133313025151406072336352335018126287b5e +58dba86a8e41887edb0000000001000cfe58022b05cc000e00224010070003040b0a00040a03 +0f100a00031b003f3f1112011739113311331133313001100207233612111002273316121102 +2bb5bcaebcaeafbbaebdb40210fedffe34cbd201d10117011701d2d1ccfe33fee10000000002 +0084ffec041d05cc00170023005d40371e050e0e0d18000d00242505110215151b505915100d +000a15022150590216b025013f25019025017025011f2501ff2501e02501c025015d5d5d7171 +717272003f2b00183f3f3f2b1112003939111201393911331133113333313001102122262723 +1406072336351133111407333e01333212033426232206151416333236041dfe727ba3330208 +02ae06b4040432a57acdc1bd7887988b889988790222fdca59631f7f0a36a904edfe59415868 +5afeecfee2e3c4d0e2d5cbc905cc05cc007d0581001500790581001500000000000000000000 +00000000043a001400770000ffec00000000ffec00000000ffec0000fe570000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000080000000000 +00b400bd00af00a00000000000000000000000000088007e000000ac00000000000000000000 +000000bf00c300ab00000000009b008d00000000000000000000000000000000000000000000 +0000000000b900aa000000000000009400990087000000000000000000000000000000000000 +000000000000006a0083008d00a400b4000000000000000000000060006a0079009800ac00b8 +00a700000122013300c3006b00000000000000db00c900000000000000000000000000000000 +00000000000001e101c9009200a8006b009200b7006b009b0000027b02f200920252006e02d7 +03810082008900a0009f0169008f0000016000a4015b005e0082000000000000005e0065006f +0000000000000000000000000000008a009000a5007a0080000000000000000000000581fff3 +000dfcb300830089008f00960069007105cc000ffc1efff2003404e6000dfed400bf031f00a7 +00ae00b500000000008100000000000000000748036a02b60202fd9300000091006700910061 +01d90000028d0341000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000006810468001404cb0000ffecffd3 +fe7f008300db00aa00ba00a000cf40475b5a59585554535251504f4e4d4c4b4a494847464544 +434241403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f181411100f0e0d0b +0a090807060504030201002c20b0016045b003252011466123452361482d2c20451868442d2c +45234660b0206120b04660b004262348482d2c4523462361b0206020b02661b02061b0042623 +48482d2c45234660b0406120b06660b004262348482d2c4523462361b0406020b02661b04061 +b004262348482d2c0110203c003c2d2c20452320b0cd442320b8015a51582320b08d44235920 +b0ed51582320b04d44235920b0042651582320b00d44235921212d2c20204518684420b00160 +2045b04676688a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370 +b101283e01b0282370b10228453ab10200080d2d2c2045b00325456164b050515845441b2121 +592d2c49b00e23442d2c2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0008b +20b12cc08a8cb8100062602b0c642364615c58b00361592d2c8a03458a8a87b0112bb0292344 +b0297ae4182d2c4565b02c234445b02b23442d2c4b525845441b2121592d2c4b515845441b21 +21592d2c01b005251023208af500b0016023edec2d2c01b005251023208af500b0016123edec +2d2c01b0062510f500edec2d2cb00243b001525821212121211b462346608a8a462320468a60 +8a61b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b01060 +68013a592d2c2045b0032546524bb013515b58b0022546206861b00325b003253f2321381b21 +11592d2c2045b00325465058b0022546206861b00325b003253f2321381b2111592d2c00b007 +43b006430b2d2c21210c6423648bb84000622d2c21b08051580c6423648bb82000621bb20040 +2f2b59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b002602d2c0c642364 +8bb84000626023212d2c4b53588ab004254964234569b0408b61b08062b020616ab00e234423 +10b00ef61b21238a121120392f592d2c4b535820b0032549646920b00526b0062549642361b0 +8062b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab00426 +111220392320392f2f592d2c4523456023456023456023766818b08062202d2cb0482b2d2c20 +45b0005458b040442045b04061441b2121592d2c45b1302f4523456160b0016069442d2c4b51 +58b02f2370b01423421b2121592d2c4b515820b0032545695358441b2121591b2121592d2c45 +b01443b0006063b0016069442d2cb02f45442d2c452320458a60442d2c45234560442d2c4b23 +5158b90033ffe0b134201bb3330034005944442d2cb0164358b00326458a586466b01f601b64 +b020606620581b21b04059b001615923586559b02923442310b029e01b2121212121592d2cb0 +024354584b53234b515a58381b2121591b21212121592d2cb0164358b004254564b020606620 +581b21b04059b0016123581b6559b0292344b00525b00825082058021b0359b0042510b00525 +2046b0042523423cb00425b0072508b0072510b006252046b00425b0016023423c2058011b00 +59b0042510b00525b029e0b02920456544b0072510b00625b029e0b00525b00825082058021b +0359b00525b003254348b00425b0072508b00625b00325b0016043481b215921212121212121 +2d2c02b00425202046b004252342b0052508b003254548212121212d2c02b0032520b0042508 +b0022543482121212d2c452320451820b00050205823652359236820b040505821b040592358 +65598a60442d2c4b53234b515a5820458a60441b2121592d2c4b545820458a60441b2121592d +2c4b53234b515a58381b2121592d2cb000214b5458381b2121592d2cb002435458b0462b1b21 +212121592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b21212121592d2cb0 +02435458b0492b1b212121592d2c208a08234b538a4b515a5823381b2121592d2c00b0022549 +b000535820b04038111b21592d2c014623466023466123201020468a61b8ff80628ab140408a +704560683a2d2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb012004b014b54 +422d2cb1020042b123018851b1400188535a58b910000020885458b202010243604259b12401 +885158b920000040885458b2020202436042b12401885458b2022002436042004b014b5258b2 +020802436042591bb940000080885458b202040243604259b94000008063b80100885458b202 +080243604259b94000010063b80200885458b202100243604259b12601885158b94000020063 +b80400885458b202400243604259b94000040063b80800885458b20280024360425959595959 +59b10002435458400a0540084009400c020d021bb10102435458b2054008ba010000090100b3 +0c010d011bb18002435258b2054008b80180b109401bb2054008ba01800009014059b9400000 +808855b94000020063b8040088555a58b30c000d011bb30c000d0159595942424242422d2c45 +1868234b51582320452064b04050587c59688a6059442d2cb00016b00225b0022501b001233e +00b002233eb10102060cb00a236542b00b234201b001233f00b002233fb10102060cb0062365 +42b0072342b00116012d2cb080b0024350b001b00243545b58212310b0201ac91b8a10ed592d +2cb0592b2d2c8a10e52d0001000000021999f71170365f0f3cf5001f080000000000c840f99a +00000000dd7b2e16fba6fd930a6a07d700000008000200010000000000010000073efe4e0043 +0ab4fba6fa7a0a6a00010000000000000000000000000000001e060000cd047300530239001f +02aa00880473005701c700890473005304e3002e047300a8023900bb0239000005c700680400 +0039023900bd047300880400005701c7008a04730085047300560473005704ac0065055600a8 +0400001702aa005b04ac006502aa007f04000005023900b802aa000c04730084000000000000 +004c000000d40000015c000001c0000002e000000374000003f8000005500000058c000005d8 +000005d80000069c0000078000000824000008d80000099800000a2800000adc00000ba00000 +0c7400000cd800000d5c00000ef000000f2800000f8c00000fec0000122400001270000012d4 +000013a000010000001e01520054005c000600020010002f005c000002a40204000400014121 +0009013f000101390055013e000101390055014201400014001f01410140001f001f013b0033 +013a00550138003301390055004001070001001f01070001009f010440aa01c0fd01affd0100 +fd010a4ffb0120fb01f550281ff246281ff1462a1ff0462b1f5fef7fef020fef4fef5fef8fef +afef050be5e41e1fe3e2461f0fe20140e246161fe1e0461fcfe0dfe0efe00340e0333646e046 +181feeedff1fed01e855ec48eb55ea320055e9e8e855e7480055e600ff1fdd3ddf55df010355 +de3d0355dc03ff1f0fd51fd5020fd51fd50240ca181b46cfc201bdc03c1fc150261fbcbe281f +ffb90150b870b880b803b8ffc040ffb81232461fb73fb74fb76fb77fb79fb7afb70718b60170 +b2a0b2b0b2030fb20190b501b0b5010fb501080fb33fb3efb30380b090b002b0b0c0b0d0b003 +2faf3faf02a0adb0ad02c0add0ad022fac3fac029fab01c0aad0aa024fa98fa9022fa96fa9bf +a9ffa9049c9b241f509b016f9601bf960196461d1f9594171f0f941f947f948f94ff94053091 +409102809101708f808f02908f01c08fd08f024f8c5f8c6f8c038646ff1f9f85018483311f74 +733f1f7350261f6f6e3c1f6e46351f1a01185519331855073303550603ff1f6050261f5f5026 +1f5c46311f5b5a481f5a46311f1332125505010355043203556c03010c033c034c036c037c03 +05ef51ff4064510240513538464051252846cf50014946201f4846351f4746351faf4601df46 +ef46028046011632155511010f5510320f55020100550100011f1f0f3f0f5f0f7f0f040f0f2f +0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b +4bb807ff524bb007505bb00188b02553b00188b040515ab00688b000555a5b58b101018e5985 +8d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0101db1160042597374 +7374752b2b2b2b2b017374752b2b2b00742b2b7373752b2b2b012b2b2b002b2b2b2b2b2b012b +2b002b2b012b732b00747374757374732b012b747500732b7374017373740073747473747301 +5e73737473730073732b7373012b002b012b00732b74752b2b2b2b2b2b2b2b2b2b2b012b2b74 +2b2b5e732b002b5e7374012b2b2b002b73735e73737301737373002b2b2b2b2b2b185e0000> +] def +/f-0-0 currentdict end definefont pop +%%EndResource +%%BeginResource: font LiberationSans-Bold +11 dict begin +/FontType 42 def +/FontName /LiberationSans-Bold def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 69 /E put +Encoding 73 /I put +Encoding 86 /V put +Encoding 97 /a put +Encoding 98 /b put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 103 /g put +Encoding 105 /i put +Encoding 108 /l put +Encoding 110 /n put +Encoding 111 /o put +Encoding 114 /r put +Encoding 116 /t put +Encoding 117 /u put +Encoding 119 /w put +Encoding 120 /x put +/CharStrings 19 dict dup begin +/.notdef 0 def +/I 1 def +/t 2 def +/e 3 def +/r 4 def +/a 5 def +/b 6 def +/l 7 def +/V 8 def +/i 9 def +/w 10 def +/E 11 def +/x 12 def +/c 13 def +/u 14 def +/d 15 def +/n 16 def +/g 17 def +/o 18 def +end readonly def +/sfnts [ +<000100000009008000030010637674206d5f6ba100000d70000002886670676d7e61b6110000 +0ff8000007b4676c796672ac2aa30000009c00000cd4686561640b8df529000017ac00000036 +686865610e180386000017e400000024686d747852760714000018080000004c6c6f63610000 +7a3800001854000000506d617870042b0534000018a400000020707265708aa104b9000018c4 +00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e900000000010089000001b00581000300664045030000040501030012e00501b00501a00501 +900501800501500501400501000501f00501c00501b00501a005017005016005011f0501e005 +01d00501c00501b005018005015d5d5d5d5d717171717171717272727272727272003f3f1112 +013911333130331121118901270581fa7f0000010019ffee029105380015003b401d130c0c0a +0d080d040416170d0506054f590a060808060f00114f590016003f2b00183f332f11332b1100 +3311120139113333113333113331300522263511233533373315331523111416333237150601 +a47c86899758b0cdcd3c3f213d68128789027ebefefebefdce4f4b0eae22000000020050ffec +042d044e00120019006f4043170a1011160b0b0303110a031b1a160b525916211011480f1601 +0e0516160006061352590610000e51597f1001101001101000169f1b016f1b015f1b014f1b01 +2f1b015d5d5d5d5d003f322f5d5d2b00183f2b11120039182f5f5e5d2b2b1112011739113311 +331133113331300522001110003332121115211416333237050201220607212e01024af4fefa +010af4e9f6fd4a756c9527010973fea0636b0301a4086e1401210115010c0120fecbfed6089e +a18117feda03b18a7c83830000010087000002fe044f0016003e402508161600000f18170d12 +5059080d10050f00159f18017f1801d01801af18015f18012f18015d5d5d5d7171003f3f3f33 +2b11120139391133113331303311342627211e0115333e02333217152623220615118f050301 +0c030a0429405842362144346975033c59772e12b71e725d2d0feb0faaa7fded00000002003c +ffec0480044e00260033006d403f2427270707150e0f2c03030f150335340628525906060059 +0e690e022d0e01030f0e1f0e0209040e12120b51591210192f002f4f5924210016bf35014f35 +015d71003f32322b110033183f2b1100335f5e5d5f5d5d1239182f2b11120117391133113311 +331133113331300522263534363f0135342623220607253e0133321615111416333237150e03 +23222627230613070e0215141633323e013501899db0dbd0e94a544e4909fedb1bebcbcdde29 +30201e1928282d1e6a650a0676599062522b473b426d3e14ab9ba8b00204376a6747520e9ea3 +cabafe765b450698060a06046865d50209020423483c4d4b487f470000020087ffec048f05cc +00160021003c40201d060f0f0d17000d002322141a4f591114100e000b1503204f5906031670 +230171003f332b00183f3f3f332b111201393911331133113333313001100223222627231406 +072136351121110733363332120134262322061514163332048fd7c873a82d020905feef0801 +1904045ffbc0cdfedb6c7172777572df0221fef4fed7645e237a115d9a04d5fe62b0d0feddfe +f6b8b2bfb4acc00000000001008f000001a805cc00030046402d030000050401000015500501 +400501b00501a005017f05016005011f0501ef0501d00501c00501b005018005015d5d5d5d5d +71717171717272003f3f1112013911333130331121118f011905ccfa34000001000e00000548 +0581000a0038401f090a010006030202060a030c0bc00c019f0c01600c012f0c010902030601 +12003f333f33015d5d5d5d11121739113311333311333130290101210116173f0101210342fe +d5fdf7013401221b2f1533012101310581fc7758b256b403890000000002008f000001a805cc +00030007005640360307070004040809050f0415010053590100500901400901b00901a00901 +7f09016009011f0901ef0901d00901c00901b009018009015d5d5d5d5d71717171717272003f +2b00183f3f111201391133331133313013352115011121118f0119fee7011904fdcfcffb0304 +3afbc6000001fffa0000063d043a001401ba40ff0100110e0d0407060a0a0411030813141416 +090808158f16017916016b16015d16014f16013b16012d16011b16010d1601f91601eb1601dd +1601cf1601a916b916029b16018d16017f16016b16015d16014b16013d16011b162b16020d16 +0168ff1601d916e91602cb1601bd1601ab16019d16018916017b16016d16014b165b16023d16 +012b16011916010b1601fb1601ed1601db1601cd1601b91601ab16019916018b16016d167d16 +025b16014916012b163b16021d1601010f1601bb16db16eb1603af16016b168b16024f165f16 +023416010b161b160238eb1601df1601cb1601b416019b16017f168f16026416014b16013f16 +011b1601fb1601e416403f01cb1601bf16019416a416027b16016f16012b164b1602fb1601ef +160102c016d016028f16af160270160116400a0d4800160108130d04080f110a0a070015003f +323211333f333333015e5d2b5d5d5d5f5d5d7171717171717171727272727272727272725e5d +5d5d5d5d5d715f7171717171717171717171717172727272727272727272727272725e5d5d5d +5d5d5d5d5d5d5d5d5d5d5d717171717171717171113311331133113312173911333311333311 +3333313029010326270703210121133f0113211316173713210521fed7ac0c2334aefed7fee8 +0108b20e19aa012da60e1b1c9c010402942db1e0fd6e043afcc54a75027cfd84348b8402b700 +00010089000005060581000b0074404a050909000b00010b060a030700040c0d05085f590f05 +7f059f05030f058f05ff05030f03051615490f0501140505160c490505000101045f59010300 +095f590012400d01300d01200d015d5d5d003f2b00183f2b11120039182f2b5f5e5d2b5f5e5d +712b11120117395f5e5d113311333130331121152111211521112115890454fcd302f0fd1003 +560581e4fe9ee4fe8de400000001000e00000464043a000b00404024000b08090a0401070605 +0203030507090b050d0c050f0015f00d01e00d019f0d014f0d015d5d5d71003f3f1112011739 +1133113311333333113311333130210b01210901211b012109010333fcfefed5018cfe87012f +e7e60131fe87018f0188fe78022f020bfe9e0162fdf8fdce000000010050ffec0437044e0018 +0042402414150a090f03030915031a19060d4f590a0a061000146014020d0314140000114f59 +0016003f2b110033182f5f5e5d3f332f2b111201173911331133113331300522001110003332 +1617052e012322111033323637050e020252f6fef4010ef8bffa20fee50c6058d9dd506c0d01 +1a0f81d21401250106010c012bc0a90e5363fe95fe8a65640d6fae5f00000001007fffec045c +043a0016004f402f0e0707080016081618170e121203505912160c1507000fa01801901801f0 +1801b01801a01801901801701801ef18015d71717171717272003f323f3f2b11003311120139 +391133113311333130011110333236351121111417212635230e0123222635110198c0667d01 +1908fef40c0538ad77acb8043afda1fee3af890244fcb88a6890477b70d3cc02af0000020054 +ffec045c05cc00160021003e402017031212131d091309222312000c1a4f590f0c10061f4f59 +030616001570230171003f3f332b00183f332b00183f1112013939113311331133333130212e +0135230623220211101233321617332711211114170134262322061510333236034c040b045b +ffbdced9c773a72d0202011908fee37572716edd6f7a0f7928c401270109010d0125605fb201 +8bfb2064880223afbdb7bcfe90c300000001008700000464044f0018004f402f001810070708 +08181a1910141403505914100c0f080015a01a01901a01f01a01b01a01a01a01901a01701a01 +ef1a015d71717171717272003f323f3f2b110033111201393911331133113331302111102322 +0615112111342627211e0115333e013332161511034cc1667dfee70503010c030a0439ac77ac +b8025f011daf89fdbc0348576f2c13a51f7c70d4ccfd510000020054fe4e045a044f0021002b +0061403a18220a0a1f0403271212031f032d2c1b0f15254f591715100f294f590c0f15000751 +59560466047604032204320402050415040204001b702d0171003f325d5d5d2b00183f332b00 +183f332b00183f1112011739113311331133113333313001222627251e013332363d01372306 +23220211101233321733343637210615111404033426232211103332360254c6f11c01190f63 +50756c02025dffbdd0d6ccec5b050905010a06fefa0f776ee1df7077fe4e978c21414a908e39 +6bc7011c010801090120c32378136c8efce1e7ec03dea7bbfe98fe9fbb00000000020050ffec +0493044e000b00150030401a11060c0006001716090f4f59091003144f590316701701601701 +7171003f2b00183f2b1112013939113311333130011000212200111000212000013426232011 +141633200493fedcfefefdfee00120010301090117feda7e78ff007d760103021efef9fed501 +2c01060105012bfedffef1c1aefe91b5bd00000005cc05cc007d058100150079058100150000 +000000000000000000000000043a001400770000ffec00000000ffec00000000ffec0000fe57 +fff7000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000800000000000119012500f500eb0000000000000000000000c100d300ba00b000cf0000 +000000000000000000000127012901060000011200e400f400c6000000000000000000000000 +0000000000000000000000000119011f014c0000000000df00d100c500b50000000000000000 +0000000000000000000000000000010200a901fd00d80119008000b701fd00000000013f00db +015d012500aa00800075008d01fc0179012100a001100000000001310119010e010400000000 +0000000000000000000000000000013d01ff00e00106009400e00094014400e0057303190000 +00d802c5009c038102cd00cb00f4004e028d000000ff00d700cc01300145007300b400a60000 +000000730080008d000000000000000000000000030000a200980083008d0000000000000000 +05aefebc0581fd300011fff600b600bc00c60000007f008a0060000000000000000000f001ee +0190000002190108011500000000000000be00000000000000000748036a02b60202fd930000 +009100670091006101d90000028d0341000000000000000000000000000000aafe6ffe680105 +0093009800e20151008f00be00aefeb9fea4005e00af02d5005500f200a604150601000003e1 +001002fa000ffed401eafff300b8000000000363000bfd0ffff5000000000000068104770015 +04d90000ffecffc5fe7f007500cd00f2010200d5011940475b5a59585554535251504f4e4d4c +4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f +181411100f0e0d0b0a090807060504030201002c20b0016045b003252011466123452361482d +2c20451868442d2c45234660b0206120b04660b004262348482d2c4523462361b0206020b026 +61b02061b004262348482d2c45234660b0406120b06660b004262348482d2c4523462361b040 +6020b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd442320b8015a5158 +2320b08d44235920b0ed51582320b04d44235920b0042651582320b00d44235921212d2c2020 +4518684420b001602045b04676688a4560442d2c01b10b0a432343650a2d2c00b10a0b432343 +0b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c2045b00325456164b0 +50515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b00743650a2d2c +2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361592d2c8a03458a8a +87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845441b2121592d +2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c01b005251023208a +f500b0016123edec2d2c01b0062510f500edec2d2cb00243b001525821212121211b46234660 +8a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b +1bb0468c59b0106068013a592d2c2045b0032546524bb013515b58b0022546206861b00325b0 +03253f2321381b2111592d2c2045b00325465058b0022546206861b00325b003253f2321381b +2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b08051580c6423648b +b82000621bb200402f2b59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b0 +02602d2c0c6423648bb84000626023212d2c4b53588ab004254964234569b0408b61b08062b0 +20616ab00e23442310b00ef61b21238a121120392f592d2c4b535820b0032549646920b00526 +b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344 +b00eed1b8ab00426111220392320392f2f592d2c4523456023456023456023766818b0806220 +2d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1302f4523456160b0 +016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b0032545695358441b2121 +591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c452320458a60442d2c45 +234560442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb0164358b00326458a +586466b01f601b64b020606620581b21b04059b001615923586559b02923442310b029e01b21 +21212121592d2cb0024354584b53234b515a58381b2121591b21212121592d2cb0164358b004 +254564b020606620581b21b04059b0016123581b6559b0292344b00525b00825082058021b03 +59b0042510b005252046b0042523423cb00425b0072508b0072510b006252046b00425b00160 +23423c2058011b0059b0042510b00525b029e0b02920456544b0072510b00625b029e0b00525 +b00825082058021b0359b00525b003254348b00425b0072508b00625b00325b0016043481b21 +59212121212121212d2c02b00425202046b004252342b0052508b003254548212121212d2c02 +b0032520b0042508b0022543482121212d2c452320451820b00050205823652359236820b040 +505821b04059235865598a60442d2c4b53234b515a5820458a60441b2121592d2c4b54582045 +8a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b5458381b2121592d2cb002 +435458b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b +21212121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b515a5823381b2121 +592d2c00b0022549b000535820b04038111b21592d2c014623466023466123201020468a61b8 +ff80628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d +2cb012004b014b54422d2cb1020042b123018851b1400188535a58b910000020885458b20201 +0243604259b12401885158b920000040885458b2020202436042b12401885458b20220024360 +42004b014b5258b2020802436042591bb940000080885458b202040243604259b94000008063 +b80100885458b202080243604259b94000010063b80200885458b202100243604259b1260188 +5158b94000020063b80400885458b202400243604259b94000040063b80800885458b2028002 +436042595959595959b10002435458400a0540084009400c020d021bb10102435458b2054008 +ba010000090100b30c010d011bb18002435258b2054008b80180b109401bb2054008ba018000 +09014059b9400000808855b94000020063b8040088555a58b30c000d011bb30c000d01595959 +42424242422d2c451868234b51582320452064b04050587c59688a6059442d2cb00016b00225 +b0022501b001233e00b002233eb10102060cb00a236542b00b234201b001233f00b002233fb1 +0102060cb006236542b0072342b00116012d2cb080b0024350b001b00243545b58212310b020 +1ac91b8a10ed592d2cb0592b2d2c8a10e52d00010000000219994a2571315f0f3cf5001f0800 +00000000c849682600000000dd7b292bfc25fcfd0a6f08440001000800020001000000000001 +0000073efe4e00430aaafc25fa7a0a6f000100000000000000000000000000000013060000cd +0239008902aa001904730050031d00870473003c04e300870239008f0556000e0239008f0639 +fffa055600890473000e0473005004e3007f04e3005404e3008704e3005404e3005000000000 +0000004c000000cc0000014c0000021c000002a4000003a800000454000004b4000005240000 +05a4000007b400000858000008d80000097400000a1000000abc00000b5c00000c4800000cd4 +00010000001301520054005c000600020010002f005c0000034d0354000400014155013f0001 +01390055013e000101390055014201400014001f01410140001f001f013b0033013a00550138 +00330139005500a4013900f4013900020132003d0131005501310001012f00550130003d012f +0055012c012900ff001f01290001012a00550128003d0127005501270001012a00550126003d +0125005501250001012a00550123012200ff001f01220001012a0055012b003d012a00550050 +01070001002f0107000100af0104405001d0fd01bffd0110fd016ffb0140fb0180f590f5a0f5 +03f1f0351f2ff09ff0025fef012fef5fef6fef9fefdfef05e6e4201fe5e43d1fe2e0271fe1e0 +3d1fdf3ddd55de3d035500dd30dd02dd0103552f410b011e00010010011e0020011e0040011e +0003ffc0011e4028191c46dc03ff1f00db01da043c1fd4d21c1fd3d2261f60d190d1c0d10360 +d190d1b0d1c0d1e0d105b8ffc0b3d1191d46b8ffc0b4d10a0d460fb80116400f01bfbe261f40 +bb29414640bb222746b801214026b63d1f00b8016fb801b8b70a1f00b70100b720b740b760b7 +70b70540b760b790b7d0b7f0b705b80120400d483d1f00b560b502a0b5d0b502b8ffc0400eb5 +0b0e460fb25fb202b1033c1f2f410b0119003f0119004f01190003008f011900010040011940 +282629461faf2faf3faf9faf040faf0140af0e164600ad70ad80ad03e0adf0ad02abaa351faa +50261fb9011b011ab23c1f00b8011ab6010fa9010fa801bc01170113003c001f0115407e503c +1f9e9b271f9d9b271f9c9b271f809b019846281f9f97af97029646351f0f941f94029390261f +9291261f0f8f1f8f6f8f7f8f8f8f058e8c261f4f8d010f8c01408c0b0f460f891f890286850f +1f5f850136824682027650261f7550261f7450261f7350261f2970011b7001037001f47001d6 +70e67002687001597001b8fff0407d700a0d466f6e481f6e46321f1a01185519331855073303 +550603ff1f6150261f605f321f5f50261f5e5a481f5c46271f5b5a781f5a46311f1332125505 +010355043203556f03010f033f034f036f037f03055f53014053282c4640531e224640531318 +466b527b528b5203514f1c1f504f1c1f194f294f02594f694f02b80112402d46251f4946191f +4846211f4746351ff846019846011c481b551632155511010f5510320f55020100550100ff1f +b80111b21b091fb80110402d1b091f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f +073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff524bb007505bb0 +0188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb0325358b0 +601d594bb0645358b0401d594bb0805358b0101db11600425973747374752b2b2b2b2b2b2b2b +0173742b2b2b2b0073742b2b732b2b2b7373752b2b2b012b2b2b002b2b2b2b2b2b2b2b012b2b +2b73737373747474002b2b2b2b0173732b73002b73732b732b2b73012b732b00732b2b2b2b2b +7373732b012b2b0073742b73742b73742b73012b73742b007374752b73742b2b2b012b00732b +2b7374012b2b002b732b2b73752b732b2b012b2b002b2b737401732b00737373737373017373 +73002b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> +] def +/f-1-0 currentdict end definefont pop +%%EndResource +%%BeginResource: font LiberationSans-BoldItalic +11 dict begin +/FontType 42 def +/FontName /LiberationSans-BoldItalic def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 66 /B put +Encoding 73 /I put +Encoding 86 /V put +Encoding 97 /a put +Encoding 101 /e put +Encoding 105 /i put +Encoding 111 /o put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 119 /w put +/CharStrings 12 dict dup begin +/.notdef 0 def +/B 1 def +/a 2 def +/s 3 def +/e 4 def +/V 5 def +/i 6 def +/w 7 def +/I 8 def +/t 9 def +/r 10 def +/o 11 def +end readonly def +/sfnts [ +<00010000000900800003001063767420668f73c9000008c0000002886670676d7e61b6110000 +0b48000007b4676c79669ef426e60000009c00000824686561640c0c15c3000012fc00000036 +686865610ea403360000133400000024686d747833cb029100001358000000306c6f63610000 +355400001388000000346d61787003f2053c000013bc0000002070726570fc59ebc9000013dc +00000430000300240000057b0581000e00170020007940470f201718180e1700000e1c0a1304 +040a070e04212207200f0f205f590f0f18000e185f590e1200175f5900036c6d584022012022 +01f02201d02201c02201a022017022013022015d5d5d5d5d5d71722b003f2b00183f2b111200 +39182f2b1112003911120117391133113311331133113311123939313001213204151406071e +01151404290101213236353426232103213236353426232101360248fb0102a59f8899fec7fe +c6fd3f01ca0126af937286fed3bc0148d1a2889afeb60581a5a189af2117a577d3dc03495c69 +5048fc3565755a600002000affec0437044e002d0038007d40450538382a2121121e17181832 +0c1e0c3a39c03ae03a020f3a010b033806092e102e525921200f17010b0310171017091b1b14 +51591b1009354f5900275259000009165859582b003f332f2b2b00183f2b1112003939182f2f +5f5e5d39392b1112003939015f5e5d5d11123939113333113311333311333311333130052226 +353437230e01232226353424253736353423220607253e01333216151407030615141e023332 +37070e0103230e0115141633323637037c646c050654a4768ca700ff011ebf157f5e5c11fef9 +22efc6cfc1184708141a1a071e200e2a56e2a275874f4353881b0a5445251b8261a783b9bd05 +035f248049451f909692952578fe9f2d1b181a0c03079b10060201025c54464f816a00010017 +ffec042d044b0025007d404e1f131307060d00001a19061926270d1f0316161d51590d1a1d1a +2d1a0309041a1610030a515905071507250703070316502701402701302701202701102701d0 +2701b027015027014027012027015d5d5d5d717272727272003f335d2b00183f335f5e5d2b11 +12003939111201393911333311331133331133313001140423222627371e0133323635342627 +2e0135343633321617072e01232215141e01171e0103e8fefff6c9e829fb15706e6d71538dc7 +a3fbe9ceca18fb116255cd284a8db696014eaeb48e95244b42464234371e2d9f7ea0aa8d931d +453e78212c202129980000000002003fffec043a044e0017001f0067403d1f02020e07080815 +0e152019211f0052591f211011480f1f1f1f020d051f1f0b12121c5259121054076407020007 +10072007030904070b0b0551590b16003f2b1100335f5e5d5d183f2b11120039182f5f5e5d2b +2b110133123939113311331133113331300106151416333237170e0123222635341224333216 +15140727373426232206070166075d5b9342f54bdeb4d5f0900109aed1e318ec03635060831c +01dc26336a71a94a9f7ce7cfcf0137a6d7c46374bb386b628580000100ab000005e50581000a +004440260100060602090a0a0302020c0b0a0203060001124f0c01200c01100c01bf0c015f0c +013f0c015d5d5d717171003f33333f3311120139113332113312391133333130290103211316 +173e01012102e1feade301317210062f3901e501340581fc7793776a7a03af00000200230000 +025c05cc00030007005e40380605050402000007040409080706050f04150300010053590101 +585958f00901d00901a00901900901200901000901af09018009012f09015d5d5d7171717171 +712b003f2b110033183f3f332f1112013911333311331133113331300137210701132103011a +29011929fdf0d20119d304fdcfcffb03043afbc600010063000006a6043a0014006240360100 +110f0e0307060b0b03110308131414090808161503110b030714130f0e09080f070601001540 +1601a016017f16013f16012016015d5d5d5d71003f3232323f33333333331217391112013911 +3332113312173911333311333311333331302901032706070121032113153f01012113173701 +2104b7fed72b05352afed2fed74501020e1b340126012d2a05350123010a0294e68e5afd6e04 +3afd4883447b027cfd84bf8402b7000100240000025c0581000300a04070000405010300126c +6d5854050134050124050100050102f00501e00501d00501c00501b00501a005019005017005 +015f05011f0501d00501b00501a005016005013f05012005011005010005010db00501a00501 +9005018005017005014005013005011005010005013cb00501a0050172725e5d5d5d5d5d5d5d +5d5d5e5d5d5d5d5d5d5d5d717171717171717171715f727272722b003f3f1112013931303301 +21012401110127feee0581fa7f00000000010056fff002f005380019006040320c0f0b171212 +0b060307090903031a0d1b0b0a094010150f0f05000609064f590c090f00154f590016585958 +df1b01801b015d5d2b003f2b00183f332b11120039331112391a1810cd321101331239113311 +3312393332113312393931300522263534371323373337330733072303061514163332370706 +01787c8810669425a289b030ca23cd680b2f28204c205110756c4756020ebefefebefde93821 +2e2d0db61800000100230000037a044e0013004b4029050d060b0b0a0a0607071413150d1105 +06021102505911100b0a0f0615585958af15015f15012f15015d5d5d2b003f3f2f3f2b111200 +391139110133123911333311331112393931300126232206070321133637210f01333e013332 +17034c452d7b9b2365fee7a11812010c160804498e5c2f3803550faeb4fdfe033e7884ac3186 +6b0e0002003fffec04a1044d000d0019003c402314070e0007001a1b0b104f590b1004164f59 +0416585958d01b01201b01f01b01501b015d5d71712b003f2b00183f2b111201393911331133 +31300114020423222635341224333216053423220e01151033323e0104a1a3fed5bcdafe9f01 +26bcebf6fedad072874cd070834b02abcffebeaeebccc90136abdbdcf778f571fefd71e605cc +05cc007d058100150079058100150000000000000000000000000000043a001400770000ffec +ffb20000ffec00000000ffec0000fe57fe550000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000008000000000000000127011100e100ff0115011d +010700e900c100d300ba00b000cf000000000000000005cc01200000012c0122012d010e00e4 +00f400c600eb010100000000000000000000000000aa0000058101120000011100d90114006d +00df00d100c500b5009500a800e600000000000000000000000005810112008800a401020142 +00b90080011d01fd00000000013f00db015d012500aa00800075008d01fc0000015c00000000 +0000000001310119010e0104011b000000000000000000000000000000000000000000e00106 +009400e00094014400e00573031900ae00d502e700970381009d00f400cb004e0000000000d1 +0000000000000000007000b400af000000000070007f008b0000000000000000000000000000 +000000a2000000000000008d00000000000000000581fd300011fff600b200bc009d0000007f +008a0060000000000000000000f00000031f000000000000000000000000000000be00000000 +000000000748036a02b60202fd930000009100670091006101d90000028d0341000000000000 +00000000000000000000fe6ffe6800000000009800c300f202d500ab0253007d02cf00be0000 +000000000000000004150601000003e1001002fa000ffed401eafff300b8000000000363000b +fd0ffff500000000000006810477001504d90000ffecffc5fe7f007500cd00f2010200d50119 +40475b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a39383736 +3531302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201002c20b0 +016045b003252011466123452361482d2c20451868442d2c45234660b0206120b04660b00426 +2348482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b0406120b066 +60b004262348482d2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c +2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b004 +2651582320b00d44235921212d2c20204518684420b001602045b04676688a4560442d2c01b1 +0b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453a +b10200080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c2045b000 +4360442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c64 +2364615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445 +b02b23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500 +b0016023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb0 +0243b001525821212121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c +8a70456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524b +b013515b58b0022546206861b00325b003253f2321381b2111592d2c2045b00325465058b002 +2546206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648b +b84000622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c +6423648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588a +b004254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f59 +2d2c4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610 +b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c4523 +456023456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b0406144 +1b2121592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d +2c4b515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2c +b02f45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb33300 +34005944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b00161 +5923586559b02923442310b029e01b2121212121592d2cb0024354584b53234b515a58381b21 +21591b21212121592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559 +b0292344b00525b00825082058021b0359b0042510b005252046b0042523423cb00425b00725 +08b0072510b006252046b00425b0016023423c2058011b0059b0042510b00525b029e0b02920 +456544b0072510b00625b029e0b00525b00825082058021b0359b00525b003254348b00425b0 +072508b00625b00325b0016043481b2159212121212121212d2c02b00425202046b004252342 +b0052508b003254548212121212d2c02b0032520b0042508b0022543482121212d2c45232045 +1820b00050205823652359236820b040505821b04059235865598a60442d2c4b53234b515a58 +20458a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d +2cb000214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b +1b212121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c +208a08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c +014623466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a23 +53583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b140 +0188535a58b910000020885458b202010243604259b12401885158b920000040885458b20202 +02436042b12401885458b2022002436042004b014b5258b2020802436042591bb94000008088 +5458b202040243604259b94000008063b80100885458b202080243604259b94000010063b802 +00885458b202100243604259b12601885158b94000020063b80400885458b202400243604259 +b94000040063b80800885458b2028002436042595959595959b10002435458400a0540084009 +400c020d021bb10102435458b2054008ba010000090100b30c010d011bb18002435258b20540 +08b80180b109401bb2054008ba01800009014059b9400000808855b94000020063b804008855 +5a58b30c000d011bb30c000d0159595942424242422d2c451868234b51582320452064b04050 +587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a2365 +42b00b234201b001233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b0 +024350b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d00010000 +00021999577817b95f0f3cf5001f080000000000c84e874000000000dd7b2ab2fc2ffcfd0adc +083d00030008000200010000000000010000073efe4e00430aaafc2ff9ce0adc006400150000 +00000000000000000000000c0600000005c700240473000a047300170473003f055600ab0239 +0023063900630239002402aa0056031d002304e3003f0000000000000000000000e80000020c +00000300000003cc00000444000004d00000058800000648000006fc00000790000008240001 +0000000c015200540064000600020010002f005c0000031b0354000400014155013f00010139 +0055013e000101390055014201400014001f01410140001f001f013b0033013a005501380033 +0139005500a4013900f4013900020132003d0131005501310001012f00550130003d012f0055 +012c012900ff001f01290001012a00550128003d0127005501270001012a00550126003d0125 +005501250001012a00550123012200ff001f01220001012a0055012b003d012a005500500107 +0001002f0107000100af0104403b01d0fd01bffd0110fd016ffb0140fb0180f50100ed0140eb +01e6e4201fe5e43d1fe2e0151fe1e03d1fdf3ddd55de3d035500dd30dd02dd0103552f410b01 +1700010010011700200117004001170003ffc00117401f191c46dc03ff1fc8c3ff1f30c301be +47121fba4f641fb960ff1fb8b4161f6fbb011b00010010011b401b0120b70110b520b540b503 +60b470b480b4030fb25fb202b1033c1fb8011440ffae321fb0aaff1f2fb33fb34fb3038fb301 +40b32629461faf2faf3faf9faf040faf0140af0e16469fae01adaaff1fabaa351faa50261f9e +9b271f9d9b251f9c9b251f009b609b02809bf09b029f4bff1f0f941f94020f891f8902939026 +1f9291261f8f8c261f8e8c261f0f8d1f8d025f8d6f8d7f8dff8d044f8d01408d1317460f8c01 +8547321f9f8301816dff1f8003ff1f7650261f7550261f7450261f7350261f2f793f794f7903 +716f1f1f70470f1f6f471e1f1a01185519331855073303550603ff1fa76d01296d016c03ff1f +6150261f605f321f5f50261f63471c1f1962e962022062121546296239624962035e471b1f5d +5bff1f5c5b331f5b473240521f140112551332125505010355043203556f03010f033f034f03 +6f037f0305965901906a014f535f53024053282c4640531e224640531318466b527b528b5203 +514f1c1f504f1c1f194f294f02594f694f02b80116b3471e1f75ba011500850115404102504e +01a04db04dc04d034d47141f4c47321f4b47321f4a471f1fff490149470f1f4847321f004701 +1c1b801f1632155511010f5510320f55020100550100ff1fb80111b21b191fb80110402d1b19 +1f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f0001 +8016010501b80190b154532b2b4bb807ff524bb007505bb00188b02553b00188b040515ab006 +88b000555a5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0 +805358b0101db11600425973747374752b2b2b2b2b2b2b2b01742b2b742b002b2b2b7473732b +73742b2b732b2b2b737301730073752b2b2b2b012b002b2b2b732b742b2b2b2b2b73732b2b2b +2b012b2b002b732b2b2b2b2b2b01732b00732b7374752b2b2b2b73732b73742b2b2b012b2b00 +2b742b73742b73742b2b2b73017373007373732b2b2b012b74002b2b2b73752b732b2b012b2b +002b2b0173007373737373737301737373002b2b2b2b2b2b2b2b2b2b2b2b732b2b2b2b2b2b1800> +] def +/f-2-0 currentdict end definefont pop +%%EndResource +%%BeginResource: font LiberationSans-Italic +11 dict begin +/FontType 42 def +/FontName /LiberationSans-Italic def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 32 /space put +Encoding 35 /numbersign put +Encoding 40 /parenleft put +Encoding 41 /parenright put +Encoding 58 /colon put +Encoding 66 /B put +Encoding 69 /E put +Encoding 86 /V put +Encoding 97 /a put +Encoding 100 /d put +Encoding 101 /e put +Encoding 105 /i put +Encoding 108 /l put +Encoding 110 /n put +Encoding 111 /o put +Encoding 115 /s put +Encoding 116 /t put +Encoding 121 /y put +/CharStrings 19 dict dup begin +/.notdef 0 def +/numbersign 1 def +/i 2 def +/s 3 def +/V 4 def +/a 5 def +/l 6 def +/d 7 def +/parenleft 8 def +/e 9 def +/n 10 def +/t 11 def +/y 12 def +/colon 13 def +/space 14 def +/E 15 def +/parenright 16 def +/B 17 def +/o 18 def +end readonly def +/sfnts [ +<0001000000090080000300106376742071b9631f00000ae4000002886670676d7e61b6110000 +0d6c000007b4676c79669a211d1e0000009c00000a48686561640a93128e0000152000000036 +686865610d2c03c50000155800000024686d74784843028d0000157c0000004c6c6f63610000 +6c98000015c8000000506d6178700456059300001618000000207072657060cddf0200001638 +0000048300020027000004870579001b001f00d640821916001f011e0407071e1f1604061817 +17050615121c0f1d0e080b0b0e0f12040a141313090a060a21200807040b0e0baf591e1d010e +1f1c000f120faf59191615121f0e5f0e020f0e1f0e5f0e6f0e040c0f124f12023adf12ef1202 +2f123f124f128f12df12053f124f12af120312403033480e120e120518171413060a09060518 +003f3333333f3333331239392f2f2b5d71725e5d5e5d71113333332b1100333333113333332b +1100333333111201393911333311331217391133113311331133113333113312173911331133 +1133113331300103211521032313210323132335331323352113330321133303331521032113 +039e4e0104fee5586e56fe95546e54c9e14efc0112596e58016b586e58d3fd4050016a4e0375 +fe8f6cfe680198fe6801986c01716c0198fe680198fe686cfe8f017100020021000001f505cc +00030007004a400b00040408097009c0090209b8ffc040212f38483f09010f091f098f099f09 +af09ef09060a0306050f070415010053590100003f2b00183f333f33015f5e5d712b71111239 +113331300137330701133303011f22b422fe4ed2b4d30520acacfae0043afbc6000000010005 +ffec03d6044b0027004e402a070620140d001a19190014060428290d200317171d5159001a70 +1a020b031a1a1710030a515907070316003f332f2b00183f332f5f5e5d2b1112003939111201 +17391133113311331133313001140623222627371e01333236353426272e0235343633201707 +2e0123220615141e01171e02038bf8eaaecd2993218b758f9466a5808044e8d301622ca3167a +677c852a4f8f7f8148013da2af757e385850615d3e53332a506b47919dff194f464f482a3a2d +2d2852700000000100b1000005f5058100080028401201000503020502090708080a07020305 +0112003f333f3311013311331239391133113333313021230133131737013302a5c6fed2c2c6 +23850244d00581fc20f9f903e0000002002effec042d044e0029003700604034300b17182a0f +04202720180b0438390e2b515904080e0e1b085017010f17010b0317171b1b1450591b102725 +3308335059000816003f332b11003333183f2b110033182f5f5e5d5d1112392f12392b111201 +1739113333331133113331300522263537230e0123222635342425373635342623220607273e +0133321615140703061514333237070603070e0315141633323e0137039f5d55050653b27e8c +af01090122e8136a5e777a1bb22ddfbcabc7134a0b511b210e42b4c777884b2b614d619c6610 +0a4d4c407e65a882b9be0403621d5b5755571d9385a087405dfe863028490770100222040325 +39573e4b5e53864d00010021000001f505cc00030034402203000004056005018005d005024f +05011f052f059f05af05bf05ff05060100030015003f323f015d717172111239113331303301 +3301210120b4fedf05ccfa3400020045ffeb04a905cc00170026004e40292403141d0a030e12 +0e0d0d1112031227281211150e0d00141d0a030700072050590710001850590016003f2b0018 +3f2b1112001739183f333f331112013939113333113311121739113331300522263534123633 +32161733371333030607233437230e0127323e023534262322060215141601919daf7bdfad7b +9b20051c52b4f51d09ac150549a242638d62387f717a8e565e15bda5cb017db8685ea201a3fb +138d52336d5f568b51a3f5617d8b91feb7817b7c000000010060fe58035705cc000a00164009 +0207070b0c041b0000003f3f111201391133313001001110132302111000250357fdbecfaed6 +012c011d05ccfe03fd37fe7bfed70128019601740266dc00000000020045ffec0427044e0018 +00200059402e201900000f1916080909160f16212208080005200050590d201d200214042020 +0c13131d505913100c0550590c16003f2b00183f2b11120039182f5f5e5d2b11120039182f11 +1201393911331133113311331112393130010607141633323637170e01232226353412243332 +161514072737342623220607010006038586619e2c8a49e1a0c9df8e0102a1cde4189f048179 +86b72501f7234e858e60533f8378dfcac9013fb1cebc69648a487c84ab9d0000000100220000 +0416044d001b00474025031811080e0a0e0d0d090a180a1d1c08011a0b110515001505505915 +100e0d0f1b0a090015003f3232323f333f2b1112001739111201393911333311331112393911 +333130211336353423220607032313363733140607333e013332161514070302cd7e12b37ec0 +2076b4a61413aa15070353a7739495157f0285583ea7c0a4fda203535f880b85297359928a40 +64fd730000000001005dffec0280052c0018003f40210c0909120303191a001a101a0214030f +06090651590c090a0a090f001450590016003f2b00183f332f11332b110033015f5e5d111239 +1133331133313005222635343713233733373307330723030615143332370706011355610f7e +7d1a7f69782fc81ac87d0c5a2a3a1363146654374b028f83f2f283fd7b3c23580e8518000001 +ff8cfe570467043a0017004640241214090f0b0a0f0a1318131900192019020b031312120f09 +0b0a0f14091500055059001b003f2b00183f333f331239332f33015f5e5d1133111239391133 +11333332313013222737163332363f010333131e01173e010133010e0210483c1f2d205f9146 +1bd9b7700f1a010a2001b5c7fd8e6f8793fe570e8608807a2f042efdaa50b51b16400320fbc6 +c19b4d00000000020051000001e7043a0003000700274013030007040004090804059c5b0401 +009c5b010f003f2b00182f2b11120139391133113331301337330701373307fb29c329fe9329 +c329036bcfcffc95cfcf0001003f000005690581000b00474028020900000d0c05085f59ba05 +018905017805010f050108030505000101045f59010300095f590012003f2b00183f2b111200 +39182f5f5e5d5d5d5d2b1112013911333231303301210721032107210321073f011104191efc +a658031e1efce25f03831e05819cfe3c9afe159c0001ff39fe58023005cc000a001640090207 +070b0c0400001b003f3f11120139113331300300111003331211100005c70242cfaed6fed4fe +e3fe5801fd02c901850129fed8fe6afe8cfd9adc0003003f000005100581000d0014001d0050 +402b0e111519091104150d0d040609041f1e061d0e0e1d5f590e1d13490e0e0d000d155f590d +1200145f590003003f2b00183f2b11120039182f2b2b11120039111201173911331133113311 +12393130012132161510051e01151404290101212011342901032132363534262321015001fe +d1f1fead8a98fec8feebfdad015c014b0163fef4feb5d70170d2c39f95fe920581ad95fee33b +17a376d5e2032a0102bcfbb1938e6b70000000020043ffec0432044d000e001c0032401b0f00 +150800081e1d001e101e021f030c1150590c10051850590516003f2b00183f2b015f5e5d1112 +39391133113331300114020e012322263536123633321607102322060215141633323e020432 +5095d88ac4e4048cf8b7d2debaf887a35a807a677d5e3b02ab82fee7c361eccbcc013ca2dbc7 +011e8bfee684949b4593e400000005cc05de007d058100150079058100150000000000000000 +000000000000043a001400770000ffec00000000ffec00000000ffec0000fe57000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000008000000 +000000b400bd00af00a000d600b1009d00a8009600870088007e00a000ac0000000000000000 +05cc012000bf00c300ab000000bc009b008d00aa000000000000000000000000000000000000 +00000581011200b900af007200b200a900940099008000000000000000000000000000000000 +0000000005810112006a009100ae00b4005b004c0074006401d90181006a00b800ac0095008a +016500f601080122013300ed00e900c300a5008800db00cf00c900c30039002b00a000000000 +000000000000000001e101c9009200a8006b009200b7006b009b0000000002f2008a0292006e +02d60381004c008900a0005e000000d70000000000a4015b005e0082007400000000005e0065 +006f00000000000000000000000000000088008d00a5007a00800000000000000000fee50581 +fff3000dfcb300830088008d00960069007105cc000ffc1efff2003404e6000dfed400bf031f +00a9000000b500000000008100000000000000000748036a02b60202fd930000009100670091 +006101d90000028d0341000001530145019700e3007904d103d10727feef004e008800570064 +00ad00bd00b4035c000e0078fff20098005f0000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000006810468001404cb0000ffec +ffd3fe7f008300dd00aa00ba00a000cf40475b5a59585554535251504f4e4d4c4b4a49484746 +4544434241403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f181411100f0e +0d0b0a090807060504030201002c20b0016045b003252011466123452361482d2c2045186844 +2d2c45234660b0206120b04660b004262348482d2c4523462361b0206020b02661b02061b004 +262348482d2c45234660b0406120b06660b004262348482d2c4523462361b0406020b02661b0 +4061b004262348482d2c0110203c003c2d2c20452320b0cd442320b8015a51582320b08d4423 +5920b0ed51582320b04d44235920b0042651582320b00d44235921212d2c20204518684420b0 +01602045b04676688a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b028 +2370b101283e01b0282370b10228453ab10200080d2d2c2045b00325456164b050515845441b +2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0 +008b20b12cc08a8cb8100062602b0c642364615c58b00361592d2c8a03458a8a87b0112bb029 +2344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845441b2121592d2c4b51584544 +1b2121592d2c01b005251023208af500b0016023edec2d2c01b005251023208af500b0016123 +edec2d2c01b0062510f500edec2d2cb00243b001525821212121211b462346608a8a46232046 +8a608a61b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b0 +106068013a592d2c2045b0032546524bb013515b58b0022546206861b00325b003253f232138 +1b2111592d2c2045b00325465058b0022546206861b00325b003253f2321381b2111592d2c00 +b00743b006430b2d2c21210c6423648bb84000622d2c21b08051580c6423648bb82000621bb2 +00402f2b59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b002602d2c0c64 +23648bb84000626023212d2c4b53588ab004254964234569b0408b61b08062b020616ab00e23 +442310b00ef61b21238a121120392f592d2c4b535820b0032549646920b00526b00625496423 +61b08062b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab0 +0426111220392320392f2f592d2c4523456023456023456023766818b08062202d2cb0482b2d +2c2045b0005458b040442045b04061441b2121592d2c45b1302f4523456160b0016069442d2c +4b5158b02f2370b01423421b2121592d2c4b515820b0032545695358441b2121591b2121592d +2c45b01443b0006063b0016069442d2cb02f45442d2c452320458a60442d2c45234560442d2c +4b235158b90033ffe0b134201bb3330034005944442d2cb0164358b00326458a586466b01f60 +1b64b020606620581b21b04059b001615923586559b02923442310b029e01b2121212121592d +2cb0024354584b53234b515a58381b2121591b21212121592d2cb0164358b004254564b02060 +6620581b21b04059b0016123581b6559b0292344b00525b00825082058021b0359b0042510b0 +05252046b0042523423cb00425b0072508b0072510b006252046b00425b0016023423c205801 +1b0059b0042510b00525b029e0b02920456544b0072510b00625b029e0b00525b00825082058 +021b0359b00525b003254348b00425b0072508b00625b00325b0016043481b21592121212121 +21212d2c02b00425202046b004252342b0052508b003254548212121212d2c02b0032520b004 +2508b0022543482121212d2c452320451820b00050205823652359236820b040505821b04059 +235865598a60442d2c4b53234b515a5820458a60441b2121592d2c4b545820458a60441b2121 +592d2c4b53234b515a58381b2121592d2cb000214b5458381b2121592d2cb002435458b0462b +1b21212121592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b21212121592d +2cb002435458b0492b1b212121592d2c208a08234b538a4b515a5823381b2121592d2c00b002 +2549b000535820b04038111b21592d2c014623466023466123201020468a61b8ff80628ab140 +408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb012004b01 +4b54422d2cb1020042b123018851b1400188535a58b910000020885458b202010243604259b1 +2401885158b920000040885458b2020202436042b12401885458b2022002436042004b014b52 +58b2020802436042591bb940000080885458b202040243604259b94000008063b80100885458 +b202080243604259b94000010063b80200885458b202100243604259b12601885158b9400002 +0063b80400885458b202400243604259b94000040063b80800885458b2028002436042595959 +595959b10002435458400a0540084009400c020d021bb10102435458b2054008ba0100000901 +00b30c010d011bb18002435258b2054008b80180b109401bb2054008ba01800009014059b940 +0000808855b94000020063b8040088555a58b30c000d011bb30c000d0159595942424242422d +2c451868234b51582320452064b04050587c59688a6059442d2cb00016b00225b0022501b001 +233e00b002233eb10102060cb00a236542b00b234201b001233f00b002233fb10102060cb006 +236542b0072342b00116012d2cb080b0024350b001b00243545b58212310b0201ac91b8a10ed +592d2cb0592b2d2c8a10e52d00010000000219995e0be7ee5f0f3cf5001f080000000000c84e +81b500000000dd7b2c92fab0fd930ae3081d00020008000200010000000000010000073efe4e +00430aaafab0fa560ae3006400150000000000000000000000000013060000000473002701c7 +002104000005055600b10473002e01c700210473004502aa006004730045047300220239005d +0400ff8c02390051023900000556003f02aaff390556003f0473004300000000000000000000 +0148000001c000000288000002dc000003e000000430000004f8000005480000060c000006b0 +00000740000007e00000083000000830000008ac000008f8000009b400000a48000100000013 +015200540065000600020010002f005c0000037803aa0004000141380009013f000101390055 +013e000101390055014201400014001f01410140001f001f013b0033013a0055013800330139 +00550080010f000100f0010f0001004f010f00af010f000200ef010f00010080010f0001003f +010f00010000010f0001004001070001001f01070001009f0104405201c0fd01affd0100fd01 +0a4ffb0120fb01f550281ff246281ff0462b1f5fef7fef020fef4fef5fef8fefafef050be5e4 +1e1fe3e2461f0fe20140e246161fe1e0461fbfe0cfe0dfe00340e0333646e046181fbe011c00 +3d011b0055011a003d0119405855eeedff1fed02e855ec48eb55ea320055e9e8e855e8010055 +e7480055e600ff1fdd3ddf55df010355de3d0355dc03ff1f0fd5010fd5ffd502ffd5019fd401 +d3d23c1fbfc201c150261f60be70be80be0340b860b870b803b8ffc04059b81232460fb73fb7 +020fb33fb3efb3030960b070b00290b0a0b0b0b00380ad90ad02a0adb0ad027fab01a0aab0aa +022fa96fa9020fa94fa99fa9dfa9040ba09f2b1f409f09114600a110a1023a40a150a102b0a1 +c0a1d0a103b8ffc04020a12024469e9b241f9d9b241f9c9b241f509b01985a481f9796241fd0 +96e09602b8ffc0b4960d11460fb8010a4056010f957f95025f946f94cf94df94040f941f947f +948f94ff940593923c1f4092171d464092090c460f91015f919f91af91bf91ef91ff91064091 +1c2546a08fb08f02c08fd08fe08f038e8d461f308d408d02808d016fbe010c000100e0010c00 +01ffc0010c409a0e1146208a308a028584461f816dff1f8003ff1fcf75df75ef7503ef750174 +733f1f7350261f7246351f7146351f4070262c4620703070026f46351f6e46351f1a01185519 +331855073303550603ff1fa76d01296d016c03ff1f615f2f1f605f421f5f50261f5e5a321f5c +46311f5b5a481f5a46311f1332125505010355043203556f03010f033f034f036f037f030596 +5901b052c052d05203b8ffc0b3522d3446b8ffc0409b52202446ef51ff510240513538464051 +252846cf5001204e292f46084e1f2246094d194d02484d584dd84de84df84d05984d01184c24 +2d46184c1d2046984ca84c024b46371f4946201f4846351f4746351faf4601df46ef46028046 +011632155511010f5510320f55020100550100011f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f +8f0fdf0fff0f073f0f7f0fef0f036f00014f00018016010501b80190b154532b2b4bb807ff52 +4bb007505bb00188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d +4bb0325358b0601d594bb0645358b0401d594bb0805358b0101db11600425973747374752b2b +2b2b2b017374752b2b2b002b732b2b7374752b2b742b2b732b2b7301730073752b2b2b012b2b +2b002b2b2b2b2b73732b2b2b2b012b2b742b002b2b2b2b73742b2b012b732b73740073742b73 +742b73742b2b2b73747373012b732b2b00732b2b2b2b73755e73012b2b005e73740173730073 +7473745e73732b730173002b73012b73007374752b2b2b2b2b2b2b2b2b2b2b2b2b2b012b2b74 +2b2b5e732b002b5e7374012b2b002b73735e7373730173737300737373737474752b2b2b2b2b +2b185e0000> +] def +/f-3-0 currentdict end definefont pop +%%EndResource +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 20 7 334 243 +%%EndPageSetup +q 20 7 314 236 rectclip +1 0 0 -1 0 250 cm q +0.980392 0.858824 0.678431 rg +51 21 69.992 27.75 re f +0 g +0.75 w +0 J +0 j +[] 0.0 d +10 M q 1 0 0 1 0 0 cm +51 21 69.992 27.75 re S Q +BT +9.75 0 0 -9.75 73.875 34.125 Tm +/f-0-0 1 Tf +(\253trait\273)Tj +/f-1-0 1 Tf +-0.424617 -1.153846 Td +(Iterable)Tj +ET +0.980392 0.858824 0.678431 rg +115.035 7.5 12.707 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +115.035 7.5 12.707 16.5 re S Q +BT +9.75 0 0 -9.75 118.784912 20.625 Tm +/f-0-0 1 Tf +(T)Tj +ET +0.980392 0.858824 0.678431 rg +51.75 117 69.992 27.75 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +51.75 117 69.992 27.75 re S Q +BT +9.75 0 0 -9.75 75.375 130.125 Tm +/f-0-0 1 Tf +(\253trait\273)Tj +/f-1-0 1 Tf +0.0914776 -1.153846 Td +[(V)18(iew)]TJ +ET +0.980392 0.858824 0.678431 rg +88.688 103.5 39.805 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +88.688 103.5 39.805 16.5 re S Q +BT +9.75 0 0 -9.75 92.436768 116.625 Tm +/f-0-0 1 Tf +(L: CList)Tj +ET +0.980392 0.858824 0.678431 rg +38.25 214.5 103.316 27.75 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +38.25 214.5 103.316 27.75 re S Q +BT +9.75 0 0 -9.75 74.037598 227.625 Tm +/f-0-0 1 Tf +(\253trait\273)Tj +/f-1-0 1 Tf +-1.768799 -1.153846 Td +[(ExcludingV)18(iew)]TJ +ET +0.980392 0.858824 0.678431 rg +60 189.75 88.316 27.75 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +60 189.75 88.316 27.75 re S Q +BT +9.75 0 0 -9.75 63.75 202.875 Tm +/f-0-0 1 Tf +(LIncluded <: CList)Tj +0 -1.153846 Td +(LExcluded <: CList)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +89.25 103.5 m 89.25 48.75 l S Q +1 g +95.562 63.992 m 89.25 48.75 l 82.938 63.992 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +95.562 63.992 m 89.25 48.75 l 82.938 63.992 l 95.562 63.992 l S Q +BT +9.75 0 0 -9.75 19.973511 97.125 Tm +/f-0-0 1 Tf +[(T)18( -> \(Entity)74(, L\))]TJ +3.066819 1.230769 Td +(\253bind\273)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +90 189.75 m 90 144.75 l S Q +1 g +96.312 159.992 m 90 144.75 l 83.688 159.992 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +96.312 159.992 m 90 144.75 l 83.688 159.992 l 96.312 159.992 l S Q +BT +9.75 0 0 -9.75 19.223511 179.25 Tm +/f-0-0 1 Tf +[(L)37( -> LIncluded)]TJ +3.33605 1.153846 Td +(\253bind\273)Tj +ET +0.988235 0.917647 0.639216 rg +169.5 21 156.332 35.25 re f +0 g +q 1 0 0 1 0 0 cm +169.5 21 156.332 35.25 re S Q +q 1 0 0 1 0 0 cm +169.5 39.75 m 325.832 39.75 l S Q +BT +9.75 0 0 -9.75 210.631897 35.625 Tm +/f-2-0 1 Tf +[(BaseV)37(iewIterator)]TJ +/f-3-0 1 Tf +-3.834041 -1.769231 Td +[(#isV)37(alid\(entity: Entity\): Boolean)]TJ +ET +0.988235 0.917647 0.639216 rg +284.375 7.5 48.207 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +284.375 7.5 48.207 16.5 re S Q +BT +9.75 0 0 -9.75 288.124878 20.625 Tm +/f-0-0 1 Tf +[(L)37( <: CList)]TJ +ET +0.988235 0.917647 0.639216 rg +209.25 117 77.383 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +209.25 117 77.383 18 re S Q +BT +9.75 0 0 -9.75 222.019775 131.625 Tm +/f-1-0 1 Tf +[(V)18(iewIterator)]TJ +ET +0.988235 0.917647 0.639216 rg +245.176 103.5 48.207 16.5 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +245.176 103.5 48.207 16.5 re S Q +BT +9.75 0 0 -9.75 248.92749 116.625 Tm +/f-0-0 1 Tf +[(L)37( <: CList)]TJ +ET +0.988235 0.917647 0.639216 rg +186 212.25 123.973 18 re f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +186 212.25 123.973 18 re S Q +BT +9.75 0 0 -9.75 199.426392 226.875 Tm +/f-1-0 1 Tf +[(ExcludingV)18(iewIterator)]TJ +ET +0.988235 0.917647 0.639216 rg +228.406 187.5 88.316 27.75 re f +0 g +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +228.406 187.5 88.316 27.75 re S Q +BT +9.75 0 0 -9.75 232.15686 200.625 Tm +/f-0-0 1 Tf +(LIncluded <: CList)Tj +0 -1.153846 Td +(LExcluded <: CList)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +251.25 187.5 m 251.25 135 l S Q +1 g +257.562 150.242 m 251.25 135 l 244.938 150.242 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +257.562 150.242 m 251.25 135 l 244.938 150.242 l 257.562 150.242 l S Q +BT +9.75 0 0 -9.75 259.568848 178.125 Tm +/f-0-0 1 Tf +(LIncluded -> L)Tj +-0.0455228 1.230769 Td +(\253bind\273)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +248.25 103.5 m 248.25 56.25 l S Q +1 g +254.562 71.492 m 248.25 56.25 l 241.938 71.492 l f +0 g +[] 0.0 d +q 1 0 0 1 0 0 cm +254.562 71.492 m 248.25 56.25 l 241.938 71.492 l 254.562 71.492 l S Q +BT +9.75 0 0 -9.75 258.818848 94.125 Tm +/f-0-0 1 Tf +[(L)37( -> L)]TJ +0.0314002 1.153846 Td +(\253bind\273)Tj +ET +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +121.5 127.5 m 209.25 127.5 l S Q +[] 0.0 d +q 1 0 0 1 0 0 cm +201.629 130.656 m 209.25 127.5 l 201.629 124.344 l S Q +[ 2.25 2.25] 0 d +q 1 0 0 1 0 0 cm +143.25 223.5 m 186 223.5 l S Q +[] 0.0 d +q 1 0 0 1 0 0 cm +178.379 226.656 m 186 223.5 l 178.379 220.344 l S Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/doc/img/fsm-demo.eps b/doc/img/fsm-demo.eps new file mode 100644 index 00000000..96e4d559 --- /dev/null +++ b/doc/img/fsm-demo.eps @@ -0,0 +1,1014 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.17.4 (https://cairographics.org) +%%CreationDate: Wed Oct 13 22:36:00 2021 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 7 7 685 376 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%BeginResource: font LiberationSans-Bold +11 dict begin +/FontType 42 def +/FontName /LiberationSans-Bold def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 32 /space put +Encoding 65 /A put +Encoding 66 /B put +Encoding 67 /C put +Encoding 68 /D put +Encoding 80 /P put +Encoding 83 /S put +Encoding 86 /V put +Encoding 97 /a put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 103 /g put +Encoding 104 /h put +Encoding 105 /i put +Encoding 108 /l put +Encoding 110 /n put +Encoding 111 /o put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 117 /u put +Encoding 121 /y put +/CharStrings 24 dict dup begin +/.notdef 0 def +/P 1 def +/a 2 def +/u 3 def +/s 4 def +/e 5 def +/A 6 def +/d 7 def +/space 8 def +/B 9 def +/l 10 def +/C 11 def +/h 12 def +/n 13 def +/g 14 def +/V 15 def +/o 16 def +/c 17 def +/i 18 def +/t 19 def +/y 20 def +/D 21 def +/r 22 def +/S 23 def +end readonly def +/sfnts [ +<000100000009008000030010637674206d5f6ba100001294000002886670676d7e61b6110000 +151c000007b4676c79667b139f2a0000009c000011f8686561640b8df52900001cd000000036 +686865610e18038b00001d0800000024686d74786d2108b700001d2c000000606c6f63610000 +e0a400001d8c000000646d6178700430053400001df000000020707265708aa104b900001e10 +00000490000200cd00000532058100030007001f400d06020503020309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e900000000020089000005100581000b0013004840290f0606070c000700151405105f590505 +0608080f5f59080306128015017015016015013015011f15017171717171003f3f2b11120039 +182f2b1112013939113311331133313001140e01232111211121320405342901112132360510 +7ce79ffea2fed90279fd0111fed7fefafecf01397a8403c388d675fe100581e9dadefe377900 +0002003cffec0480044e00260033006d403f2427270707150e0f2c03030f1503353406285259 +060600590e690e022d0e01030f0e1f0e0209040e12120b51591210192f002f4f5924210016bf +35014f35015d71003f32322b110033183f2b1100335f5e5d5f5d5d1239182f2b111201173911 +33113311331133113331300522263534363f0135342623220607253e01333216151114163332 +37150e0323222627230613070e0215141633323e013501899db0dbd0e94a544e4909fedb1beb +cbcdde2930201e1928282d1e6a650a0676599062522b473b426d3e14ab9ba8b00204376a6747 +520e9ea3cabafe765b450698060a06046865d50209020423483c4d4b487f47000001007fffec +045c043a0016004f402f0e0707080016081618170e121203505912160c1507000fa018019018 +01f01801b01801a01801901801701801ef18015d71717171717272003f323f3f2b1100331112 +0139391133113311333130011110333236351121111417212635230e0123222635110198c066 +7d011908fef40c0538ad77acb8043afda1fee3af890244fcb88a6890477b70d3cc02af000001 +0048ffec041f044f002800724045070621141b1a0d00001a140604292a210d1703171e5159c2 +1b01601b01030f1b1f1b020a041b1b1710030a5159140724070207070316502a01b02a01302a +01402a012f2a015d5d717172003f332f5d2b00183f332f5f5e5d5f5d5d2b1112003939111201 +17391133113311331133313001140423222627371e01333236353426272e0235343633321617 +072e01232206151416171e03041ffeffe3dfed27f7156780766c5768eea657efdbc1eb1df90c +5e6664644d5b7fc57747013c9db38d95254d403c40343d152f51815e9bad968e1a4241333c2f +37121a374c7700020050ffec042d044e00120019006f4043170a1011160b0b0303110a031b1a +160b525916211011480f16010e0516160006061352590610000e51597f100110100110100016 +9f1b016f1b015f1b014f1b012f1b015d5d5d5d5d003f322f5d5d2b00183f2b11120039182f5f +5e5d2b2b11120117391133113311331133313005220011100033321211152114163332370502 +01220607212e01024af4fefa010af4e9f6fd4a756c9527010973fea0636b0301a4086e140121 +0115010c0120fecbfed6089ea18117feda03b18a7c838300000200330000059105810007000f +020740ff0d01000c02080300070304060508040807031011070c025f590d08050c0c06050304 +0012861101741101641101531101431101341101251101161101021101f31101e41101d41101 +c51101b61101a311019311018411017511016611015411014511013411012411011511010411 +0168f51101e51101d41101c51101b3110100a011019211018411017411016211015011014211 +01321101241101161101021101f01101e21101d41101c41101b21101a4110190110182110174 +1101621101521101441101361101241101101101021101f41101e41101d61101c41101b21101 +a2110194110186110176110164110152110144110134110126110114110106406f110138f211 +01e41101d61101c21101b41101a6110184110176110164110154110146110126110112110101 +001101f41101c41101b01101a01101941101741101641101501101441101341101141101e411 +01c41101b4110194110184110170110164110144110110110102001101085e5d5f5d5d5d5d5d +5d5d5d5d7171717171717171717171725f727272727272727272727272725e5d5d5d5d5d5d5d +5d5d5d5d5d5d5d5d5d7171717171717171717171717171717172727272727272727272725f72 +727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d717171717171717171003f323f33392f12 +39332b00182f111201173911333311331133111239391139393130210321032101210901070e +0103210327046d7dfde77dfed90202015c0200fd52060a1c9e01958b2b0168fe980581fa7f04 +a816245cfe3401958800000000020054ffec045c05cc00160021003e402017031212131d0913 +09222312000c1a4f590f0c10061f4f59030616001570230171003f3f332b00183f332b00183f +1112013939113311331133333130212e01352306232202111012333216173327112111141701 +34262322061510333236034c040b045bffbdced9c773a72d0202011908fee37572716edd6f7a +0f7928c401270109010d0125605fb2018bfb2064880223afbdb7bcfe90c30000000300890000 +056a0581000e0017001f008540510c1309131b1b040f0918000009040321200c141b141b5f59 +0f141f1402140514160c491414040505135f590503041c5f590412a021019021018021017021 +016021015021014021013021013021012021015d5d7171717171717171003f2b00183f2b1112 +0039182f2b5f5e5d2b1112003911120117391133113311331133111239313001140429011121 +2004151406071e010134262321112132361334290111213236056afee0ff00fd3f0285010201 +098588abb3fe867977feb001527d7152fee4fe8a01818e830192c0d20581b3af78a51d14af01 +d55f50fea357fe09c6fe6c6700000001008f000001a805cc00030046402d0300000504010000 +15500501400501b00501a005017f05016005011f0501ef0501d00501c00501b005018005015d +5d5d5d5d71717171717272003f3f1112013911333130331121118f011905ccfa340000010054 +ffec058f05960018005240321609100f0203090f03031a190c135f5910100c04000210020200 +0240028002c002d002050b0302020606005f590613301a015d003f2b110033182f5f5e5d713f +332f2b1112011739113311331133313025201305060423200011100021320417052e01232206 +151412031b010b68010153febfe0feacfe8d01660154f801383ffefc21c183c8cfd5d4010c61 +ccc70181015a015b0174c7c1476a7df8eff3ff000001008f0000046405cc00150050402f120f +0f1008071007171611001007151503030b50590310a01701901701f01701b01701a017019017 +01701701ef17015d71717171717272003f2b110033183f333f11120139391133113311333130 +013e013332161511211110232206151121112111140701a439ac77acb8fee8c1667dfee70119 +0803627c70d4ccfd52025e011daf89fdbd05ccfe6b6d68000001008700000464044f0018004f +402f00181007070808181a1910141403505914100c0f080015a01a01901a01f01a01b01a01a0 +1a01901a01701a01ef1a015d71717171717272003f323f3f2b11003311120139391133113311 +33313021111023220615112111342627211e0115333e013332161511034cc1667dfee7050301 +0c030a0439ac77acb8025f011daf89fdbc0348576f2c13a51f7c70d4ccfd510000020054fe4e +045a044f0021002b0061403a18220a0a1f0403271212031f032d2c1b0f15254f591715100f29 +4f590c0f1500075159560466047604032204320402050415040204001b702d0171003f325d5d +5d2b00183f332b00183f332b00183f1112011739113311331133113333313001222627251e01 +3332363d01372306232202111012333217333436372106151114040334262322111033323602 +54c6f11c01190f6350756c02025dffbdd0d6ccec5b050905010a06fefa0f776ee1df7077fe4e +978c21414a908e396bc7011c010801090120c32378136c8efce1e7ec03dea7bbfe98fe9fbb00 +00000001000e000005480581000a0038401f090a010006030202060a030c0bc00c019f0c0160 +0c012f0c01090203060112003f333f33015d5d5d5d1112173911331133331133313029010121 +0116173f0101210342fed5fdf7013401221b2f1533012101310581fc7758b256b40389000000 +00020050ffec0493044e000b00150030401a11060c0006001716090f4f59091003144f590316 +7017016017017171003f2b00183f2b1112013939113311333130011000212200111000212000 +013426232011141633200493fedcfefefdfee00120010301090117feda7e78ff007d76010302 +1efef9fed5012c01060105012bfedffef1c1aefe91b5bd00000000010050ffec0437044e0018 +0042402414150a090f03030915031a19060d4f590a0a061000146014020d0314140000114f59 +0016003f2b110033182f5f5e5d3f332f2b111201173911331133113331300522001110003332 +1617052e012322111033323637050e020252f6fef4010ef8bffa20fee50c6058d9dd506c0d01 +1a0f81d21401250106010c012bc0a90e5363fe95fe8a65640d6fae5f00000002008f000001a8 +05cc00030007005640360307070004040809050f0415010053590100500901400901b00901a0 +09017f09016009011f0901ef0901d00901c00901b009018009015d5d5d5d5d71717171717272 +003f2b00183f3f111201391133331133313013352115011121118f0119fee7011904fdcfcffb +03043afbc60000010019ffee029105380015003b401d130c0c0a0d080d040416170d0506054f +590a060808060f00114f590016003f2b00183f332f11332b1100331112013911333311333311 +3331300522263511233533373315331523111416333237150601a47c86899758b0cdcd3c3f21 +3d68128789027ebefefebefdce4f4b0eae22000000010010fe570468043a001501ba40ff0b0a +13090e1112120e030a041617110a0f130e0900055059001b9617018617017317016317010050 +1701421701321701241701141701061701f21701e01701d01701c21701b41701a41701961701 +82170174170160170152170142170134170126170112170104170167f41701e21701d21701c4 +1701b41701a21701941701841701761701661701541701441701321701221701141701061701 +f61701d41701c61701b01701a217019217018417017617016617014017013217012217011417 +01061701f61701d41701c21701b2170101a01701901701841701601701541701441701301701 +20170114170104170137f41701cb1701b41701741701041701403bf41701e41701cb1701bb17 +01ab17019417017417013b170124170100170102f01701e01701bf1701801701701701501701 +301701101701001701075e5d5d5d5d5d5d5d5d5d5f7171717171717171717172727272725e5d +5d5d5d5d5d5d5d5d5d5f5d5d5d5d717171717171717171717171717172727272727272727272 +7272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d7171717171715f71717171003f2b00 +182f33333f331112011739113311333311333130012227351633323e013701211316173f0113 +21010e01011b654c352c3c4f3f27fe540129aa283d1941a00126fe5456b9fe570dc808265869 +042ffe056de15feb01fffb8dd0a0000000020089000005710581000900120034401d0f050a00 +05001413060e5f590603050f5f5905128014013014012014015d5d71003f2b00183f2b111201 +3939113311333130011402042321112120000134262b01113332120571abfec7cafdc601fe01 +640186fed7ecdbd1fabee002cbdafebbac0581fe99feb1e3effc4701060000010087000002fe +044f0016003e402508161600000f18170d125059080d10050f00159f18017f1801d01801af18 +015f18012f18015d5d5d5d7171003f3f3f332b11120139391133113331303311342627211e01 +15333e02333217152623220615118f0503010c030a0429405842362144346975033c59772e12 +b71e725d2d0feb0faaa7fded00000001003bffec05060596002a0052402f0c001d1c22160706 +06161c00042c2b0c22031919205f591d1d1904030a5f59100720073007033007400702070703 +13003f332f5d712b00183f332f2b111200393911120117391133113311331133313001140421 +202427251e01332035342e01272e0435342421200417052e01232015141e01171e030506fecd +fed7fef1fecc2c011d1da89501354781b79e7c644627011f01120106010726fee216877efef4 +3970abcbaf66360196cfdbc0c32f7065bc3c4e3425252d3d56744bbfcba4bd275b5ca8374631 +252b4961870005cc05cc007d058100150079058100150000000000000000000000000000043a +001400770000ffec00000000ffec00000000ffec0000fe57fff7000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000800000000000119012500f5 +00eb0000000000000000000000c100d300ba00b000cf00000000000000000000000001270129 +01060000011200e400f400c60000000000000000000000000000000000000000000000000119 +011f014c0000000000df00d100c500b500000000000000000000000000000000000000000000 +010200a901fd00d80119008000b701fd00000000013f00db015d012500aa00800075008d01fc +0179012100a001100000000001310119010e0104000000000000000000000000000000000000 +013d01ff00e00106009400e00094014400e005730319000000d802c5009c038102cd00cb00f4 +004e028d000000ff00d700cc01300145007300b400a60000000000730080008d000000000000 +000000000000030000a200980083008d000000000000000005aefebc0581fd300011fff600b6 +00bc00c60000007f008a0060000000000000000000f001ee0190000002190108011500000000 +000000be00000000000000000748036a02b60202fd930000009100670091006101d90000028d +0341000000000000000000000000000000aafe6ffe6801050093009800e20151008f00be00ae +feb9fea4005e00af02d5005500f200a604150601000003e1001002fa000ffed401eafff300b8 +000000000363000bfd0ffff500000000000006810477001504d90000ffecffc5fe7f007500cd +00f2010200d5011940475b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e +3d3c3b3a393837363531302f2e2d2c28272625242322211f181411100f0e0d0b0a0908070605 +04030201002c20b0016045b003252011466123452361482d2c20451868442d2c45234660b020 +6120b04660b004262348482d2c4523462361b0206020b02661b02061b004262348482d2c4523 +4660b0406120b06660b004262348482d2c4523462361b0406020b02661b04061b00426234848 +2d2c0110203c003c2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed51582320 +b04d44235920b0042651582320b00d44235921212d2c20204518684420b001602045b0467668 +8a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0 +282370b10228453ab10200080d2d2c2045b00325456164b050515845441b2121592d2c49b00e +23442d2c2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8c +b8100062602b0c642364615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d +2c4565b02c234445b02b23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b0 +05251023208af500b0016023edec2d2c01b005251023208af500b0016123edec2d2c01b00625 +10f500edec2d2cb00243b001525821212121211b462346608a8a462320468a608a61b8ff8062 +232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c +2045b0032546524bb013515b58b0022546206861b00325b003253f2321381b2111592d2c2045 +b00325465058b0022546206861b00325b003253f2321381b2111592d2c00b00743b006430b2d +2c21210c6423648bb84000622d2c21b08051580c6423648bb82000621bb200402f2b59b00260 +2d2c21b0c051580c6423648bb81555621bb200802f2b59b002602d2c0c6423648bb840006260 +23212d2c4b53588ab004254964234569b0408b61b08062b020616ab00e23442310b00ef61b21 +238a121120392f592d2c4b535820b0032549646920b00526b0062549642361b08062b020616a +b00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320 +392f2f592d2c4523456023456023456023766818b08062202d2cb0482b2d2c2045b0005458b0 +40442045b04061441b2121592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b0 +1423421b2121592d2c4b515820b0032545695358441b2121591b2121592d2c45b01443b00060 +63b0016069442d2cb02f45442d2c452320458a60442d2c45234560442d2c4b235158b90033ff +e0b134201bb3330034005944442d2cb0164358b00326458a586466b01f601b64b02060662058 +1b21b04059b001615923586559b02923442310b029e01b2121212121592d2cb0024354584b53 +234b515a58381b2121591b21212121592d2cb0164358b004254564b020606620581b21b04059 +b0016123581b6559b0292344b00525b00825082058021b0359b0042510b005252046b0042523 +423cb00425b0072508b0072510b006252046b00425b0016023423c2058011b0059b0042510b0 +0525b029e0b02920456544b0072510b00625b029e0b00525b00825082058021b0359b00525b0 +03254348b00425b0072508b00625b00325b0016043481b2159212121212121212d2c02b00425 +202046b004252342b0052508b003254548212121212d2c02b0032520b0042508b00225434821 +21212d2c452320451820b00050205823652359236820b040505821b04059235865598a60442d +2c4b53234b515a5820458a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b51 +5a58381b2121592d2cb000214b5458381b2121592d2cb002435458b0462b1b21212121592d2c +b002435458b0472b1b212121592d2cb002435458b0482b1b21212121592d2cb002435458b049 +2b1b212121592d2c208a08234b538a4b515a5823381b2121592d2c00b0022549b000535820b0 +4038111b21592d2c014623466023466123201020468a61b8ff80628ab140408a704560683a2d +2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb10200 +42b123018851b1400188535a58b910000020885458b202010243604259b12401885158b92000 +0040885458b2020202436042b12401885458b2022002436042004b014b5258b2020802436042 +591bb940000080885458b202040243604259b94000008063b80100885458b202080243604259 +b94000010063b80200885458b202100243604259b12601885158b94000020063b80400885458 +b202400243604259b94000040063b80800885458b2028002436042595959595959b100024354 +58400a0540084009400c020d021bb10102435458b2054008ba010000090100b30c010d011bb1 +8002435258b2054008b80180b109401bb2054008ba01800009014059b9400000808855b94000 +020063b8040088555a58b30c000d011bb30c000d0159595942424242422d2c451868234b5158 +2320452064b04050587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb1 +0102060cb00a236542b00b234201b001233f00b002233fb10102060cb006236542b0072342b0 +0116012d2cb080b0024350b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c +8a10e52d000100000002199903f5892b5f0f3cf5001f080000000000c849682600000000dd7b +292bfc25fcfd0a6f084400010008000200010000000000010000073efe4e00430aaafc25fa7a +0a6f000100000000000000000000000000000018060000cd055600890473003c04e3007f0473 +00480473005005c7003304e300540239000005c700890239008f05c7005404e3008f04e30087 +04e300540556000e04e30050047300500239008f02aa00190473001005c70089031d00870556 +003b000000000000004c000000e0000001e4000002800000036c0000043c000006900000073c +0000073c000008340000089400000944000009e000000a8000000b6c00000bdc00000c680000 +0d0400000d8400000e0400001014000010940000111c000011f800010000001801520054005c +000600020010002f005c0000034d0354000400014155013f000101390055013e000101390055 +014201400014001f01410140001f001f013b0033013a0055013800330139005500a4013900f4 +013900020132003d0131005501310001012f00550130003d012f0055012c012900ff001f0129 +0001012a00550128003d0127005501270001012a00550126003d0125005501250001012a0055 +0123012200ff001f01220001012a0055012b003d012a0055005001070001002f0107000100af +0104405001d0fd01bffd0110fd016ffb0140fb0180f590f5a0f503f1f0351f2ff09ff0025fef +012fef5fef6fef9fefdfef05e6e4201fe5e43d1fe2e0271fe1e03d1fdf3ddd55de3d035500dd +30dd02dd0103552f410b011e00010010011e0020011e0040011e0003ffc0011e4028191c46dc +03ff1f00db01da043c1fd4d21c1fd3d2261f60d190d1c0d10360d190d1b0d1c0d1e0d105b8ff +c0b3d1191d46b8ffc0b4d10a0d460fb80116400f01bfbe261f40bb29414640bb222746b80121 +4026b63d1f00b8016fb801b8b70a1f00b70100b720b740b760b770b70540b760b790b7d0b7f0 +b705b80120400d483d1f00b560b502a0b5d0b502b8ffc0400eb50b0e460fb25fb202b1033c1f +2f410b0119003f0119004f01190003008f011900010040011940282629461faf2faf3faf9faf +040faf0140af0e164600ad70ad80ad03e0adf0ad02abaa351faa50261fb9011b011ab23c1f00 +b8011ab6010fa9010fa801bc01170113003c001f0115407e503c1f9e9b271f9d9b271f9c9b27 +1f809b019846281f9f97af97029646351f0f941f94029390261f9291261f0f8f1f8f6f8f7f8f +8f8f058e8c261f4f8d010f8c01408c0b0f460f891f890286850f1f5f85013682468202765026 +1f7550261f7450261f7350261f2970011b7001037001f47001d670e67002687001597001b8ff +f0407d700a0d466f6e481f6e46321f1a01185519331855073303550603ff1f6150261f605f32 +1f5f50261f5e5a481f5c46271f5b5a781f5a46311f1332125505010355043203556f03010f03 +3f034f036f037f03055f53014053282c4640531e224640531318466b527b528b5203514f1c1f +504f1c1f194f294f02594f694f02b80112402d46251f4946191f4846211f4746351ff8460198 +46011c481b551632155511010f5510320f55020100550100ff1fb80111b21b091fb80110402d +1b091f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f +00018016010501b80190b154532b2b4bb807ff524bb007505bb00188b02553b00188b040515a +b00688b000555a5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d59 +4bb0805358b0101db11600425973747374752b2b2b2b2b2b2b2b0173742b2b2b2b0073742b2b +732b2b2b7373752b2b2b012b2b2b002b2b2b2b2b2b2b2b012b2b2b73737373747474002b2b2b +2b0173732b73002b73732b732b2b73012b732b00732b2b2b2b2b7373732b012b2b0073742b73 +742b73742b73012b73742b007374752b73742b2b2b012b00732b2b7374012b2b002b732b2b73 +752b732b2b012b2b002b2b737401732b0073737373737301737373002b2b2b2b2b2b2b2b2b2b +2b2b732b2b2b2b2b2b1800> +] def +/f-0-0 currentdict end definefont pop +%%EndResource +%%BeginResource: font LiberationSans +11 dict begin +/FontType 42 def +/FontName /LiberationSans def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 32 /space put +Encoding 33 /exclam put +Encoding 46 /period put +Encoding 47 /slash put +Encoding 65 /A put +Encoding 66 /B put +Encoding 67 /C put +Encoding 77 /M put +Encoding 80 /P put +Encoding 82 /R put +Encoding 86 /V put +Encoding 97 /a put +Encoding 98 /b put +Encoding 99 /c put +Encoding 100 /d put +Encoding 101 /e put +Encoding 103 /g put +Encoding 104 /h put +Encoding 105 /i put +Encoding 107 /k put +Encoding 108 /l put +Encoding 110 /n put +Encoding 111 /o put +Encoding 114 /r put +Encoding 115 /s put +Encoding 116 /t put +Encoding 117 /u put +Encoding 121 /y put +/CharStrings 29 dict dup begin +/.notdef 0 def +/d 1 def +/o 2 def +/slash 3 def +/e 4 def +/n 5 def +/a 6 def +/b 7 def +/l 8 def +/space 9 def +/P 10 def +/y 11 def +/u 12 def +/s 13 def +/B 14 def +/t 15 def +/A 16 def +/i 17 def +/C 18 def +/h 19 def +/g 20 def +/V 21 def +/R 22 def +/c 23 def +/period 24 def +/k 25 def +/exclam 26 def +/M 27 def +/r 28 def +end readonly def +/sfnts [ +<000100000009008000030010637674204ada4bfa00001700000002886670676d7e61b6110000 +1988000007b4676c7966c758a3140000009c00001664686561640b008bb10000213c00000036 +686865610d94039a0000217400000024686d747876f00bfe00002198000000746c6f63610001 +342c0000220c000000786d617870038c03e4000022840000002070726570fdae4749000022a4 +00000343000200cd00000532058100030007001f400d02060503060309080503040003003fcd +2fcd11120139391133113331301321112113112111cd0465fb9b4c03cd0581fa7f0535fb1704 +e900000000020056ffec03ef05cc00160022005640311d000e0e0f17060f06242312150e0000 +0b0308082050590810031a505903169024017024011f2401ff2401e02401c024015d5d5d7171 +71003f2b00183f2b1112003939183f3f1112013939113311331133333130250e012322021110 +2132161733271133111417232e0135011416333236353426232206033532a57acdc1018e7ba4 +320202b406ac0307fdda7887998a8a978879ae685a0114011802365a627901c1fb13a9361074 +2a0170e3c4d4dfd7c8c900020056ffec041d044e000a00160048402c11060b0006001718080e +50590810031450590316a01801901801801801701801601801501801301801df18015d717171 +71717171003f2b00183f2b111201393911331133313001100223220211102132120334262322 +06151416333236041dfaeeedf201e5f8eabd859d9e8d8b95a28b021efee4feea012101110230 +feeffee1e0cbcfdcd6d7d000000000010000ffec023905cc00030013b7020500040100001300 +3f3f1101331133313015013301019b9efe691405e0fa200000020057ffec0418044e00120019 +00774046131106071900000c0c0711031b1a06060003190050590d190114041919090f0f1650 +590f10090350590916d01b01c01b01a01b01901b01801b01701b01601b01501b01301b017171 +71717171717171003f2b00183f2b11120039182f5f5e5d2b11120039182f1112011739113311 +3311331133313001141633323637170221220211101233201115272e012322060701149a9475 +8d199e61fea8f0fbfbe901ddba0f908783990601f7baca5e482dff00011e011a010c011efdc1 +188aab9daf99000000010088000003ee044e001a0061403c1209090a001a0a1a1b1c12160016 +05505916100d0f0a0015d01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b0 +1c01a01c01701c015d5d5d5d5d5d5d7171727272003f323f3f2b111200391112013939113311 +33113331302111342e01232206151123113427331e0217333e01333216151103392a5c598296 +b406aa01020302033ea379b2a502ae6b7634b29efd8d0353bd2a052c394f705db1ccfd2f0002 +0057ffec0473044e00230030008e40562029290707150e0f2e03030f151a0432311d1851591d +1620001107295159070711003f0e010f0e6f0e020b030e0e11110b50591110002450590016c0 +3201a03201903201803201703201603201503201303201a032015d7171717171717171003f2b +00183f2b110033182f5f5e5d711112392f2b11120039183f2b11120117391133113311331133 +113331300522263534363f013534262322060727122132161511141633323715062322262723 +0e0127323e013d01070e02151416019ea3a4ddf6f37078796e0bbc2e0184ccce2a3b1a214447 +645b060645b75a639a59c57f83465f14ac96a8b406043b8472525a110124bbb1fe2e50510770 +1069707c67875a9d53590402306451586000000000020084ffec041d05cc00170023005d4037 +1e050e0e0d18000d00242505110215151b505915100d000a15022150590216b025013f250190 +25017025011f2501ff2501e02501c025015d5d5d7171717272003f2b00183f3f3f2b11120039 +391112013939113311331133333130011021222627231406072336351133111407333e013332 +12033426232206151416333236041dfe727ba333020802ae06b4040432a57acdc1bd7887988b +889988790222fdca59631f7f0a36a904edfe594158685afeecfee2e3c4d0e2d5cbc90001008a +0000013e05cc000300764051030000050401000015f00501e00501df0501c00501b005019f05 +018005017005011f05010f0501f00501df0501c00501b00501a005019005014f0501ff0501e0 +0501d00501c005018005017005011f05015d5d5d5d5d5d5d7171717171717172727272727272 +727272003f3f1112013911333130331133118ab405ccfa340000000200a8000004ea0581000a +0011003c40200f0505060b00060012130f045f590f0f0507070e5f5907030512201301201301 +5d71003f3f2b11120039182f2b11120139391133113311333130011404232111231121320407 +10290111212004eafefbe0fe62bf0251ed0104c0feb8fe850183014003d9c8ecfddb0581decc +0111fdd4000000010005fe5703fc043a001601e440ff13080f11120a0909030f120418170813 +0f131711090f00055059001b9218018218017418016418015218014218013418012418011218 +01021801f41801e41801d21801c21801b41801a4180192180182180174180164180156180142 +180134180124180116180102180167f41801e41801d61801c21801b41801a418019618018218 +01741801641801561801421801341801241801161801021801f41801e41801d61801c2180101 +b01801a01801941801841801701801601801541801441801301801201801141801041801f018 +01e01801d41801c41801b01801a0180194180184180170180160180154180144180130180120 +180114180104180137e018405a01d41801c41801a01801941801841801601801541801441801 +201801141801041801e01801d41801c41801a018019418018418016018010250180130180120 +1801001801c018019018018018015018012f1801101801001801075e5d5d5d5d5d5d5d717171 +715f717171717171717272727272727272727272725e5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d +7171717171717171717171715f71717171727272727272727272727272727272725e5d5d5d5d +5d5d5d5d5d5d5d5d5d5d5d5d71717171717171717171003f2b00183f33113333113311120117 +39113311331133333130132227351633323f010133131e0217371333010e02bf4a32262ea862 +11fe53c0e4050e4c0346edbefe6043748dfe570b8706f72b0435fdaa0e27de0dc502b1fbc6ad +a953000000010085ffec03eb043a001a005f403b1208080b01190b191c1b1205160550591616 +0d1509000fd01c01c01c01b01c01f01c01b01c01ff1c01e01c01d01c01c01c01b01c01a01c01 +701c015d5d5d5d5d5d5d7171727272003f323f3f2b1100331112013939113311331133313001 +11141e01333236351133111417232e0227230e012322263511013a2a5c598296b406aa010203 +02033ea379b2a5043afd526b7634b29e0273fcadbd2a052c394f705db1cc02d100010039ffec +03b6044b002a0064403c070622151c1b0d00001b1506042b2c0d220318181f50591c1810030a +5059070316102c01002c01f02c01e02c01c02c01602c01802c013f2c01102c015d5d5d717171 +717272003f332b00183f332b1112003939111201173911331133113311333130011406232226 +27371e013332363534262f012e0235343633321617072e0123220615141e01171e0303b6e7d0 +cadb219f179080897f5862819b834ad3cab3d31ca20f836e7a74305e978f7e4928012b99a685 +8d1f5751545440501a22284d6e50949b7e8b14484d4a4b2e3c2a25243d4a6100000300a80000 +04ea0581000d0016001e0068403a0b1308131b1b040e081700000804031f200b131a131a5f59 +132413024d0f1301033e1301040f130110051313040505125f590503041b5f590412003f2b00 +183f2b11120039182f5f5e5d5f5d5f712b2b1112003911120117391133113311331133111239 +31300114042321112120111406071e01013426232111213236133429011121323604eafeeef4 +fdc4020001f08c80a8b6feee9c94febf0141999751fea2fe9c0173afa0018dbcd10581feaa7d +aa1d14b901fa7262fe4273fdfff9fe04820000000001001ffff0022a052c0014004540240d14 +140b0f0f09040416150e05080550590b0f09010c030940080f0212505902168016015d003f2b +00183f1acd5f5e5d332b11003311120139113333113332113331302506232235112335333733 +15331523111416333237022a595dd87d843578c8c8333f24440818f502d283f2f283fd554e3f +0e0000000002000400000552058100070010005b40360d01000c020306050800030404080703 +12110c025f590c0c080503040012b01201501201f01201c012019012016012013012012f1201 +5d5d5d5d5d5d7171003f323f33392f2b11120117391133321133331239391239393130210321 +0323013309010706070321032627048fa1fd7ea2c6023fd90236fd5b091931b4020fb51c1c01 +9cfe640581fa7f04f11c5382fe3101d145570000000200890000013d05cc00030007006e4048 +0307070004040809050f0415010053590100ff0901e00901df0901c00901b009019f09018009 +017009011f0901000901f00901df0901c00901b00901a009019009014f09011f09015d717171 +7171717172727272727272727272003f2b00183f3f1112013911333311333130133533150311 +331189b4b4b40520acacfae0043afbc600010068ffec057905960019005e4039031017160809 +091610031a1b0f17010d0317171313005f59130400081008400850089008a008d008e008080c +0308080c0c065f590c13201b015d003f2b110033182f5f5e5d3f2b110033182f5f5e5d111201 +173911331133113331300122001110003320131706042322240235100021320417072e010318 +eafefc010fe70128959c57fec5d0d5fec9a3016c0142e1012e47b531d904fafed3fefafefdfe +c501254eb6beb10149e10151017eb0ad3c7b820000000001008e000003ee05cc00180060403b +1511111208071207191a13000003120715030d50590310d01a01c01a01b01a01f01a01b01a01 +ff1a01e01a01d01a01c01a01b01a01a01a01701a015d5d5d5d5d5d5d7171727272003f2b0018 +3f3312393f11120139391133113311333130013e0133321615112311342e0123220615112311 +3311140607013d3aa37db0a7b52a60557f99b4b4070103816a63afcefd2f02ae726f34b095fd +8205ccfe7e3d820a00020056fe5703ef044b0020002e009f4064211709091f0403281111031f +03302f1c0f170a140e1425505914100e2b50590e16000750591504010604010b04001b403001 +203001cf3001b0300190300120300100300150df3001c030014f3001a030018030012f30010f +3001f03001d030010f3001085e5d5d5d717171717272725e5d5d5d5d5d7171003f325e5d5d2b +00183f2b00183f2b1112003939183f1112011739113311331133113333313001222627371e01 +33201135230e012322021110123332161733343637330615111003342e012322061514163332 +3e010224b1d21eb5127b64010d0233b277c7bbc9cd73a92e020804ab06b34883538a7e768f55 +8448fe578b801a4b51013bae68690108011b011f011169611e940736aafcc5fe3803c684bf65 +c8e0dec264bb0000000100090000054d05810008003e402607080100050302020508030a0920 +0a500a02300a600a900ac00af00a052f0a01070203050112003f333f33015d5d711112173911 +3311333311333130212301330117370133030ec6fdc1c9018654540184c90581fc20f9f903e0 +0000000200a8000005680581000d00160057402f010c0c1309130303040e09000d0d09040317 +180c0213025f591313000505125f5905030400128018017018012018015d5d5d003f323f2b11 +120039182f2b1100331112011739113311331133113311123911333130210121112311213204 +1514060701033426232111213236048cfe92fe49bf0297ee0103b7a10190f8a79dfe3b01cd97 +a50249fdb70581d5be9dd61cfda103ec7b81fdf88d0000010057ffec03ca044e001900664045 +000d1413060707130d031a1b101750591f147f148f14df140414141010200670068006d006e0 +060500061006600670068006c006d00607090306060a0a0350590a161f1b015d003f2b110033 +182f5f5e5d713f332f5d2b1112011739113311331133313001141633323637170e0123220211 +101233321617072e012322060113888960810fb615e0ace3eff0e0a6db1cb90e72698f800222 +d8d0686c0c9cba011f01130111011fac970e5a6abe000000000100bb0000017e00db00030017 +400a030000040500019b5b00002f2b111201391133313033353315bbc3dbdb0000000001008a +0000040305cc000b008d40670809010a090a04000b0b070304040d0c1f0d3f0d021f0d3f0d5f +0dff0d040f0d1f0d3f0d5f0d7f0d05390d40535648600d800da00dc00dd00d05df0d01000d60 +0d800da00d04000d100d300d400d800da00dc00de00df00d09070201070a04080f0500041500 +15003f3f3f3f1739015e5d7171722b5e5d717211123911333332113312393911331133313021 +01071123113311013309010330fe9284b4b401dbd3fe4901ce01ee6dfe7f05ccfc61020dfe2f +fd97000200b90000017f05810003000701e440ff03070702040409082001010f01010e030105 +4004059c5b040203920901840901720901620901540901440901320901220901140901040901 +f20901e20901d40901c40901b20901a409019409018409017209016409015409014409013409 +0124090114090104090167f40901b90901a909019909018909017909014909013d09012d0901 +1f09010f0901ff0901ef0901db0901cb0901bb0901ab09019d09018d09017d09016f09015f09 +014b09013b09012b09011b09010b0901fd0901ed0901dd0901cd0901bb0901ab09019b09018b +09017d09016b09015b09014d09013d09012909011909010b090137fb0901eb0901dd0901cd09 +01bb0901ab09019909405b018909017909016909015b09014b09013b09012d09011d090101eb +0901db0901cb0901bf0901af09019f09017b09016b09013b09012b09011b09010f090102cf09 +01bf09019f09018f09017f09016009014009011f09010f0901075e5d5d5d5d5d5d5d5d5d5f71 +71717171717171717171715f7272727272727272727272727272725e5d5d5d5d5d5d5d5d5d5d +5d5d5d5d5d5d7171717171717171717171717171717172727272727272727272725e5d5d5d5d +5d5d5d5d5d5d5d5d5d5d5d5d71717171717171717171003f2f2b001a1810ce5f5e5d5d111201 +3911333311333130012303330335331501679418c4c6c2018d03f4fa7fc9c900000100a80000 +06020581001a015240ef18001a100d0e1a0e1c1b030a180a0f03000714030e12901c01841c01 +701c01641c01441c01341c01201c01141c01f41c01d01c01c41c01a41c01841c01741c01601c +01541c01341c01101c01041c0167e41c01c41c01b41c01941c01741c01501c01441c01241c01 +041c01f41c01d41c01b41c01841c01641c01441c01341c01141c01f41c01c41c01a41c018b1c +01741c01541c01341c01041c0137e41c01cb1c01b41c01941c01741c01441c01241c010b1c01 +f41c01d41c01bb1c01841c01641c014b1c01341c01141c01fb1c01e41c01c41c01a41c01801c +0102701c01501c01401c013f1c01201c01001c01075e5d5d5d5d5d5d5f5d5d5d5d5d71717171 +7171717172727272727272725e5d5d5d5d5d5d5d5d7171717171717171727272727272727272 +5e5d5d5d5d5d5d5d5d5d5d5d7171717171717171003f17333f33331133111201393911333311 +333331302111343706070123012f011f0111231133011e01173e01370133110556093127fe94 +86fe8f38210304aafb01771425060833090170f503ac9c90b365fc4003c0aa6e6fbdfc540581 +fc2f3b871e28a31503d1fa7f0001008800000288044e00130023401006131300000c14150f06 +0a10040f0015003f3f3f3333111201393911331133313033113427331615333e013332171526 +23220615118e06aa08042b70662425243c7076033e728ab8258b660aa50ac1b4fdcc000005cc +05cc007d058100150079058100150000000000000000000000000000043a001400770000ffec +00000000ffec00000000ffec0000fe5700000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000008000000000000b400bd00af00a0000000000000 +0000000000000088007e000000ac00000000000000000000000000bf00c300ab00000000009b +008d000000000000000000000000000000000000000000000000000000b900aa000000000000 +009400990087000000000000000000000000000000000000000000000000006a0083008d00a4 +00b4000000000000000000000060006a0079009800ac00b800a700000122013300c3006b0000 +0000000000db00c90000000000000000000000000000000000000000000001e101c9009200a8 +006b009200b7006b009b0000027b02f200920252006e02d703810082008900a0009f0169008f +0000016000a4015b005e0082000000000000005e0065006f0000000000000000000000000000 +008a009000a5007a0080000000000000000000000581fff3000dfcb300830089008f00960069 +007105cc000ffc1efff2003404e6000dfed400bf031f00a700ae00b500000000008100000000 +000000000748036a02b60202fd930000009100670091006101d90000028d0341000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000006810468001404cb0000ffecffd3fe7f008300db00aa00ba00a000cf +40475b5a59585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a39383736 +3531302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201002c20b0 +016045b003252011466123452361482d2c20451868442d2c45234660b0206120b04660b00426 +2348482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b0406120b066 +60b004262348482d2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c +2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b004 +2651582320b00d44235921212d2c20204518684420b001602045b04676688a4560442d2c01b1 +0b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453a +b10200080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c2045b000 +4360442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c64 +2364615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445 +b02b23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500 +b0016023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2cb0 +0243b001525821212121211b462346608a8a462320468a608a61b8ff8062232010238ab10c0c +8a70456020b0005058b00161b8ffba8b1bb0468c59b0106068013a592d2c2045b0032546524b +b013515b58b0022546206861b00325b003253f2321381b2111592d2c2045b00325465058b002 +2546206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648b +b84000622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c +6423648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588a +b004254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f59 +2d2c4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610 +b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c4523 +456023456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b0406144 +1b2121592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d +2c4b515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2c +b02f45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb33300 +34005944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b00161 +5923586559b02923442310b029e01b2121212121592d2cb0024354584b53234b515a58381b21 +21591b21212121592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559 +b0292344b00525b00825082058021b0359b0042510b005252046b0042523423cb00425b00725 +08b0072510b006252046b00425b0016023423c2058011b0059b0042510b00525b029e0b02920 +456544b0072510b00625b029e0b00525b00825082058021b0359b00525b003254348b00425b0 +072508b00625b00325b0016043481b2159212121212121212d2c02b00425202046b004252342 +b0052508b003254548212121212d2c02b0032520b0042508b0022543482121212d2c45232045 +1820b00050205823652359236820b040505821b04059235865598a60442d2c4b53234b515a58 +20458a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d +2cb000214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b +1b212121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c +208a08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c +014623466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a23 +53583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b140 +0188535a58b910000020885458b202010243604259b12401885158b920000040885458b20202 +02436042b12401885458b2022002436042004b014b5258b2020802436042591bb94000008088 +5458b202040243604259b94000008063b80100885458b202080243604259b94000010063b802 +00885458b202100243604259b12601885158b94000020063b80400885458b202400243604259 +b94000040063b80800885458b2028002436042595959595959b10002435458400a0540084009 +400c020d021bb10102435458b2054008ba010000090100b30c010d011bb18002435258b20540 +08b80180b109401bb2054008ba01800009014059b9400000808855b94000020063b804008855 +5a58b30c000d011bb30c000d0159595942424242422d2c451868234b51582320452064b04050 +587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a2365 +42b00b234201b001233f00b002233fb10102060cb006236542b0072342b00116012d2cb080b0 +024350b001b00243545b58212310b0201ac91b8a10ed592d2cb0592b2d2c8a10e52d00010000 +00021999ba273c4e5f0f3cf5001f080000000000c840f99a00000000dd7b2e16fba6fd930a6a +07d700000008000200010000000000010000073efe4e00430ab4fba6fa7a0a6a000100000000 +00000000000000000000001d060000cd04730056047300560239000004730057047300880473 +00570473008401c7008a02390000055600a8040000050473008504000039055600a80239001f +0556000401c7008905c700680473008e047300560556000905c700a804000057023900bb0400 +008a023900b906aa00a802aa0088000000000000004c00000110000001ac000001dc000002b0 +000003640000048400000550000005e0000005e0000006640000089c0000095000000a340000 +0b0c00000b9400000c3c00000cd000000d9400000e4400000f7400000fe00000108c0000114c +0000117c000012400000144c000016000000166400010000001d01520054005c000600020010 +002f005c000002a402040004000141210009013f000101390055013e00010139005501420140 +0014001f01410140001f001f013b0033013a00550138003301390055004001070001001f0107 +0001009f010440aa01c0fd01affd0100fd010a4ffb0120fb01f550281ff246281ff1462a1ff0 +462b1f5fef7fef020fef4fef5fef8fefafef050be5e41e1fe3e2461f0fe20140e246161fe1e0 +461fcfe0dfe0efe00340e0333646e046181feeedff1fed01e855ec48eb55ea320055e9e8e855 +e7480055e600ff1fdd3ddf55df010355de3d0355dc03ff1f0fd51fd5020fd51fd50240ca181b +46cfc201bdc03c1fc150261fbcbe281fffb90150b870b880b803b8ffc040ffb81232461fb73f +b74fb76fb77fb79fb7afb70718b60170b2a0b2b0b2030fb20190b501b0b5010fb501080fb33f +b3efb30380b090b002b0b0c0b0d0b0032faf3faf02a0adb0ad02c0add0ad022fac3fac029fab +01c0aad0aa024fa98fa9022fa96fa9bfa9ffa9049c9b241f509b016f9601bf960196461d1f95 +94171f0f941f947f948f94ff94053091409102809101708f808f02908f01c08fd08f024f8c5f +8c6f8c038646ff1f9f85018483311f74733f1f7350261f6f6e3c1f6e46351f1a011855193318 +55073303550603ff1f6050261f5f50261f5c46311f5b5a481f5a46311f133212550501035504 +3203556c03010c033c034c036c037c0305ef51ff4064510240513538464051252846cf500149 +46201f4846351f4746351faf4601df46ef46028046011632155511010f5510320f5502010055 +0100011f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f0001 +4f00018016010501b80190b154532b2b4bb807ff524bb007505bb00188b02553b00188b04051 +5ab00688b000555a5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d +594bb0805358b0101db11600425973747374752b2b2b2b2b017374752b2b2b00742b2b737375 +2b2b2b012b2b2b002b2b2b2b2b2b012b2b002b2b012b732b00747374757374732b012b747500 +732b73740173737400737474737473015e73737473730073732b7373012b002b012b00732b74 +752b2b2b2b2b2b2b2b2b2b2b012b2b742b2b5e732b002b5e7374012b2b2b002b73735e737373 +01737373002b2b2b2b2b2b185e0000> +] def +/f-1-0 currentdict end definefont pop +%%EndResource +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 7 7 685 376 +%%EndPageSetup +q 7 7 678 369 rectclip +1 0 0 -1 0 385 cm q +1 g +75 86.25 m 176.25 86.25 l 181.25 86.25 183.75 88.75 183.75 93.75 c 183.75 + 147.75 l 183.75 152.75 181.25 155.25 176.25 155.25 c 75 155.25 l 70 155.25 + 67.5 152.75 67.5 147.75 c 67.5 93.75 l 67.5 88.75 70 86.25 75 86.25 c h +75 86.25 m f +0 g +0.75 w +0 J +0 j +[] 0.0 d +10 M q 1 0 0 1 0 0 cm +75 86.25 m 176.25 86.25 l 181.25 86.25 183.75 88.75 183.75 93.75 c 183.75 + 147.75 l 183.75 152.75 181.25 155.25 176.25 155.25 c 75 155.25 l 70 155.25 + 67.5 152.75 67.5 147.75 c 67.5 93.75 l 67.5 88.75 70 86.25 75 86.25 c h +75 86.25 m S Q +q 1 0 0 1 0 0 cm +67.5 105 m 183.75 105 l S Q +BT +9.75 0 0 -9.75 111.803101 100.875 Tm +/f-0-0 1 Tf +(Pause)Tj +/f-1-0 1 Tf +-4.159292 -1.769231 Td +(do/enable PlayPauseBtn)Tj +0 -1.153846 Td +[(do/enable )55(AddBallBtn)]TJ +0 -1.153846 Td +[(do/disable ChangeV)55(elBtn)]TJ +0 -1.153846 Td +(do/enable ResetBtn)Tj +ET +1 g +321 86.25 m 420.086 86.25 l 425.086 86.25 427.586 88.75 427.586 93.75 c + 427.586 147.75 l 427.586 152.75 425.086 155.25 420.086 155.25 c 321 155.25 + l 316 155.25 313.5 152.75 313.5 147.75 c 313.5 93.75 l 313.5 88.75 316 +86.25 321 86.25 c h +321 86.25 m f +0 g +q 1 0 0 1 0 0 cm +321 86.25 m 420.086 86.25 l 425.086 86.25 427.586 88.75 427.586 93.75 c + 427.586 147.75 l 427.586 152.75 425.086 155.25 420.086 155.25 c 321 155.25 + l 316 155.25 313.5 152.75 313.5 147.75 c 313.5 93.75 l 313.5 88.75 316 +86.25 321 86.25 c h +321 86.25 m S Q +q 1 0 0 1 0 0 cm +313.5 105 m 427.586 105 l S Q +BT +9.75 0 0 -9.75 349.947876 100.875 Tm +/f-0-0 1 Tf +(Add Balls)Tj +/f-1-0 1 Tf +-3.353628 -1.769231 Td +(do/enable PlayPauseBtn)Tj +0 -1.153846 Td +[(do/enable )55(AddBallBtn)]TJ +0 -1.153846 Td +[(do/disable changeV)55(elBtn)]TJ +0 -1.153846 Td +(do/enable ResetBtn)Tj +ET +1 g +573 86.25 m 672.633 86.25 l 677.633 86.25 680.133 88.75 680.133 93.75 c + 680.133 147.75 l 680.133 152.75 677.633 155.25 672.633 155.25 c 573 155.25 + l 568 155.25 565.5 152.75 565.5 147.75 c 565.5 93.75 l 565.5 88.75 568 +86.25 573 86.25 c h +573 86.25 m f +0 g +q 1 0 0 1 0 0 cm +573 86.25 m 672.633 86.25 l 677.633 86.25 680.133 88.75 680.133 93.75 c + 680.133 147.75 l 680.133 152.75 677.633 155.25 672.633 155.25 c 573 155.25 + l 568 155.25 565.5 152.75 565.5 147.75 c 565.5 93.75 l 565.5 88.75 568 +86.25 573 86.25 c h +573 86.25 m S Q +q 1 0 0 1 0 0 cm +565.5 105 m 680.133 105 l S Q +BT +9.75 0 0 -9.75 587.584717 100.875 Tm +/f-0-0 1 Tf +[(Change V)55(elocity)]TJ +/f-1-0 1 Tf +-1.880484 -1.769231 Td +(do/enable PlayPauseBtn)Tj +0 -1.153846 Td +[(do/disable )55(AddBallBtn)]TJ +0 -1.153846 Td +[(do/enable ChangeV)55(elBtn)]TJ +0 -1.153846 Td +(do/enable ResetBtn)Tj +ET +1 g +573 266.25 m 676.414 266.25 l 681.414 266.25 683.914 268.75 683.914 273.75 + c 683.914 327.75 l 683.914 332.75 681.414 335.25 676.414 335.25 c 573 335.25 + l 568 335.25 565.5 332.75 565.5 327.75 c 565.5 273.75 l 565.5 268.75 568 + 266.25 573 266.25 c h +573 266.25 m f +0 g +q 1 0 0 1 0 0 cm +573 266.25 m 676.414 266.25 l 681.414 266.25 683.914 268.75 683.914 273.75 + c 683.914 327.75 l 683.914 332.75 681.414 335.25 676.414 335.25 c 573 335.25 + l 568 335.25 565.5 332.75 565.5 327.75 c 565.5 273.75 l 565.5 268.75 568 + 266.25 573 266.25 c h +573 266.25 m S Q +q 1 0 0 1 0 0 cm +565.5 285 m 683.914 285 l S Q +BT +9.75 0 0 -9.75 604.92334 280.875 Tm +/f-0-0 1 Tf +(Dragging)Tj +/f-1-0 1 Tf +-3.658804 -1.769231 Td +(do/disable PlayPauseBtn)Tj +0 -1.153846 Td +[(do/disable )55(AddBallBtn)]TJ +0 -1.153846 Td +[(do/disable ChangeV)55(elBtn)]TJ +0 -1.153846 Td +(do/disable ResetBtn)Tj +ET +1 g +321 266.25 m 420.633 266.25 l 425.633 266.25 428.133 268.75 428.133 273.75 + c 428.133 327.75 l 428.133 332.75 425.633 335.25 420.633 335.25 c 321 335.25 + l 316 335.25 313.5 332.75 313.5 327.75 c 313.5 273.75 l 313.5 268.75 316 + 266.25 321 266.25 c h +321 266.25 m f +0 g +q 1 0 0 1 0 0 cm +321 266.25 m 420.633 266.25 l 425.633 266.25 428.133 268.75 428.133 273.75 + c 428.133 327.75 l 428.133 332.75 425.633 335.25 420.633 335.25 c 321 335.25 + l 316 335.25 313.5 332.75 313.5 327.75 c 313.5 273.75 l 313.5 268.75 316 + 266.25 321 266.25 c h +321 266.25 m S Q +q 1 0 0 1 0 0 cm +313.5 285 m 428.133 285 l S Q +BT +9.75 0 0 -9.75 347.784119 280.875 Tm +/f-0-0 1 Tf +(Select Ball)Tj +/f-1-0 1 Tf +-3.131704 -1.769231 Td +(do/enable PlayPauseBtn)Tj +0 -1.153846 Td +[(do/enable )55(AddBallBtn)]TJ +0 -1.153846 Td +[(do/enable ChangeV)55(elBtn)]TJ +0 -1.153846 Td +(do/enable ResetBtn)Tj +ET +1 g +81 266.25 m 182.25 266.25 l 187.25 266.25 189.75 268.75 189.75 273.75 c + 189.75 327.75 l 189.75 332.75 187.25 335.25 182.25 335.25 c 81 335.25 l + 76 335.25 73.5 332.75 73.5 327.75 c 73.5 273.75 l 73.5 268.75 76 266.25 + 81 266.25 c h +81 266.25 m f +0 g +q 1 0 0 1 0 0 cm +81 266.25 m 182.25 266.25 l 187.25 266.25 189.75 268.75 189.75 273.75 c + 189.75 327.75 l 189.75 332.75 187.25 335.25 182.25 335.25 c 81 335.25 l + 76 335.25 73.5 332.75 73.5 327.75 c 73.5 273.75 l 73.5 268.75 76 266.25 + 81 266.25 c h +81 266.25 m S Q +q 1 0 0 1 0 0 cm +73.5 285 m 189.75 285 l S Q +BT +9.75 0 0 -9.75 122.142517 280.875 Tm +/f-0-0 1 Tf +(Play)Tj +/f-1-0 1 Tf +-4.604361 -1.769231 Td +(do/enable PlayPauseBtn)Tj +0 -1.153846 Td +[(do/disable )55(AddBallBtn)]TJ +0 -1.153846 Td +[(do/disable ChangeV)55(elBtn)]TJ +0 -1.153846 Td +(do/disable ResetBtn)Tj +ET +103.5 33.375 m 103.5 29.441 106.691 26.25 110.625 26.25 c 114.559 26.25 + 117.75 29.441 117.75 33.375 c 117.75 37.309 114.559 40.5 110.625 40.5 c + 106.691 40.5 103.5 37.309 103.5 33.375 c h +103.5 33.375 m f +q 1 0 0 1 0 0 cm +110.25 40.5 m 110.25 86.25 l S Q +q 1 0 0 1 0 0 cm +107.094 78.629 m 110.25 86.25 l 113.406 78.629 l S Q +q 1 0 0 1 0 0 cm +151.5 266.25 m 151.5 155.25 l S Q +q 1 0 0 1 0 0 cm +154.656 162.871 m 151.5 155.25 l 148.344 162.871 l S Q +BT +9.75 0 0 -9.75 157.125 262.875 Tm +/f-1-0 1 Tf +(PlayPauseBtn.clicked)Tj +ET +q 1 0 0 1 0 0 cm +183.75 98.25 m 313.5 98.25 l S Q +q 1 0 0 1 0 0 cm +305.879 101.406 m 313.5 98.25 l 305.879 95.094 l S Q +BT +9.75 0 0 -9.75 208.125 91.875 Tm +/f-1-0 1 Tf +(AddBallBtn.clicked)Tj +ET +q 1 0 0 1 0 0 cm +184.5 147 m 246.5 174.5 298.75 214 341.25 265.5 c S Q +q 1 0 0 1 0 0 cm +333.965 261.629 m 341.25 265.5 l 338.832 257.613 l S Q +BT +9.75 0 0 -9.75 288.375 203.625 Tm +/f-1-0 1 Tf +(Ball.selected)Tj +ET +q 1 0 0 1 0 0 cm +312.75 300.75 m 190.5 300.75 l S Q +q 1 0 0 1 0 0 cm +198.121 297.594 m 190.5 300.75 l 198.121 303.906 l S Q +BT +9.75 0 0 -9.75 203.625 316.875 Tm +/f-1-0 1 Tf +(PlayPauseBtn.clicked)Tj +ET +q 1 0 0 1 0 0 cm +312.75 280.5 m 253.25 259 199.75 217.5 152.25 156 c S Q +q 1 0 0 1 0 0 cm +159.406 160.102 m 152.25 156 l 154.41 163.961 l S Q +BT +9.75 0 0 -9.75 227.625 226.125 Tm +/f-1-0 1 Tf +(!Ball.selected)Tj +ET +q 1 0 0 1 0 0 cm +370.5 266.25 m 370.5 155.25 l S Q +q 1 0 0 1 0 0 cm +373.656 162.871 m 370.5 155.25 l 367.344 162.871 l S Q +BT +9.75 0 0 -9.75 378.567261 214.875 Tm +/f-1-0 1 Tf +(AddBallBtn.clicked)Tj +ET +q 1 0 0 1 0 0 cm +429 273.75 m 500 240.75 554.5 201.5 592.5 156 c S Q +q 1 0 0 1 0 0 cm +590.039 163.875 m 592.5 156 l 585.191 159.828 l S Q +BT +9.75 0 0 -9.75 549.567261 212.625 Tm +/f-1-0 1 Tf +[(ChangeV)55(elBtn.clicked)]TJ +ET +q 1 0 0 1 0 0 cm +428.25 320.25 m 565.5 320.25 l S Q +q 1 0 0 1 0 0 cm +557.879 323.406 m 565.5 320.25 l 557.879 317.094 l S Q +BT +9.75 0 0 -9.75 461.625 313.875 Tm +/f-1-0 1 Tf +(Mouse.dragging)Tj +ET +q 1 0 0 1 0 0 cm +565.5 278.25 m 428.25 278.25 l S Q +q 1 0 0 1 0 0 cm +435.871 275.094 m 428.25 278.25 l 435.871 281.406 l S Q +BT +9.75 0 0 -9.75 461.148743 274.875 Tm +/f-1-0 1 Tf +(Mouse.released)Tj +ET +q 1 0 0 1 0 0 cm +623.25 85.5 m 624.75 46 543.5 26.25 379.5 26.25 c 215.5 26.25 131.75 46 + 128.25 85.5 c S Q +q 1 0 0 1 0 0 cm +125.777 77.629 m 128.25 85.5 l 132.066 78.188 l S Q +BT +9.75 0 0 -9.75 346.875 16.875 Tm +/f-1-0 1 Tf +(Mouse.clicked)Tj +ET +q 1 0 0 1 0 0 cm +313.5 140.25 m 183.75 140.25 l S Q +q 1 0 0 1 0 0 cm +191.371 137.094 m 183.75 140.25 l 191.371 143.406 l S Q +BT +9.75 0 0 -9.75 208.125 131.625 Tm +/f-1-0 1 Tf +(AddBallBtn.clicked)Tj +ET +q 1 0 0 1 0 0 cm +349.5 335.25 m 349.5 362.25 l 397.5 362.25 l 397.5 335.25 l S Q +q 1 0 0 1 0 0 cm +400.656 342.871 m 397.5 335.25 l 394.344 342.871 l S Q +BT +9.75 0 0 -9.75 303.375 377.625 Tm +/f-1-0 1 Tf +(Mouse.clicked and Ball.selected)Tj +ET +q 1 0 0 1 0 0 cm +103.5 155.25 m 103.5 266.25 l S Q +q 1 0 0 1 0 0 cm +100.344 258.629 m 103.5 266.25 l 106.656 258.629 l S Q +BT +9.75 0 0 -9.75 7.125 214.875 Tm +/f-1-0 1 Tf +(PlayPauseBtn.clicked)Tj +ET +q 1 0 0 1 0 0 cm +370.5 86.25 m 370.5 71.25 l 451.5 71.25 l 451.5 120.75 l 427.5 120.75 l + S Q +q 1 0 0 1 0 0 cm +435.121 117.594 m 427.5 120.75 l 435.121 123.906 l S Q +BT +9.75 0 0 -9.75 385.875 64.875 Tm +/f-1-0 1 Tf +(Mouse.clicked)Tj +ET +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/process/organizational-sprint.md b/process/organizational-sprint.md index e3086943..1ef5d3a1 100644 --- a/process/organizational-sprint.md +++ b/process/organizational-sprint.md @@ -8,6 +8,8 @@ - Test passano - Codice documentato (Scaladoc) - Code review + - Coverage + - Formattazione codice - Cadenza dei meeting: - Cadenza dei meeting una volta a settimana. - Preparazione della build diff --git a/process/product-backlog.csv b/process/product-backlog.csv index b89a014b..276828c7 100644 --- a/process/product-backlog.csv +++ b/process/product-backlog.csv @@ -1,15 +1,15 @@ -Priority,Description,URL,Estimation size,1,2,3,4,5,6 -1,Setting up the build environment,,10,0,0,0,0,0,0 -1,Deepen our knowledge of the ECS pattern,https://skypjack.github.io/,20,0,0,0,0,0,0 -1,Deepen our knowledge of Scala 3,https://docs.scala-lang.org/scala3/new-in-scala3.html,30,0,0,0,0,0,0 -1,Design architecture,,10,0,0,0,0,0,0 -2,As a framework user I want to create a World,,20,20,0,0,0,0,0 -2,As a framework user I want to manipulate the World's Entities,,20,20,0,0,0,0,0 -2,As a framework user I want to manipulate the Entities' Components,,20,20,0,0,0,0,0 -2,As a framework user I want to define World's Views,,30,30,22,0,0,0,0 -2,As a framework user I want to define and use Systems,,30,30,5,20,0,0,0 -2,As a framework user I want to update the World's state,,5,5,5,5,0,0,0 -3,As a framework I want the framework to be able to update the state of at least 10'000 Entities in less than 10ms,,50,50,50,0,0,0,0 -3,As a framework user I would higly appreciate a handy DSL to perform these operations,,40,40,40,15,3,1,16 -3,As a framework user I want to define World's Views excluding specific components,,10,20,20,20,20,0,0 -4,As a framework user I want a working example of the framework,,15,15,15,15,15,10,10 +Priority,Description,URL,Estimation size,1,2,3,4,5,6,7,8 +1,Setting up the build environment,,10,0,0,0,0,0,0,0,0 +1,Deepen our knowledge of the ECS pattern,https://skypjack.github.io/,20,0,0,0,0,0,0,0,0 +1,Deepen our knowledge of Scala 3,https://docs.scala-lang.org/scala3/new-in-scala3.html,30,0,0,0,0,0,0,0,0 +1,Design architecture,,10,0,0,0,0,0,0,0,0 +2,As a framework user I want to create a World,,20,20,0,0,0,0,0,0,0 +2,As a framework user I want to manipulate the World's Entities,,20,20,0,0,0,0,0,0,0 +2,As a framework user I want to manipulate the Entities' Components,,20,20,0,0,0,0,0,0,0 +2,As a framework user I want to define World's Views,,30,30,22,0,0,0,0,0,0 +2,As a framework user I want to define and use Systems,,30,30,5,20,0,0,0,0,0 +2,As a framework user I want to update the World's state,,5,5,5,5,0,0,0,0,0 +3,As a framework I want the framework to be able to update the state of at least 10'000 Entities in less than 10ms,,50,50,50,0,0,0,0,0,0 +3,As a framework user I would higly appreciate a handy DSL to perform these operations,,40,40,40,15,3,1,16,13,0 +3,As a framework user I want to define World's Views excluding specific components,,10,20,20,20,20,0,0,0,0 +4,As a framework user I want a working example of the framework,,15,15,15,15,15,10,10,5,0 diff --git a/process/sprint2.csv b/process/sprint2.csv index 84e06407..2bc63de5 100644 --- a/process/sprint2.csv +++ b/process/sprint2.csv @@ -1,7 +1,6 @@ Sprint 2 (da 15/08/2021 a 22/08/2021),,,,,,,,,,, Product Backlog Item,Sprint Task,URL,Volunteer,Initial estimate of effort,1,2,3,4,5,6,7 -As a framework user I want to create a World,"Define a Sparse Set data structure ",,"Nicolas Farabegoli, Nicolò Di Domenico",10,8,8,2,0,0,0,0 -,Define the World type,,Nicolas Farabegoli,2,0,0,0,0,0,0,0 +As a framework user I want to create a World,Define the World type,,Nicolas Farabegoli,2,0,0,0,0,0,0,0 ,Design detailed World's architecture,,"Nicolas Farabegoli, Linda Vitali, Nicolò Di Domenico, Giacomo Cavalieri",8,6,2,2,2,2,2,2 As a framework user I want to manipulate the World's Entities,Define Entities type,,Nicolas Farabegoli,2,0,0,0,0,0,0,0 ,Design detailed Entity's architecture,,"Nicolas Farabegoli, Linda Vitali, Nicolò Di Domenico, Giacomo Cavalieri",8,8,2,2,2,2,2,2 diff --git a/process/sprint7.csv b/process/sprint7.csv index 29aa50a4..329f7de4 100644 --- a/process/sprint7.csv +++ b/process/sprint7.csv @@ -1,11 +1,11 @@ -Sprint 7 (da 21/09/2021 a 26/09/2021),,,,,,,,,,, -Product Backlog Item,Sprint Task,URL,Volunteer,Initial estimate of effort,1,2,3,4,5,6,7 -As a framework user I want a working example of the framework,Handle balls collisions,,Nicolò Di Domenico,7,,,,,,, -,Update balls position,,Linda Vitali,1,,,,,,, -,Balls rendering,,Linda Vitali,1,,,,,,, -,Handle balls creation,,Nicolas Farabegoli,2,,,,,,, -,Handle balls drag and drop,,Nicolas Farabegoli,4,,,,,,, -,Handle balls velocity editing,,Giacomo Cavalieri,4,,,,,,, -,Create demo UI,,Linda Vitali,1,,,,,,, -As a framework user I would higly appreciate a handy DSL to perform these operations,Complete DSL for Systems,,Linda Vitali,1,,,,,,, -,Refactor World's interface,,Giacomo Cavalieri,15,,,,,,, \ No newline at end of file +Sprint 7 (da 21/09/2021 a 26/09/2021),,,,,,,,,,, +Product Backlog Item,Sprint Task,URL,Volunteer,Initial estimate of effort,1,2,3,4,5,6,7 +As a framework user I want a working example of the framework,Handle balls collisions,,Nicolò Di Domenico,7,6,6,4,4,2,1,0 +,Update balls position,,Linda Vitali,1,1,1,1,1,0,0,0 +,Balls rendering,,Linda Vitali,1,1,1,1,1,1,0,0 +,Handle balls creation,,Nicolas Farabegoli,2,2,2,2,2,0,0,0 +,Handle balls drag and drop,,Nicolas Farabegoli,4,4,4,4,2,0,0,0 +,Handle balls velocity editing,,Giacomo Cavalieri,4,4,4,4,4,4,2,0 +,Create demo UI,,Linda Vitali,1,1,1,1,1,0,0,0 +As a framework user I would higly appreciate a handy DSL to perform these operations,Complete DSL for Systems,,Linda Vitali,1,1,1,1,1,1,1,1 +,Refactor World's interface,,Giacomo Cavalieri,15,15,15,15,15,15,15,10 diff --git a/process/sprint8.csv b/process/sprint8.csv new file mode 100644 index 00000000..246cae2d --- /dev/null +++ b/process/sprint8.csv @@ -0,0 +1,9 @@ +Sprint 8 (da 28/09/2021 a 05/09/2021),,,,,,,,,,, +Product Backlog Item,Sprint Task,URL,Volunteer,Initial estimate of effort,1,2,3,4,5,6,7 +,Improve CList implementation,,Giacomo Cavalieri,2,2,2,0,0,0,0,0 +As a framework user I want a working example of the framework,Improve PlayState in demo,,Nicolò Di Domenico Nicolas Farabegoli,3,3,3,3,3,3,0,0 +,Add parameters tuning to demo,,Nicolas Farabegoli,1,1,1,0,0,0,0,0 +As a framework user I would higly appreciate a handy DSL to perform these operations,Complete DSL for Systems,,Linda Vitali,1,0,0,0,0,0,0,0 +,Refactor World's interface,,Giacomo Cavalieri,10,0,0,0,0,0,0,0 +,Use new System builder in tests,,Giacomo Cavalieri,1,1,1,0,0,0,0,0 +,Add DSL methods (world -= entity;world += system;world -= system),,Linda Vitali,1,1,1,1,0,0,0,0 \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index 5695624a..f2ee4e90 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,6 +1,8 @@ addSbtPlugin("com.github.sbt" % "sbt-jacoco" % "3.3.0") -addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.9.5") +addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.13.0") addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.7") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.3") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.1.0") +resolvers += Resolver.jcenterRepo +addSbtPlugin("net.aichler" % "sbt-jupiter-interface" % "0.8.4")