diff options
Diffstat (limited to 'rushs')
505 files changed, 30658 insertions, 0 deletions
diff --git a/rushs/creeps/.gitignore b/rushs/creeps/.gitignore new file mode 100644 index 0000000..1178b61 --- /dev/null +++ b/rushs/creeps/.gitignore @@ -0,0 +1,31 @@ +*.swp +.idea +.vertx +javadoc +server + +*.class +*.log +*.ctxt +.mtj.tmp/ +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar +hs_err_pid* +replay_pid* +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.project +.classpath diff --git a/rushs/creeps/README.md b/rushs/creeps/README.md new file mode 100644 index 0000000..ff39656 --- /dev/null +++ b/rushs/creeps/README.md @@ -0,0 +1,57 @@ +# Creeps. + +## Brief + +This document is a quick overview of the creeps given files. + +## What's in the archive + +In the provided archive you will find the following files: + + * `README.md`: this file. + * `pom.xml`: the sample maven project file that you must use for your project. + * `creeps-server.jar`: the server, for you to train on. + * `given.jar`: a compiled java library to help you in your endeavor. + * `given-javadoc.jar`: given library documentation, can be extracted with `jar xf`. + +## Installing the given jar to your local repository + + * Make sure the folder `~/.m2/repository/` exists, if not create it + (assuming you have built maven projects before, the folder should already + exist). + * Run the command `mvn install:install-file -Dfile=server/given.jar -DgroupId=com.epita -DartifactId=given -Dversion=3.0-SNAPSHOT -Dpackaging=jar`. + * You should be good to use the provided pom.xml file. + +In case the assistants publish a new version of the file, simply repeat the process again. + +### First run: + +`java -jar creeps-server.jar --printAchievements=true` will print +the list of all achievements you can get. + +### Tutorial: + +`java -jar creeps-server.jar --trackAchievements=true --enableEnemies=false --enableGC=false --citizenFeedingRate=100000` +starts the server without enemies, without Hector and without starvation. +Ideal for early development. You can even add `--enableEasyMode=true` earlier +on to help grasping the mechanics of the game. + +### The game, standard configuration: + +`java -jar creeps-server.jar --trackAchievements=true` +starts the server with the setup that will be used on the live server. + +## Web client + +The web client is enabled by default when running the local server. +To use it, you have to connect to `http://localhost:port` where port is +either 1337 by default or the value of the -httpPort option given to the +server. + +## Documentation + +The documentation is generated using Javadoc. +To use it, you can extract `given-javadoc.jar` with `jar xf`. +You can then open the `index.html` file using any web browser. + + diff --git a/rushs/creeps/pom.xml b/rushs/creeps/pom.xml new file mode 100644 index 0000000..93bc9eb --- /dev/null +++ b/rushs/creeps/pom.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>com.epita</groupId> + <version>1.0.0-SNAPSHOT</version> + <artifactId>creeps</artifactId> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>17</maven.compiler.source> + <maven.compiler.target>17</maven.compiler.target> + <maven.compiler.release>17</maven.compiler.release> + + <jackson.version>2.9.7</jackson.version> + <logback-classic.version>1.2.3</logback-classic.version> + <slf4j-api.version>1.7.25</slf4j-api.version> + <unirest.version>1.4.9</unirest.version> + <validation-api.version>2.0.1.Final</validation-api.version> + <junit-jupiter.version>5.4.0-M1</junit-jupiter.version> + <given.version>3.0-SNAPSHOT</given.version> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>3.1.1</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <transformers> + <transformer + implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> + <manifestEntries> + <Main-Class>com/epita/creeps/Program</Main-Class> + </manifestEntries> + </transformer> + </transformers> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>17</source> + <target>17</target> + </configuration> + </plugin> + + </plugins> + </build> + + <dependencies> + + <dependency> + <groupId>com.epita</groupId> + <artifactId>given</artifactId> + <version>${given.version}</version> + </dependency> + + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.30</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j-api.version}</version> + </dependency> + + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>${logback-classic.version}</version> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>${jackson.version}</version> + </dependency> + + <dependency> + <groupId>com.mashape.unirest</groupId> + <artifactId>unirest-java</artifactId> + <version>${unirest.version}</version> + </dependency> + + <dependency> + <groupId>javax.validation</groupId> + <artifactId>validation-api</artifactId> + <version>${validation-api.version}</version> + </dependency> + + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>${junit-jupiter.version}</version> + <scope>test</scope> + </dependency> + + </dependencies> +</project> diff --git a/rushs/creeps/src/main/java/com/epita/creeps/Program.java b/rushs/creeps/src/main/java/com/epita/creeps/Program.java new file mode 100644 index 0000000..30d669f --- /dev/null +++ b/rushs/creeps/src/main/java/com/epita/creeps/Program.java @@ -0,0 +1,91 @@ +package com.epita.creeps; + +import com.epita.creeps.given.exception.NoReportException; +import com.epita.creeps.given.extra.Cartographer; +import com.epita.creeps.given.json.Json; +import com.epita.creeps.given.vo.Tile; +import com.epita.creeps.given.vo.parameter.FireParameter; +import com.epita.creeps.given.vo.report.*; +import com.epita.creeps.given.vo.response.CommandResponse; +import com.epita.creeps.given.vo.response.InitResponse; +import com.epita.creeps.tools.ToolSet; +import com.mashape.unirest.http.HttpResponse; +import com.mashape.unirest.http.JsonNode; +import com.mashape.unirest.http.Unirest; +import com.mashape.unirest.http.exceptions.UnirestException; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +public class Program { + public static void main(String[] args) { + String hostName = args[0]; + String portNumber = args[1]; + String userName = args[2]; + + ToolSet tools = new ToolSet("http://" + hostName + ":" + portNumber); + Cartographer cartographer = Cartographer.INSTANCE; + String initRequest = tools.BuildRequest("/init/" + userName); + try { + HttpResponse<JsonNode> request = Unirest.post(initRequest).body("{}").asJson(); + InitResponse initialized = Json.parse(request.getBody().getObject().toString(), InitResponse.class); + ToolSet.setHectorRate(initialized.setup.gcTickRate); + long timeTilGC = ToolSet.nextHectorPass(initialized.tick) - initialized.tick; + while (true) { + double moveTime = initialized.costs.move.cast / initialized.setup.ticksPerSeconds; //timeTilGC; + // MOVE UP + + request = Unirest.post(tools.BuildRequest("/command/" + initialized.login + "/" + initialized.citizen1Id + "/move:up")).asJson(); + + // GATHER + CommandResponse cr = Json.parse(request.getBody().getObject().toString(), CommandResponse.class); + final String rid = cr.reportId; + request = CompletableFuture.supplyAsync(() -> { + try { + + return Unirest.get(tools.BuildRequest("/report/" + rid)).asJson(); + } catch (UnirestException e) { + throw new RuntimeException(e); + } + }, CompletableFuture.delayedExecutor((long) (moveTime), TimeUnit.SECONDS)).join(); + + MoveReport mr = Json.parse(request.getBody().getObject().toString(), MoveReport.class); + cartographer.register(mr); + + if (cartographer.requestTileType(mr.newPosition) == Tile.Food || cartographer.requestTileType(mr.newPosition) == Tile.Oil || cartographer.requestTileType(mr.newPosition) == Tile.Wood || cartographer.requestTileType(mr.newPosition) == Tile.Rock) { + double gatherTime = initialized.costs.gather.cast / initialized.setup.ticksPerSeconds; + + request = CompletableFuture.supplyAsync(() -> { + try { + return Unirest.post(tools.BuildRequest("/command/" + initialized.login + "/" + initialized.citizen1Id + "/gather")).asJson(); + } catch (UnirestException e) { + throw new RuntimeException(e); + } + }, CompletableFuture.delayedExecutor((long) gatherTime, TimeUnit.SECONDS)).thenApplyAsync(i -> i, CompletableFuture.delayedExecutor((long) (gatherTime), TimeUnit.SECONDS)).join(); + } + + // cr = Json.parse(request.getBody().getObject().toString(), CommandResponse.class); + //request = Unirest.get(tools.BuildRequest("/report/" + cr.reportId)).asJson(); + // GatherReport gr = Json.parseReport(request.getBody().getObject().toString()); + double roadBuildTime = initialized.costs.buildRoad.cast / initialized.setup.ticksPerSeconds; // + ToolSet.nextHectorPass(mr.tick) - mr.tick; + + // BUILD ROAD + request = CompletableFuture.supplyAsync(() -> { + try { + return Unirest.post(tools.BuildRequest("/command/" + initialized.login + "/" + initialized.citizen1Id + "/build:road")).asJson(); + } catch (UnirestException e) { + throw new RuntimeException(e); + } + }, CompletableFuture.delayedExecutor((long) roadBuildTime, TimeUnit.SECONDS)).thenApplyAsync(i -> i, CompletableFuture.delayedExecutor((long) (roadBuildTime), TimeUnit.SECONDS)).join(); + + cr = Json.parse(request.getBody().getObject().toString(), CommandResponse.class); + request = Unirest.get(tools.BuildRequest("/report/" + cr.reportId)).asJson(); + BuildReport br = Json.parseReport(request.getBody().getObject().toString()); + timeTilGC = ToolSet.nextHectorPass(br.tick) - br.tick; + } + } catch (UnirestException | NoReportException e) { + throw new RuntimeException(e); + } + } +}
\ No newline at end of file diff --git a/rushs/creeps/src/main/java/com/epita/creeps/tools/ToolSet.java b/rushs/creeps/src/main/java/com/epita/creeps/tools/ToolSet.java new file mode 100644 index 0000000..553be1f --- /dev/null +++ b/rushs/creeps/src/main/java/com/epita/creeps/tools/ToolSet.java @@ -0,0 +1,37 @@ +package com.epita.creeps.tools; + +import com.mashape.unirest.http.Unirest; +import com.mashape.unirest.http.exceptions.UnirestException; +import lombok.Getter; +import lombok.Setter; + +public class ToolSet { + static String sampleRequest; + + @Setter + @Getter + static long hectorRate; + + public ToolSet(String sampleRequest) { + ToolSet.sampleRequest = sampleRequest; + } + + public String BuildRequest(String endPoint) { + return sampleRequest + endPoint; + } + + public void GetReport(String reportId) { + String request = BuildRequest("/report/" + reportId); + try { + Unirest.get(request).asJson(); + } catch (UnirestException e) { + throw new RuntimeException(e); + } + } + public static long nextHectorPass(long tick) { + if (tick % hectorRate != 0) { + return tick + (hectorRate - tick % hectorRate); + } + return tick; + } +} diff --git a/rushs/creeps/viewer/assets/index-1d12f9a3.css b/rushs/creeps/viewer/assets/index-1d12f9a3.css new file mode 100644 index 0000000..85d5e5c --- /dev/null +++ b/rushs/creeps/viewer/assets/index-1d12f9a3.css @@ -0,0 +1 @@ +*{padding:0;margin:0;box-sizing:border-box}img{display:block;width:100%;height:100%}main{background-color:#1b1f24;height:100vh;width:100vw;color:#cfcfd2;font-family:Rubik,sans-serif;padding:32px}@media (max-width: 700px){main{padding:8px}}button{padding:8px 16px;border:none;background-color:#1b1f24;box-shadow:#000 2px 2px 10px;transition:.2s linear;color:#fff;cursor:not-allowed;display:flex;justify-content:center;align-items:center}button:enabled{background-color:#1b1f24;cursor:pointer}button:enabled:hover{transform:rotate(-3deg)}button svg{width:12px;height:12px;background-color:transparent;fill:#fff;margin-right:8px}._toastItem.svelte-j9nwjb{width:var(--toastWidth, 16rem);height:var(--toastHeight, auto);min-height:var(--toastMinHeight, 3.5rem);margin:var(--toastMargin, 0 0 .5rem 0);padding:var(--toastPadding, 0);background:var(--toastBackground, rgba(66, 66, 66, .9));color:var(--toastColor, #fff);box-shadow:var(--toastBoxShadow, 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06));border:var(--toastBorder, none);border-radius:var(--toastBorderRadius, .125rem);position:relative;display:flex;flex-direction:row;align-items:center;overflow:hidden;will-change:transform,opacity;-webkit-tap-highlight-color:transparent}._toastMsg.svelte-j9nwjb{padding:var(--toastMsgPadding, .75rem .5rem);flex:1 1 0%}.pe.svelte-j9nwjb,._toastMsg.svelte-j9nwjb a{pointer-events:auto}._toastBtn.svelte-j9nwjb{width:2rem;height:100%;font:1rem sans-serif;display:flex;align-items:center;justify-content:center;cursor:pointer;outline:none}._toastBar.svelte-j9nwjb{top:var(--toastBarTop, auto);right:var(--toastBarRight, auto);bottom:var(--toastBarBottom, 0);left:var(--toastBarLeft, 0);height:var(--toastBarHeight, 6px);width:var(--toastBarWidth, 100%);position:absolute;display:block;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;background:transparent;pointer-events:none}._toastBar.svelte-j9nwjb::-webkit-progress-bar{background:transparent}._toastBar.svelte-j9nwjb::-webkit-progress-value{background:var(--toastProgressBackground, var(--toastBarBackground, rgba(33, 150, 243, .75)))}._toastBar.svelte-j9nwjb::-moz-progress-bar{background:var(--toastProgressBackground, var(--toastBarBackground, rgba(33, 150, 243, .75)))}._toastContainer.svelte-7xr3c1{top:var(--toastContainerTop, 1.5rem);right:var(--toastContainerRight, 2rem);bottom:var(--toastContainerBottom, auto);left:var(--toastContainerLeft, auto);position:fixed;margin:0;padding:0;list-style-type:none;pointer-events:none;z-index:9999}.listing.svelte-16l7oqr.svelte-16l7oqr{padding:8px 16px;height:100vh;overflow-y:auto}.title.svelte-16l7oqr.svelte-16l7oqr{font-size:1.5em;font-weight:700;padding-bottom:32px;padding-top:8px}.item.svelte-16l7oqr.svelte-16l7oqr{display:flex;align-items:center;margin-bottom:8px;justify-content:space-between}.item.svelte-16l7oqr div.svelte-16l7oqr{display:flex;align-items:center}.item.svelte-16l7oqr img.svelte-16l7oqr{width:28px;margin-right:8px}.item.svelte-16l7oqr button.svelte-16l7oqr{margin-left:8px}.svelte-ktxllv{box-sizing:border-box}.bg.svelte-ktxllv{position:fixed;z-index:1000;top:0;left:0;display:flex;flex-direction:column;justify-content:center;width:100vw;height:100vh;background:rgba(0,0,0,.66)}.window-wrap.svelte-ktxllv{position:relative;margin:2rem;max-height:100%}.window.svelte-ktxllv{position:relative;width:40rem;max-width:100%;max-height:100%;margin:2rem auto;color:#000;border-radius:.5rem;background:white}.content.svelte-ktxllv{position:relative;padding:1rem;max-height:calc(100vh - 4rem);overflow:auto}.close.svelte-ktxllv{display:block;box-sizing:border-box;position:absolute;z-index:1000;top:1rem;right:1rem;margin:0;padding:0;width:1.5rem;height:1.5rem;border:0;color:#000;border-radius:1.5rem;background:white;box-shadow:0 0 0 1px #000;transition:transform .2s cubic-bezier(.25,.1,.25,1),background .2s cubic-bezier(.25,.1,.25,1);-webkit-appearance:none}.close.svelte-ktxllv:before,.close.svelte-ktxllv:after{content:"";display:block;box-sizing:border-box;position:absolute;top:50%;width:1rem;height:1px;background:black;transform-origin:center;transition:height .2s cubic-bezier(.25,.1,.25,1),background .2s cubic-bezier(.25,.1,.25,1)}.close.svelte-ktxllv:before{-webkit-transform:translate(0,-50%) rotate(45deg);-moz-transform:translate(0,-50%) rotate(45deg);transform:translateY(-50%) rotate(45deg);left:.25rem}.close.svelte-ktxllv:after{-webkit-transform:translate(0,-50%) rotate(-45deg);-moz-transform:translate(0,-50%) rotate(-45deg);transform:translateY(-50%) rotate(-45deg);left:.25rem}.close.svelte-ktxllv:hover{background:black}.close.svelte-ktxllv:hover:before,.close.svelte-ktxllv:hover:after{height:2px;background:white}.close.svelte-ktxllv:focus{border-color:#39f;box-shadow:0 0 0 2px #39f}.close.svelte-ktxllv:active{transform:scale(.9)}.close.svelte-ktxllv:hover,.close.svelte-ktxllv:focus,.close.svelte-ktxllv:active{outline:none}div.svelte-1qcloh3{color:#cfcfd2;font-family:Rubik,sans-serif}.title.svelte-1qcloh3{font-size:1.5em;margin-bottom:1em;font-family:Rubik,sans-serif}header.svelte-eeciu1.svelte-eeciu1{background-color:#1b1f24;height:64px;display:flex;justify-content:space-between;align-items:center;padding:8px}header.svelte-eeciu1 .title.svelte-eeciu1{display:flex;color:#fff;font-size:24px;font-weight:700;align-items:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}header.svelte-eeciu1 .title img.svelte-eeciu1{width:32px;height:32px;margin-right:8px}header.svelte-eeciu1 .current-player.svelte-eeciu1{display:flex;align-items:center;gap:16px}.coords.svelte-4b2ujb.svelte-4b2ujb{position:absolute;bottom:4px;left:4px;font-weight:700}button.svelte-4b2ujb.svelte-4b2ujb{position:absolute;opacity:.3}button.svelte-4b2ujb.svelte-4b2ujb:hover{opacity:1}button.up.svelte-4b2ujb.svelte-4b2ujb{top:8px;transform:translate(-50%);left:50%}button.down.svelte-4b2ujb.svelte-4b2ujb{bottom:8px;transform:translate(-50%);left:50%}button.left.svelte-4b2ujb.svelte-4b2ujb{left:8px;transform:translateY(-50%) rotate(-90deg);transform-origin:bottom;top:50%}button.right.svelte-4b2ujb.svelte-4b2ujb{right:8px;transform:translateY(-50%) rotate(90deg);transform-origin:bottom;top:50%}.grid.svelte-4b2ujb.svelte-4b2ujb{max-height:calc(100% - 64px);height:calc(100% - 64px);display:flex;flex-direction:column;position:relative;overflow-y:scroll;background-size:32px!important}.lines.svelte-4b2ujb.svelte-4b2ujb{display:flex;flex-grow:1;flex-shrink:1}.tile.svelte-4b2ujb.svelte-4b2ujb{position:relative}.tile.svelte-4b2ujb>div.svelte-4b2ujb{position:absolute;bottom:0;left:0;font-size:.6em;color:red}.svelte-71xqxf{padding:0;margin:0;box-sizing:border-box}:root{--toastBackground:#2b2f37;--toastColor:#CFCFD2;--toastBarBackground:rgba(255, 69, 61, .8)}main.svelte-71xqxf{display:flex}.game.svelte-71xqxf{width:calc(100% - 300px)}aside.svelte-71xqxf{width:300px;height:100%;box-shadow:-10px 0 10px -10px #00000080} diff --git a/rushs/creeps/viewer/assets/index-ccc860fc.js b/rushs/creeps/viewer/assets/index-ccc860fc.js new file mode 100644 index 0000000..78ce181 --- /dev/null +++ b/rushs/creeps/viewer/assets/index-ccc860fc.js @@ -0,0 +1,7 @@ +var $e=Object.defineProperty;var At=(e,A,t)=>A in e?$e(e,A,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[A]=t;var O=(e,A,t)=>(At(e,typeof A!="symbol"?A+"":A,t),t);(function(){const A=document.createElement("link").relList;if(A&&A.supports&&A.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))n(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const r of i.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&n(r)}).observe(document,{childList:!0,subtree:!0});function t(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerpolicy&&(i.referrerPolicy=s.referrerpolicy),s.crossorigin==="use-credentials"?i.credentials="include":s.crossorigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function n(s){if(s.ep)return;s.ep=!0;const i=t(s);fetch(s.href,i)}})();function p(){}const sA=e=>e;function zA(e,A){for(const t in A)e[t]=A[t];return e}function He(e){return e()}function ue(){return Object.create(null)}function N(e){e.forEach(He)}function eA(e){return typeof e=="function"}function W(e,A){return e!=e?A==A:e!==A||e&&typeof e=="object"||typeof e=="function"}let RA;function k(e,A){return RA||(RA=document.createElement("a")),RA.href=A,e===RA.href}function et(e){return Object.keys(e).length===0}function tt(e,...A){if(e==null)return p;const t=e.subscribe(...A);return t.unsubscribe?()=>t.unsubscribe():t}function Fe(e,A,t){e.$$.on_destroy.push(tt(A,t))}function nt(e,A,t,n){if(e){const s=Re(e,A,t,n);return e[0](s)}}function Re(e,A,t,n){return e[1]&&n?zA(t.ctx.slice(),e[1](n(A))):t.ctx}function st(e,A,t,n){if(e[2]&&n){const s=e[2](n(t));if(A.dirty===void 0)return s;if(typeof s=="object"){const i=[],r=Math.max(A.dirty.length,s.length);for(let o=0;o<r;o+=1)i[o]=A.dirty[o]|s[o];return i}return A.dirty|s}return A.dirty}function it(e,A,t,n,s,i){if(s){const r=Re(A,t,n,i);e.p(r,s)}}function ot(e){if(e.ctx.length>32){const A=[],t=e.ctx.length/32;for(let n=0;n<t;n++)A[n]=-1;return A}return-1}const ke=typeof window<"u";let EA=ke?()=>window.performance.now():()=>Date.now(),VA=ke?e=>requestAnimationFrame(e):p;const lA=new Set;function Ue(e){lA.forEach(A=>{A.c(e)||(lA.delete(A),A.f())}),lA.size!==0&&VA(Ue)}function vA(e){let A;return lA.size===0&&VA(Ue),{promise:new Promise(t=>{lA.add(A={c:e,f:t})}),abort(){lA.delete(A)}}}function D(e,A){e.appendChild(A)}function Oe(e){if(!e)return document;const A=e.getRootNode?e.getRootNode():e.ownerDocument;return A&&A.host?A:e.ownerDocument}function rt(e){const A=h("style");return lt(Oe(e),A),A.sheet}function lt(e,A){D(e.head||e,A)}function I(e,A,t){e.insertBefore(A,t||null)}function v(e){e.parentNode.removeChild(e)}function TA(e,A){for(let t=0;t<e.length;t+=1)e[t]&&e[t].d(A)}function h(e){return document.createElement(e)}function V(e){return document.createTextNode(e)}function R(){return V(" ")}function aA(){return V("")}function U(e,A,t,n){return e.addEventListener(A,t,n),()=>e.removeEventListener(A,t,n)}function f(e,A,t){t==null?e.removeAttribute(A):e.getAttribute(A)!==t&&e.setAttribute(A,t)}function ct(e){return Array.from(e.childNodes)}function hA(e,A){A=""+A,e.wholeText!==A&&(e.data=A)}function gt(e,A,t,n){t===null?e.style.removeProperty(A):e.style.setProperty(A,t,n?"important":"")}function kA(e,A,t){e.classList[t?"add":"remove"](A)}function Ge(e,A,t=!1){const n=document.createEvent("CustomEvent");return n.initCustomEvent(e,t,!1,A),n}class at{constructor(){this.e=this.n=null}c(A){this.h(A)}m(A,t,n=null){this.e||(this.e=h(t.nodeName),this.t=t,this.c(A)),this.i(n)}h(A){this.e.innerHTML=A,this.n=Array.from(this.e.childNodes)}i(A){for(let t=0;t<this.n.length;t+=1)I(this.t,this.n[t],A)}p(A){this.d(),this.h(A),this.i(this.a)}d(){this.n.forEach(v)}}const KA=new Map;let XA=0;function ft(e){let A=5381,t=e.length;for(;t--;)A=(A<<5)-A^e.charCodeAt(t);return A>>>0}function ut(e,A){const t={stylesheet:rt(A),rules:{}};return KA.set(e,t),t}function DA(e,A,t,n,s,i,r,o=0){const l=16.666/n;let c=`{ +`;for(let C=0;C<=1;C+=l){const Q=A+(t-A)*i(C);c+=C*100+`%{${r(Q,1-Q)}} +`}const g=c+`100% {${r(t,1-t)}} +}`,a=`__svelte_${ft(g)}_${o}`,u=Oe(e),{stylesheet:m,rules:d}=KA.get(u)||ut(u,e);d[a]||(d[a]=!0,m.insertRule(`@keyframes ${a} ${g}`,m.cssRules.length));const w=e.style.animation||"";return e.style.animation=`${w?`${w}, `:""}${a} ${n}ms linear ${s}ms 1 both`,XA+=1,a}function QA(e,A){const t=(e.style.animation||"").split(", "),n=t.filter(A?i=>i.indexOf(A)<0:i=>i.indexOf("__svelte")===-1),s=t.length-n.length;s&&(e.style.animation=n.join(", "),XA-=s,XA||dt())}function dt(){VA(()=>{XA||(KA.forEach(e=>{const{stylesheet:A}=e;let t=A.cssRules.length;for(;t--;)A.deleteRule(t);e.rules={}}),KA.clear())})}function Bt(e,A,t,n){if(!A)return p;const s=e.getBoundingClientRect();if(A.left===s.left&&A.right===s.right&&A.top===s.top&&A.bottom===s.bottom)return p;const{delay:i=0,duration:r=300,easing:o=sA,start:l=EA()+i,end:c=l+r,tick:g=p,css:a}=t(e,{from:A,to:s},n);let u=!0,m=!1,d;function w(){a&&(d=DA(e,0,1,r,i,o,a)),i||(m=!0)}function C(){a&&QA(e,d),u=!1}return vA(Q=>{if(!m&&Q>=l&&(m=!0),m&&Q>=c&&(g(1,0),C()),!u)return!1;if(m){const P=Q-l,y=0+1*o(P/r);g(y,1-y)}return!0}),w(),g(0,1),C}function mt(e){const A=getComputedStyle(e);if(A.position!=="absolute"&&A.position!=="fixed"){const{width:t,height:n}=A,s=e.getBoundingClientRect();e.style.position="absolute",e.style.width=t,e.style.height=n,je(e,s)}}function je(e,A){const t=e.getBoundingClientRect();if(A.left!==t.left||A.top!==t.top){const n=getComputedStyle(e),s=n.transform==="none"?"":n.transform;e.style.transform=`${s} translate(${A.left-t.left}px, ${A.top-t.top}px)`}}let pA;function mA(e){pA=e}function IA(){if(!pA)throw new Error("Function called outside component initialization");return pA}function wt(e){IA().$$.on_mount.push(e)}function ze(e){IA().$$.on_destroy.push(e)}function Ct(){const e=IA();return(A,t)=>{const n=e.$$.callbacks[A];if(n){const s=Ge(A,t);n.slice().forEach(i=>{i.call(e,s)})}}}function ht(e,A){IA().$$.context.set(e,A)}function Dt(e){return IA().$$.context.get(e)}const BA=[],wA=[],GA=[],de=[],Qt=Promise.resolve();let xA=!1;function pt(){xA||(xA=!0,Qt.then(Ke))}function tA(e){GA.push(e)}const WA=new Set;let UA=0;function Ke(){const e=pA;do{for(;UA<BA.length;){const A=BA[UA];UA++,mA(A),Et(A.$$)}for(mA(null),BA.length=0,UA=0;wA.length;)wA.pop()();for(let A=0;A<GA.length;A+=1){const t=GA[A];WA.has(t)||(WA.add(t),t())}GA.length=0}while(BA.length);for(;de.length;)de.pop()();xA=!1,WA.clear(),mA(e)}function Et(e){if(e.fragment!==null){e.update(),N(e.before_update);const A=e.dirty;e.dirty=[-1],e.fragment&&e.fragment.p(e.ctx,A),e.after_update.forEach(tA)}}let dA;function ZA(){return dA||(dA=Promise.resolve(),dA.then(()=>{dA=null})),dA}function nA(e,A,t){e.dispatchEvent(Ge(`${A?"intro":"outro"}${t}`))}const jA=new Set;let Z;function T(){Z={r:0,c:[],p:Z}}function S(){Z.r||N(Z.c),Z=Z.p}function b(e,A){e&&e.i&&(jA.delete(e),e.i(A))}function H(e,A,t,n){if(e&&e.o){if(jA.has(e))return;jA.add(e),Z.c.push(()=>{jA.delete(e),n&&(t&&e.d(1),n())}),e.o(A)}}const qA={duration:0};function vt(e,A,t){let n=A(e,t),s=!1,i,r,o=0;function l(){i&&QA(e,i)}function c(){const{delay:a=0,duration:u=300,easing:m=sA,tick:d=p,css:w}=n||qA;w&&(i=DA(e,0,1,u,a,m,w,o++)),d(0,1);const C=EA()+a,Q=C+u;r&&r.abort(),s=!0,tA(()=>nA(e,!0,"start")),r=vA(P=>{if(s){if(P>=Q)return d(1,0),nA(e,!0,"end"),l(),s=!1;if(P>=C){const y=m((P-C)/u);d(y,1-y)}}return s})}let g=!1;return{start(){g||(g=!0,QA(e),eA(n)?(n=n(),ZA().then(c)):c())},invalidate(){g=!1},end(){s&&(l(),s=!1)}}}function It(e,A,t){let n=A(e,t),s=!0,i;const r=Z;r.r+=1;function o(){const{delay:l=0,duration:c=300,easing:g=sA,tick:a=p,css:u}=n||qA;u&&(i=DA(e,1,0,c,l,g,u));const m=EA()+l,d=m+c;tA(()=>nA(e,!1,"start")),vA(w=>{if(s){if(w>=d)return a(0,1),nA(e,!1,"end"),--r.r||N(r.c),!1;if(w>=m){const C=g((w-m)/c);a(1-C,C)}}return s})}return eA(n)?ZA().then(()=>{n=n(),o()}):o(),{end(l){l&&n.tick&&n.tick(1,0),s&&(i&&QA(e,i),s=!1)}}}function OA(e,A,t,n){let s=A(e,t),i=n?0:1,r=null,o=null,l=null;function c(){l&&QA(e,l)}function g(u,m){const d=u.b-i;return m*=Math.abs(d),{a:i,b:u.b,d,duration:m,start:u.start,end:u.start+m,group:u.group}}function a(u){const{delay:m=0,duration:d=300,easing:w=sA,tick:C=p,css:Q}=s||qA,P={start:EA()+m,b:u};u||(P.group=Z,Z.r+=1),r||o?o=P:(Q&&(c(),l=DA(e,i,u,d,m,w,Q)),u&&C(0,1),r=g(P,d),tA(()=>nA(e,u,"start")),vA(y=>{if(o&&y>o.start&&(r=g(o,d),o=null,nA(e,r.b,"start"),Q&&(c(),l=DA(e,i,r.b,r.duration,0,w,s.css))),r){if(y>=r.end)C(i=r.b,1-i),nA(e,r.b,"end"),o||(r.b?c():--r.group.r||N(r.group.c)),r=null;else if(y>=r.start){const Y=y-r.start;i=r.a+r.d*w(Y/r.duration),C(i,1-i)}}return!!(r||o)}))}return{run(u){eA(s)?ZA().then(()=>{s=s(),a(u)}):a(u)},end(){c(),r=o=null}}}const Pt=typeof window<"u"?window:typeof globalThis<"u"?globalThis:global;function bt(e,A){H(e,1,1,()=>{A.delete(e.key)})}function yt(e,A){e.f(),bt(e,A)}function Mt(e,A,t,n,s,i,r,o,l,c,g,a){let u=e.length,m=i.length,d=u;const w={};for(;d--;)w[e[d].key]=d;const C=[],Q=new Map,P=new Map;for(d=m;d--;){const E=a(s,i,d),F=t(E);let M=r.get(F);M?n&&M.p(E,A):(M=c(F,E),M.c()),Q.set(F,C[d]=M),F in w&&P.set(F,Math.abs(d-w[F]))}const y=new Set,Y=new Set;function x(E){b(E,1),E.m(o,g),r.set(E.key,E),g=E.first,m--}for(;u&&m;){const E=C[m-1],F=e[u-1],M=E.key,J=F.key;E===F?(g=E.first,u--,m--):Q.has(J)?!r.has(M)||y.has(M)?x(E):Y.has(J)?u--:P.get(M)>P.get(J)?(Y.add(M),x(E)):(y.add(J),u--):(l(F,r),u--)}for(;u--;){const E=e[u];Q.has(E.key)||l(E,r)}for(;m;)x(C[m-1]);return C}function Yt(e,A){const t={},n={},s={$$scope:1};let i=e.length;for(;i--;){const r=e[i],o=A[i];if(o){for(const l in r)l in o||(n[l]=1);for(const l in o)s[l]||(t[l]=o[l],s[l]=1);e[i]=o}else for(const l in r)s[l]=1}for(const r in n)r in t||(t[r]=void 0);return t}function Ht(e){return typeof e=="object"&&e!==null?e:{}}function K(e){e&&e.c()}function G(e,A,t,n){const{fragment:s,on_mount:i,on_destroy:r,after_update:o}=e.$$;s&&s.m(A,t),n||tA(()=>{const l=i.map(He).filter(eA);r?r.push(...l):N(l),e.$$.on_mount=[]}),o.forEach(tA)}function j(e,A){const t=e.$$;t.fragment!==null&&(N(t.on_destroy),t.fragment&&t.fragment.d(A),t.on_destroy=t.fragment=null,t.ctx=[])}function Ft(e,A){e.$$.dirty[0]===-1&&(BA.push(e),pt(),e.$$.dirty.fill(0)),e.$$.dirty[A/31|0]|=1<<A%31}function q(e,A,t,n,s,i,r,o=[-1]){const l=pA;mA(e);const c=e.$$={fragment:null,ctx:null,props:i,update:p,not_equal:s,bound:ue(),on_mount:[],on_destroy:[],on_disconnect:[],before_update:[],after_update:[],context:new Map(A.context||(l?l.$$.context:[])),callbacks:ue(),dirty:o,skip_bound:!1,root:A.target||l.$$.root};r&&r(c.root);let g=!1;if(c.ctx=t?t(e,A.props||{},(a,u,...m)=>{const d=m.length?m[0]:u;return c.ctx&&s(c.ctx[a],c.ctx[a]=d)&&(!c.skip_bound&&c.bound[a]&&c.bound[a](d),g&&Ft(e,a)),u}):[],c.update(),g=!0,N(c.before_update),c.fragment=n?n(c.ctx):!1,A.target){if(A.hydrate){const a=ct(A.target);c.fragment&&c.fragment.l(a),a.forEach(v)}else c.fragment&&c.fragment.c();A.intro&&b(e.$$.fragment),G(e,A.target,A.anchor,A.customElement),Ke()}mA(l)}class _{$destroy(){j(this,1),this.$destroy=p}$on(A,t){const n=this.$$.callbacks[A]||(this.$$.callbacks[A]=[]);return n.push(t),()=>{const s=n.indexOf(t);s!==-1&&n.splice(s,1)}}$set(A){this.$$set&&!et(A)&&(this.$$.skip_bound=!0,this.$$set(A),this.$$.skip_bound=!1)}}const rA=[];function gA(e,A=p){let t;const n=new Set;function s(o){if(W(e,o)&&(e=o,t)){const l=!rA.length;for(const c of n)c[1](),rA.push(c,e);if(l){for(let c=0;c<rA.length;c+=2)rA[c][0](rA[c+1]);rA.length=0}}}function i(o){s(o(e))}function r(o,l=p){const c=[o,l];return n.add(c),n.size===1&&(t=A(s)||p),o(e),()=>{n.delete(c),n.size===0&&(t(),t=null)}}return{set:s,update:i,subscribe:r}}class Rt{constructor(A){O(this,"ws");O(this,"game");let t;window.location.protocol==="https:"?t="wss://"+window.document.location.host+"/ws":t="ws://"+window.document.location.host+"/ws",this.ws=new WebSocket(t),this.ws.onopen=this.onOpen,this.ws.onmessage=this.onMessage.bind(this),this.ws.onerror=this.onError,this.ws.onclose=this.onClose,this.game=A}onOpen(A){console.log("Connected to server")}onClose(A){console.log("Disconnected from server")}onError(A){}onMessage(A){const t=JSON.parse(A.data);switch(t.type){case"update":this.game.update(t.items);break;case"join":this.game.addPlayer(t.items[0]);break;case"died":this.game.removePlayer(t.items[0]);break;case"achievement":this.game.addAchievements(t.items);break}}}function Xe(e){const A=e-1;return A*A*A+1}function Le(e,{delay:A=0,duration:t=400,easing:n=sA}={}){const s=+getComputedStyle(e).opacity;return{delay:A,duration:t,easing:n,css:i=>`opacity: ${i*s}`}}function kt(e,{delay:A=0,duration:t=400,easing:n=Xe,x:s=0,y:i=0,opacity:r=0}={}){const o=getComputedStyle(e),l=+o.opacity,c=o.transform==="none"?"":o.transform,g=l*(1-r);return{delay:A,duration:t,easing:n,css:(a,u)=>` + transform: ${c} translate(${(1-a)*s}px, ${(1-a)*i}px); + opacity: ${l-g*u}`}}function Ut(e,{from:A,to:t},n={}){const s=getComputedStyle(e),i=s.transform==="none"?"":s.transform,[r,o]=s.transformOrigin.split(" ").map(parseFloat),l=A.left+A.width*r/t.width-(t.left+r),c=A.top+A.height*o/t.height-(t.top+o),{delay:g=0,duration:a=m=>Math.sqrt(m)*120,easing:u=Xe}=n;return{delay:g,duration:eA(a)?a(Math.sqrt(l*l+c*c)):a,easing:u,css:(m,d)=>{const w=d*l,C=d*c,Q=m+d*A.width/t.width,P=m+d*A.height/t.height;return`transform: ${i} translate(${w}px, ${C}px) scale(${Q}, ${P});`}}}const Ot={duration:4e3,initial:1,next:0,pausable:!1,dismissable:!0,reversed:!1,intro:{x:256},theme:{}},Gt=()=>{const{subscribe:e,update:A}=gA([]);let t=0;const n={},s=c=>c instanceof Object;return{subscribe:e,push:(c,g={})=>{const a={target:"default",...s(c)?c:{...g,msg:c}},u=n[a.target]||{},m={...Ot,...u,...a,theme:{...u.theme,...a.theme},id:++t};return A(d=>m.reversed?[...d,m]:[m,...d]),t},pop:c=>{A(g=>{if(!g.length||c===0)return[];if(s(c))return g.filter(u=>c(u));const a=c||Math.max(...g.map(u=>u.id));return g.filter(u=>u.id!==a)})},set:(c,g={})=>{const a=s(c)?{...c}:{...g,id:c};A(u=>{const m=u.findIndex(d=>d.id===a.id);return m>-1&&(u[m]={...u[m],...a}),u})},_init:(c="default",g={})=>(n[c]=g,n)}},LA=Gt();function Be(e){return Object.prototype.toString.call(e)==="[object Date]"}function JA(e,A){if(e===A||e!==e)return()=>e;const t=typeof e;if(t!==typeof A||Array.isArray(e)!==Array.isArray(A))throw new Error("Cannot interpolate values of different type");if(Array.isArray(e)){const n=A.map((s,i)=>JA(e[i],s));return s=>n.map(i=>i(s))}if(t==="object"){if(!e||!A)throw new Error("Object cannot be null");if(Be(e)&&Be(A)){e=e.getTime(),A=A.getTime();const i=A-e;return r=>new Date(e+r*i)}const n=Object.keys(A),s={};return n.forEach(i=>{s[i]=JA(e[i],A[i])}),i=>{const r={};return n.forEach(o=>{r[o]=s[o](i)}),r}}if(t==="number"){const n=A-e;return s=>e+s*n}throw new Error(`Cannot interpolate ${t} values`)}function jt(e,A={}){const t=gA(e);let n,s=e;function i(r,o){if(e==null)return t.set(e=r),Promise.resolve();s=r;let l=n,c=!1,{delay:g=0,duration:a=400,easing:u=sA,interpolate:m=JA}=zA(zA({},A),o);if(a===0)return l&&(l.abort(),l=null),t.set(e=s),Promise.resolve();const d=EA()+g;let w;return n=vA(C=>{if(C<d)return!0;c||(w=m(e,r),typeof a=="function"&&(a=a(e,r)),c=!0),l&&(l.abort(),l=null);const Q=C-d;return Q>a?(t.set(e=r),!1):(t.set(e=w(u(Q/a))),!0)}),n.promise}return{set:i,update:(r,o)=>i(r(s,e),o),subscribe:t.subscribe}}function zt(e){let A,t=e[0].msg+"",n;return{c(){A=new at,n=aA(),A.a=n},m(s,i){A.m(t,s,i),I(s,n,i)},p(s,i){i&1&&t!==(t=s[0].msg+"")&&A.p(t)},i:p,o:p,d(s){s&&v(n),s&&A.d()}}}function Kt(e){let A,t,n;const s=[e[6]()];var i=e[0].component.src;function r(o){let l={};for(let c=0;c<s.length;c+=1)l=zA(l,s[c]);return{props:l}}return i&&(A=new i(r())),{c(){A&&K(A.$$.fragment),t=aA()},m(o,l){A&&G(A,o,l),I(o,t,l),n=!0},p(o,l){const c=l&64?Yt(s,[Ht(o[6]())]):{};if(i!==(i=o[0].component.src)){if(A){T();const g=A;H(g.$$.fragment,1,0,()=>{j(g,1)}),S()}i?(A=new i(r()),K(A.$$.fragment),b(A.$$.fragment,1),G(A,t.parentNode,t)):A=null}else i&&A.$set(c)},i(o){n||(A&&b(A.$$.fragment,o),n=!0)},o(o){A&&H(A.$$.fragment,o),n=!1},d(o){o&&v(t),A&&j(A,o)}}}function me(e){let A,t,n;return{c(){A=h("div"),A.textContent="✕",f(A,"class","_toastBtn pe svelte-j9nwjb"),f(A,"role","button"),f(A,"tabindex","-1")},m(s,i){I(s,A,i),t||(n=U(A,"click",e[3]),t=!0)},p,d(s){s&&v(A),t=!1,n()}}}function Xt(e){let A,t,n,s,i,r,o,l,c,g;const a=[Kt,zt],u=[];function m(w,C){return w[0].component?0:1}n=m(e),s=u[n]=a[n](e);let d=e[0].dismissable&&me(e);return{c(){A=h("div"),t=h("div"),s.c(),i=R(),d&&d.c(),r=R(),o=h("progress"),f(t,"role","status"),f(t,"class","_toastMsg svelte-j9nwjb"),kA(t,"pe",e[0].component),f(o,"class","_toastBar svelte-j9nwjb"),o.value=e[1],f(A,"class","_toastItem svelte-j9nwjb"),kA(A,"pe",e[0].pausable)},m(w,C){I(w,A,C),D(A,t),u[n].m(t,null),D(A,i),d&&d.m(A,null),D(A,r),D(A,o),l=!0,c||(g=[U(A,"mouseenter",e[4]),U(A,"mouseleave",e[5])],c=!0)},p(w,[C]){let Q=n;n=m(w),n===Q?u[n].p(w,C):(T(),H(u[Q],1,1,()=>{u[Q]=null}),S(),s=u[n],s?s.p(w,C):(s=u[n]=a[n](w),s.c()),b(s,1),s.m(t,null)),C&1&&kA(t,"pe",w[0].component),w[0].dismissable?d?d.p(w,C):(d=me(w),d.c(),d.m(A,r)):d&&(d.d(1),d=null),(!l||C&2)&&(o.value=w[1]),C&1&&kA(A,"pe",w[0].pausable)},i(w){l||(b(s),l=!0)},o(w){H(s),l=!1},d(w){w&&v(A),u[n].d(),d&&d.d(),c=!1,N(g)}}}function Lt(e,A,t){let n,{item:s}=A;const i=jt(s.initial,{duration:s.duration,easing:sA});Fe(e,i,d=>t(1,n=d));const r=()=>LA.pop(s.id),o=()=>{(n===1||n===0)&&r()};let l=s.initial,c=l,g=!1;const a=()=>{s.pausable&&!g&&n!==l&&(i.set(n,{duration:0}),g=!0)},u=()=>{if(g){const d=s.duration,w=d-d*((n-c)/(l-c));i.set(l,{duration:w}).then(o),g=!1}},m=()=>{const{props:d={},sendIdTo:w}=s.component;return w&&(d[w]=s.id),d};return ze(()=>{typeof s.onpop=="function"&&s.onpop(s.id)}),e.$$set=d=>{"item"in d&&t(0,s=d.item)},e.$$.update=()=>{e.$$.dirty&1&&typeof s.progress<"u"&&t(0,s.next=s.progress,s),e.$$.dirty&131&&l!==s.next&&(t(7,l=s.next),c=n,g=!1,i.set(l).then(o))},[s,n,i,r,a,u,m,l]}class Tt extends _{constructor(A){super(),q(this,A,Lt,Xt,W,{item:0})}}function we(e,A,t){const n=e.slice();return n[5]=A[t],n}function Ce(e,A){let t,n,s,i,r,o,l,c=p,g;return n=new Tt({props:{item:A[5]}}),{key:e,first:null,c(){t=h("li"),K(n.$$.fragment),s=R(),f(t,"style",i=A[1](A[5].theme)),this.first=t},m(a,u){I(a,t,u),G(n,t,null),D(t,s),g=!0},p(a,u){A=a;const m={};u&1&&(m.item=A[5]),n.$set(m),(!g||u&1&&i!==(i=A[1](A[5].theme)))&&f(t,"style",i)},r(){l=t.getBoundingClientRect()},f(){mt(t),c(),je(t,l)},a(){c(),c=Bt(t,l,Ut,{duration:200})},i(a){g||(b(n.$$.fragment,a),tA(()=>{o&&o.end(1),r=vt(t,kt,A[5].intro),r.start()}),g=!0)},o(a){H(n.$$.fragment,a),r&&r.invalidate(),o=It(t,Le,{}),g=!1},d(a){a&&v(t),j(n),a&&o&&o.end()}}}function St(e){let A,t=[],n=new Map,s,i=e[0];const r=o=>o[5].id;for(let o=0;o<i.length;o+=1){let l=we(e,i,o),c=r(l);n.set(c,t[o]=Ce(c,l))}return{c(){A=h("ul");for(let o=0;o<t.length;o+=1)t[o].c();f(A,"class","_toastContainer svelte-7xr3c1")},m(o,l){I(o,A,l);for(let c=0;c<t.length;c+=1)t[c].m(A,null);s=!0},p(o,[l]){if(l&3){i=o[0],T();for(let c=0;c<t.length;c+=1)t[c].r();t=Mt(t,l,r,1,o,i,n,A,yt,Ce,null,we);for(let c=0;c<t.length;c+=1)t[c].a();S()}},i(o){if(!s){for(let l=0;l<i.length;l+=1)b(t[l]);s=!0}},o(o){for(let l=0;l<t.length;l+=1)H(t[l]);s=!1},d(o){o&&v(A);for(let l=0;l<t.length;l+=1)t[l].d()}}}function Nt(e,A,t){let n;Fe(e,LA,l=>t(4,n=l));let{options:s={}}=A,{target:i="default"}=A,r;const o=l=>Object.keys(l).reduce((c,g)=>`${c}${g}:${l[g]};`,"");return e.$$set=l=>{"options"in l&&t(2,s=l.options),"target"in l&&t(3,i=l.target)},e.$$.update=()=>{e.$$.dirty&12&&LA._init(i,s),e.$$.dirty&24&&t(0,r=n.filter(l=>l.target===i))},[r,o,s,i,n]}class Wt extends _{constructor(A){super(),q(this,A,Nt,St,W,{options:2,target:3})}}const CA=class{static async getPlayers(){return fetch(`${CA.apiUrl}/info`).then(A=>A.json()).catch(()=>null)}static async getTiles(A,t,n,s){return fetch(`${CA.apiUrl}/map?startX=${A}&startY=${t}&endX=${n}&endY=${s}`).then(i=>i.json()).catch(()=>null)}static async getUnits(A,t,n,s){return fetch(`${CA.apiUrl}/units?startX=${A}&startY=${t}&endX=${n}&endY=${s}`).then(i=>i.json()).catch(()=>null)}};let cA=CA;O(cA,"apiUrl",window.document.location.protocol+"//"+window.document.location.host);class xt{constructor(A,t){O(this,"startX");O(this,"startY");O(this,"viewX",50);O(this,"viewY",25);O(this,"tiles",gA([]));O(this,"units",gA([]));this.startX=A,this.startY=t}async centerTo(A,t){this.startX=A-Math.floor(this.viewX/2),this.startY=t-Math.floor(this.viewY/2),await this.update()}async update(){const A=await cA.getTiles(this.startX,this.startY,this.startX+this.viewX-1,this.startY+this.viewY-1);this.tiles.set([]),A.forEach(n=>{let s=[];for(let i=0;i<n.length;i+=2)for(let r=0;r<+n[i];r+=1)s.push(n[i+1]);this.tiles.update(i=>[s,...i])});const t=await cA.getUnits(this.startX,this.startY,this.startX+this.viewX-1,this.startY+this.viewY-1);console.log(t),this.units.set(t)}updateBlock(A,t,n){A>this.startX&&A<this.startX+this.viewX&&t>this.startY&&t<this.startY+this.viewY&&this.tiles.update(s=>{const i=[...s];return i[this.viewY-(t-this.startY+1)][A-this.startX]=n,i})}updateUnit(A){(A.x>this.startX&&A.x<this.startX+this.viewX&&A.y>this.startY&&A.y<this.startY+this.viewY||A.x==-1)&&(console.log(`Updating unit ${A.opcode} (${A.unitId}) at ${A.x}, ${A.y}`),this.units.update(t=>A.x==-1?(console.log("Unit is dead, removing it"),t.filter(n=>n.unitId!==A.unitId)):t.filter(n=>n.unitId===A.unitId).length===0?(console.log("No unit found with this id, adding it"),[A,...t]):(console.log("Moving unit"),t.map(n=>n.unitId===A.unitId?A:n))))}async moveTop(){await this.moveRelative(0,5)}async moveDown(){await this.moveRelative(0,-5)}async moveLeft(){await this.moveRelative(-10,0)}async moveRight(){await this.moveRelative(10,0)}async moveRelative(A,t){this.startX+=A,this.startY+=t,await this.update()}}const Jt="/assets/notif-fba26198.mp3";class Vt{constructor(A){O(this,"login");O(this,"socket");O(this,"players",gA([]));O(this,"currentPlayer",gA(null));O(this,"currentLogin",null);O(this,"map");this.login=A,this.socket=new Rt(this),this.map=new xt(0,0),cA.getPlayers().then(t=>this.players.set(t))}selectPlayer(A){this.currentLogin=A.login,this.currentPlayer.set(A)}addPlayer(A){console.log(`${A.login} joined`),this.players.update(t=>[...t,A])}removePlayer(A){console.log(`${A.login} left`),this.players.update(t=>t.filter(n=>n.login!==A.login))}addAchievements(A){this.players.update(t=>t.map(n=>{for(const s of A)n.login===s.login&&(console.log(`${n.login} got achievement ${s.achievement}`),n.achievements.push(s.achievement),this.currentLogin==n.login&&(LA.push("You got the achievement "+s.achievement),new Audio(Jt).play(),this.currentPlayer.set(n)));return n}))}async moveTo(A){await this.map.centerTo(A.townHallsCoordinates[0].x,A.townHallsCoordinates[0].y)}update(A){for(const t of A)t.type==="tile"?this.map.updateBlock(t.x,t.y,t.tile):t.type=="unit"&&this.map.updateUnit(t)}}const Zt="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAGSUlEQVR4Ae1cPatdRRR9X/e9IpgUYohaGBDSCGkkhSBYCSEgAS2MhkiwSWrB0kIsLfwL+QU2NlYiWFj4J2wEQSzsDM/3nre4XLIW55199p2PM2f2etXdd2b27L3WerPnzDnn7u3pTwgIASEgBISAEIiIwH4HSV/MnMOiMTyYGTxNPzMCEsDMBMw9vQQwNwMzz7/E+jVa8x9/9W1RSJ9986Xlf1GYagWw6Oy8XQLonGArPQnAQqjz9qMF5Dda81+++2HVFHi+v3/8nucfjXfduak9glYApi+YLQEEI5zTlQAYkWB2U/Vog/1oDS19nZ/K/w+//QouBvYI0L42ZuVAKwDTEcyWAIIRzulKAIxIMHvW+rPBetE136uX1u4laAXwMthZfwmgM0K96UgAXsQ66z/HvYBZa/61128Chf/88TvY3A6NEwz2x0N2uJdQdJ+mFYAZCmZLAMEI53QlAEYkmF20vmywnLXml+bT2jNYewKOr/Y5gVYAZiCYLQEEI5zTlQAYkWB2iT1A1zW/tD5qP0+gFaA0o437lwAaJ6h0eBJAaYQb959jD6CaX5Hk3OcEWgEqktfiVBJAi6xUjEkCqAh2i1Pt8jyAav6MTE54nsAVnVYAF1z9dZYA+uPUlZEE4IKrv867nAPAHqD2u3o7nJUDa1a8pf1DMBmM1HMBrQAZSFiyCwlgyexliF0CyADikl1MOQeAmj93shPet08KsbT/pOAGBqeeC2gFGAA10lcSQCS2B3KVAAZAifTVlD0A4GFdR0PnHQzrOvziIm1Lsr+PRx9cQ3P7Zwhy4/fBnXdgimf27xYCAFoBAL54hgQQj3PIWAIAOOIZQ3uAtCKbiGHt6/Da8yXCYw7nPY2Vn1YAE9K+O0gAffNrZicBmBD13QGuCTepwh4g93Vr6ev81ujicweOLze+7H/geQHgXCsAIxbMlgCCEc7pSgCMSDB76BygaQismmoF7z3r987n9W/FW7pdK0BphBv3LwE0TlDp8CSA0gg37r/6HsA6my6NF9f03DWb/ZfOJ9W/VoBUBBc+XgJYOIGp4UsAqQgufLy5B+Cz5NJn16l4WjU9d42uPZ91L8WLn1YAL2Kd9ZcAOiPUm44E4EWss/5wb/iS3OD5gEv6bL9O3SPwnmPreOIHb0329ucwvOO9+GSo+aMcawVgRoPZEkAwwjldCYARCWaP1odLsHDtCdiHtwby+NQ9AvvLbZ+8cgNcXtC7iJ8++QLa2dih5u/C4XZarQBbKGJ+kABi8r7NWgLYQhHzg3kvYAAWb82BPQPX8E++/g6mOD1cgb06OwU71bD2IByfd773Hj2FIa9duQI2G7VrPs+vFYARCWZLAMEI53QlAEYkmD2lnkMNX+MzZcyLMMJ4fn+df+PmxYFTPp/TdTaPOaDfFIJg1p1PDw5hyNkh/k8cnZ1B++r8HOxUY8KeIwnvdXyj4zHb1Gw0fnEISACLoyxvwBJAXjwX523oHIDLZNGk+DrYuyfgGm8FywXx+Bxr/B7blsPy7cwHp2BFMDpeK4AFX+ftEkDnBFvpSQAWQp23D9UTrhkWBOwDxl+/8y6Mv3f3PtipewBw1qEx4ZzAmzXwpRXAC19n/SWAzgj1piMBeBHrrD/Ug01uUMP5/rlVk156402A6KPP8P44NMpwI2DhP4Ev4FwrgJuCvgZIAH3x6c5GAnBD1teAoXsBoxlyjRntXKGx9jlC7fkYwtz4awVghIPZEkAwwjldCYARCWabewC+7sxdg4Lh3Vy6WgGao6RuQBJAXbybm00CaI6SugHBufBmargXYIXDe4LS18nsn397mOOx4j89wP+Bf1cnOIQQ+vmXn6A9dX5wNmA8P8J3JU/+G39XkvdsAy4hI8x+oLe+6hsBCaBvfs3sJAATor47QD24JFXXnmB1+21w8/D+A7C9hlXz2d/hrbfgq0cfPwbba3jn5+ch3n/wOUx59fgYbMvg+a3+vCdZ9x/lWCuAhWjn7RJA5wRb6UkAFkKdt4/Wh4m5j+4Rjq+/Cm726X3953/9Ce0TDCvm0Xgm+Le6VJ2ff09hoMZzvFZ80F8rAMARz5AA4nEOGUsAAEc8w1UvdoQntSZ7Y0ydj9P0zs/jU+NJnZ/jAVsrAMARz5AA4nEOGUsAAEc843/wxTQySNxbjQAAAABJRU5ErkJggg==",qt="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAFxElEQVR4Ae1dvYoVTRDdq6KRoeJPYCArgi9hIAiCT2EmmO8jmAsbrU8hYmLqI4jCYmCigrGBuHBd8TLcOrfv1NTU9Ex31/miWzP9U3XOoaqmZ9bv4ID/EQEiQASIABEgAhERWDUQ9HrhGKrG8MLC4HH7hRGgABYmYOntKYClGVh4/xrrV2/Nf3qaF9E3h+r6VWHKDKDy2fYACqBtftXoKAAVorYHXKogvN6af/8ZhnCWNSTc7/Prnf16/T13rqgegRkgq1zKX5wCKJ+jrB5SAFnhLX/xourRBq7eGpr7Od9L2elL7EnkiomeYVEOmAEkP+EsCiAc5TJgCkDiEc5atP5s0K665lsVU9q7BGYAK4ONjacAGiPUGg4FYEWssfH9D615gl205j+/9UpEdfzthbDxvrg5wMD1cMqIdwlZ+zRmAGQomE0BBCMcw6UAEJFgdtb6ssFy0Zqfm0+tZ9B6AvRv7nMCZgBkIJhNAQQjHMOlABCRYHaOHqDpmp9bH/g9QeL7AXTBxSEzAMIZzKYAghGO4VIAiEgw21U/Nlix5s8omqnPCZgBZiSvxK0ogBJZmdEnCmBGsEvcasz3AKz5CzI54HsCk3fMACa42htMAbTHqSkiCsAEV3uDx5wDiB5g7r/VG3FWLljT/M29vnBmAsN7LsAMMAEJNS9BAdTM3gS+UwATgFjzEkPOAUTNXzrYAe/HXS7mXt/lXGKy91yAGSABaqRLFEAkthOxUgAJUCJdGnIOIHoA7TnaC572HL5eC3fM261WMmSsoZ9O/pjX3J6A62/f+/c7N37WcwFmAGQomE0BBCMcw6UAEJFgduocwFdkKwNw57n/pLIAwF3saXbig/HMAABINJMCiMY4xEsBACDRTPlQ/D960QNM/dya+zm/NAILPBcQnDMDlKaYmf2hAGYGvLTtKIDSGJnZn9Q5wMwu2LbTaqq2mvVdgnU/6/qav7nvMwPkRrjw9SmAwgnK7R4FkBvhwtefvQfQzqZz44U1feqajevnjse7PjOAF8HK51MAlRPodZ8C8CJY+Xy1B8BvzKZ+NzA1flpNn7pGz72f9i7FiiczgBWxxsZTAI0Rag2HArAi1th48W54T2zi+4A9Y7rL3h4Be45u4YE/rDXZOh7dsM634jNBze/lmBkAGQ1mUwDBCMdwKQBEJJjdWx/2YGHqCXANaw3E+d4eAdeb2r5y7YZYcg1/i/j4w3dxH40RNX8Mh922zAAdFDF/UAAxee+ipgA6KGL+cNWPgZD19gzWnsDbA2j7edd/96v//02sYTZg/0k5YwbQGGn8PgXQOMFaeBSAhlDj94fUE6zhQ+Zswybm49+vHx6dbY8N9ztDzRd4nwPayxczQDjJyYApAIlHOIsCCEe5DDj1TSDWEDljYgvPvqP3BAl4kY/emm6dzwyQQCzSJQogEtuJWCmABCiRLqV6AC1+rSaJ+9pzP/YA2uat3R/xbkLg68WDGcCLYOXzKYDKCfS6TwF4Eax8fuqZUtQYrFHa2fXVO3cFJA/ffxE2DR8CGv4D+BKcMwP4+Kh+NgVQPYW+ACgAH37Vzxb1YBNNbw9QWsR4jpD7XcLc+3nxTvQMgnNmAC/Clc+nACon0Os+BeBFsPL56rsArCH4nFl5/OHdZwYILgEKgAIIjkDw8NUeAPHReoLcz8m4Pv7bw4dH6HFeW8Mj7+67q6M/uyPkFZYAiUc4iwIIR7kMmAKQeISzxLnwnujFu4E9Y7rL2jeA3cCBP7Saj8tcvPdAXHry9qOwrYZ1f/we4vajr2JL67sK3F8sljCwJzof0ssxM0ACxEiXKIBIbCdipQASoES61FsfBgLR2yNcvn5TLLNay+G/f/4Q9wcYms9ygwELGofMuj/2VIkaj+5r/onxzAACjngGBRCPcxExBSDgiGeY6sVIeLw12eqjdz8M07o/zvf6490f/RE2M4CAI55BAcTjXERMAQg44hl/AV7j/OgJ907tAAAAAElFTkSuQmCC",_t="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAFwklEQVR4Ae1du24UQRA8IwQklp3wTAgg5Gv4BBJCIogIHUECIX/ABxGSkFgghGSLBIvgMNLp5C6tp7end2Znpovo+nYe3VWl7t7ZPbzZ8B8RIAJEgAgQASIQEYGDAYLerhxD1xjeWBk8br8yAhTAygSsvT0FsDYDK+/fY/1K1vzfR8nLbrgPz1XI1AFuJxZcgBlgQTB7XIoC6JG1BX2mABYEs8elbnbgdLKov9q8rhoC7vdx8x73T/p7ObipHoEZAOkLZlMAwQjHcCkARCSY3VQ92mGfrKGl7/O9/L89fyOWmOgRxPVLY1UOmAGQjmA2BRCMcAyXAkBEgtmr1p8d1l3XfKteWnuWwAxgZXCw8RTAYIRaw6EArIgNNn6NZwFN1/w7n3wM/3mZnp/xLKFon8YMkOZr+KsUwPAUpwOkANL4DH+1aH3Zodd0zfcyrPUMWk+A+9c+J2AGQAaC2RRAMMIxXAoAEQlml+gBhq75pfVR+30CZoDSjDa+PgXQOEGl3aMASiPc+PpL9ACs+RVJXvqcgBmgInktbkUBtMhKRZ8ogIpgt7hVzvsArPkrMjnjfQKTd8wAJrjGG0wBjMepKSIKwATXeINzzgFED1D7t3oZZ+WCNc3f0usLZxYwvOcCzAALkNDzEhRAz+wt4DsFsACIPS8xpwcQNR+D1WoqjvfaM2pecgvN39LrJ53LuDijZ0lyzAyQAfpIUyiAkdjMiIUCyABtpCnJ+rALVPQAWg31gqPVtO1WuGPe7uBAhoxn6x+278xrXp2A61+99v9zafxm9DACAGYAZCiYTQEEIxzDpQAQkWD21PsAviLbGYD4//h92Ph6gLXDx54G40P/mAEQkWA2BRCMcAyXAkBEgtninnAXu+gBlr5vLX2f3xp/DZ4LCM6ZAVpTTGV/KIDKgLe2HQXQGiOV/Zk6B6jsgm07raZqq1mfJVj3s66v+Vv6OjNAaYQbX58CaJyg0u5RAKURbnx9cU+487XoOYD2vFqrodaarOFfez/0Z+lzFlx/Am/BOTMAIhbMpgCCEY7hUgCISDBbPQfAGlK6Znnxr13Ta++nPUux4scMYEVssPEUwGCEWsOhAKyIDTZe3BNeE5s4F7hmzP5rb4+APcd+4ZkfrDXZOh7dsM634rNAzU9yzAyAjAazKYBghGO4FAAiEsxO1odrsDD1BLiGtQbifG+PgOstbd+++0AsuYXfIv66OBXX0cio+Tkc7rdlBthDEfMDBRCT933UFMAeipgfXPVjJmTJnsHaE3h7AG0/7/p/P8twtb8bWLvmI2fMAIhIMJsCCEY4hksBICLB7Dk9gCxqm82cOVdhFPPx9+snR33/Hv9qoDmfZ/QcLrwvfUrOZwbIYW2gORTAQGTmhEIB5KA20JypdwJFzS4dK94HR+8JJvBGPpI13TqfGWACsUhfUQCR2J6IlQKYACXSV1M9gBa/VpPEde2+H3sAbfPRrmc8mxD4evFgBvAi2Pl8CqBzAr3uUwBeBDufP3VPKWoM1ijt7Prw8RMByenZV2HT8CGg4T+DL8E5M4CPj+5nUwDdU+gLgALw4df9bFEPdtEke4DWIsZzhNLPEmrv58V7omcQnDMDeBHufD4F0DmBXvcpAC+Cnc9XnwVgDcH7zM7jD+8+M0BwCVAAFEBwBIKHr/YAiI/WE5S+T8b18e/inVT+u38aHohfaRv90fZjCdAQGvw6BTA4wVp4FICG0ODXp3oAcVZ8Gb94NoB4YM3BdwBxvNXWaj6ud3z/mfjq7McXYVsN6/6Pjp+KLV58ey5s67MK3F8sNs9APsUsZgABRzyDAojHuYiYAhBwxDOS9WEmHMke4da9h2KZg60cfvHzu7g+w9B8lhvMWNA4pOr+2FPhuceE75p/YgozgIAjnkEBxONcREwBCDjiGaZ6kQmPtyZbffTuh2Fa98f5Xn+8+6M/wmYGEHDEMyiAeJyLiCkAAUc84x+0bw/TULWLkAAAAABJRU5ErkJggg==",$t="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAFxklEQVR4Ae1dTWsUQRDdlag5xGMk4iGg4J/L0aOEBII/wT8nKHgIRHNQ0IOShTXCsGw9O13d09Of9XLa2unuqnrv0VXTk0lWK/4QASJABIgAESACFhFYD5D0tnIOXWP4qDJ4dF8ZAQqgMgG13VMAtRmo7L/H+uWt+berw6yQHq9+a+t3hSl3AI3Owa9TAIMTrKVHAWgIDX79oIP8vDX/8uBIprDZSHthC/1dbn6hB2+894Ob6hG4AyB9xmwKwBjhmC4FgIgYs5uqRxP23hqa+z4/lf8PB/62ytEzVOWAO0Aq453PpwA6JzA1fAogFcHO51etPxN2Xdf8WP5be5bAHSCWwcHGUwCDERqbDgUQi9hg42v0AFVr/uPzd4LCu6v3wsbr4mKAgevhFDwncJwL4JSsHHEHQLiN2RSAMcIxXQoAETFmZ60vE5ZVa35uPrWeQesJML7S5wTcAZABYzYFYIxwTJcCQESM2Tl6gKFrfm59lD4n4A6Qm9HG16cAGicod3gUQG6EG19/iR6ANb8gyUufE3AHKEhei64ogBZZKRgTBVAQ7BZdzekBWPMrMhlwThDFKXeAimS24JoCaIGFijFQABXBb8F1VL2YAhY9QOl39QJqoBdXLd7c63uDm3Ex9VyAO8AM0EeaQgGMxOaMXCiAGaCNNCWkBxA1H5PXaiqOT7UDap7XhRZv7vW9wc24GNCzeDnmDjAD9JGmUAAjsTkjFwpgBmgjTfHWhylR0QNoNTQVHK2mbbcinGh367VMGf/u38Xdz+g19yfg+vvX/n3OjV9ADyMA4A6ADBmzKQBjhGO6FAAiYsx2/VG7tCLbGYD4fv5FZ/FjuNjTYH44njsAImLMpgCMEY7pUgCIiDFb3BNOuYseYOn71tz3+a3x1+C5gOCcO0BriikcDwVQGPDW3FEArTFSOB7XOUDhEOLcaTVVWy32WUKsv9j1tXhzX+cOkBvhxtenABonKHd4FEBuhBtfX9wTTrFmPQfQnldrNTS2Jmv4l/aH8Sx9zoLrO/AWnHMHQMSM2RSAMcIxXQoAETFmq+cAWENy16xU/EvX9NL+tGcpsfhxB4hFbLDxFMBghMamQwHEIjbYeHFP+EBu4lzggTG7r1N7BOw5dgsHfoitybHjMYzY+bH4LFDzvRxzB0BGjdkUgDHCMV0KABExZnvrwwNYRPUEuEZsDcT5qT0Crre0/fT4RCy5hXcRr799F9fRmFHz53C4c8sdYAeFzQ8UgE3ed1lTADsobH5Iqh+BkHl7htieILUH0Pylrv/j/ErAwv8bKOCg0RoCLAGtMVI4HgqgMOCtuQvpAbCGh8zZz1PMx/fXzzab/bHmPgf0HEl43wPqnc8dwJzkZMIUgMTDnEUBmKNcJuz6nUBRs+Xw5S08+7beEzgQRj68NT12PncAB2KWvqIALLHtyJUCcIBi6StXD6Dlr9UkcV2778ceQHM+2vUZzyYEvql4cAdIRbDz+RRA5wSmhk8BpCLY+XzXPaWoMVijtLPrZ6evBSSfv1wLm0YaAhr+AXwJzrkDpPHR/WwKoHsK0xKgANLw6362qAdTNt4eoLWM8Rwh97OE0v5S8Xb0DIJz7gCpCHc+nwLonMDU8CmAVAQ7n68+C8AagveZnedvPnzuAMYlQAFQAMYRMJ6+2gMgPlpPkPs+GdfH/4t3tjrEkLPaGh5ZnTsWx3gcQ8RXLAECDnsGBWCPc5ExBSDgsGe4egBxVnwPiXg2gBBhzblcHeGQJFur+bj4yRv5+wg3Hz/hkCg71v+r05di/bfXX4Ud+6wC/YvFXMb/r1oin2IWdwABhz2DArDHuciYAhBw2DO89SEQDm+P8OT5C7HMeiuH/7m9EdcDDC1m6SBgwcghRf3jexV47uGIXYtPTOEOIOCwZ1AA9jgXGVMAAg57RlS9mAlPak2OjTHVH6YZ6x/np8aT6h/jETZ3AAGHPYMCsMe5yJgCEHDYM/4C9gb53u1K2DsAAAAASUVORK5CYII=",An="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAFvElEQVR4Ae1dPYsUQRC9E0+jEwwURdBA8CeYi/grLjEwMzG50OQMjc2EM7lfISaG/gTBRBAED0SNxGC9YFmu3s51dU9Nf9Yz2prp7qp679FV07O37uzwHxEgAkSACBABIuARgd0Bkl5VzqFrDC9VBo/uKyNAAVQmoLZ7CqA2A5X991i/gjX/9/u9rJBee/JPW78rTLkDaHQOfp8CGJxgLT0KQENo8PuXO8gvWPNfPi2bAfp79W7LfzDes9FN9QjcAbb483WBAvDF91a2FMAWJL4uNFWP1tAHa2ju53wr/a9P5DnBRI+ALqpywB0A6XBmUwDOCMd0KQBExJldtf6sse665qfqpbV3CdwBUhkcbDwFMBihqelQAKmIDTa+Rg9QtebvP/wgKPzz6bGw8b64GWHgejiltXMC7gDIkDObAnBGOKZLASAizuwSPUDVmp+bT61n0HoCjK/0OQF3AGTAmU0BOCMc06UAEBFndo4eYOian1sfpc8JuAPkZrTx9SmAxgnKHR4FkBvhxtdfogdgzS9I8tLnBNwBCpLXoisKoEVWCsZEARQEu0VXc3oA1vyKTEacEyRxyh2gIpktuKYAWmChYgwUQEXwW3CdVC/WAYseoPTf6kXUwCCuWry51w8GN+Om9VyAO8AM0EeaQgGMxOaMXCiAGaCNNCWmBxA1H5PXaiqOt9oRNS/oQos39/rB4GbcjOhZghxzB5gB+khTKICR2JyRCwUwA7SRpgTrwzpR0QNoNdQKjlbTVisRTrK73V2ZMv7u39HxsutjgLnxi+hhBADcAZAhZzYF4IxwTJcCQESc2VO/FWwrgp0BiL/jd3TcWQIQLvY0mB8M3+EOgIg4sykAZ4RjuhQAIuLMFs+E69xFD7D0c2vu5/zW+MNzB4xvaXxx/YlzAcE5dwBEzJlNATgjHNOlABARZ/bUOUDTEGg1VQs+9V1Cqr/U9bV4c9/nDpAb4cbXpwAaJyh3eBRAboQbX794D6CdTefGC2v60jUb18+dj3V97gBWBDufTwF0TqA1fArAimDn89UeAM+Sc59dW/HUavrSNbq0P+1dSip+3AFSERtsPAUwGKGp6VAAqYgNNl68G74gN/H9gAvGbC5bewTsOTYLR35Ircmp4zGM1Pmp+CxQ84MccwdARp3ZFIAzwjFdCgARcWYH68MFWCT1BLhGag3E+dYeAddb2r5645ZYcgV/i3h6ciruozGj5s/hcOOWO8AGCp8fKACfvG+ypgA2UPj8YKofkZAFe4bUnsDaA2j+rOuvfn0UsPD/DRRw0GgNAZaA1hgpHA8FUBjw1tzF9ABYw2PmnM9TzMe/Xz882Ds/1t3niJ7DhPcZoMH53AHcSU4mTAFIPNxZFIA7ymXCU98JFDVbDl/ewrNv7z3BBMLIR7Cmp87nDjCBmKdLFIAntidypQAmQPF0aaoH0PLXapK4rz33Yw+gOR/t/ox3EwJfKx7cAawIdj6fAuicQGv4FIAVwc7nTz1TihqDNUo7u96/d19A8u3tV2HTsCGg4R/Bl+CcO4CNj+5nUwDdU2hLgAKw4df9bFEP1tkEe4DWMsZzhNzvEkr7s+I90TMIzrkDWBHufD4F0DmB1vApACuCnc9X3wVgDcHnzM7zdx8+dwDnEqAAKADnCDhPX+0BEB+tJ8j9nIzr428PHx5gxHltDY+83rdXx3i2R8grLAESD3cWBeCOcpkwBSDxcGdN9QDirPgMEfFuABHCmoPfAcTxqbZW83G9688fiEs/33wWdqqR6v/Os7vCxYtHX4Sd+q4C/YvF4gzkU8ziDiDg8GdQAP44FxlTAAIOf0awPkTCEewRrty8LZbZXcnhf398F/cjDC1m6SBiwcQhRf1jT4XnHhOxa/GJKdwBBBz+DArAH+ciYwpAwOHPSKoXM+Gx1uTUGK3+MM1U/zjfGo/VP8YjbO4AAg5/BgXgj3ORMQUg4PBn/AepZQ3ToTKK8AAAAABJRU5ErkJggg==",en="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAFoElEQVR4Ae1dO5JTMRB8pqjlBFBwgk0JiTgCIRExIREnIYN4Ewg5Aicg3RtQRUbGJobA5dppvdVorL+mN/JYT6OZ7i7NPD17vW38IwJEgAgQASJABDwicFgg6WPnHKbG8FFn8Lh8ZwQogM4E9F6eAujNQOf1Z6xf0Zp/9eZHVUjvvr/W/E+FKXcAjc7FxymAxQnW0qMANIQWH388QX7Rmr9dv2+bAq53+wXXj8e7bUP1CNwBkD5nNgXgjHBMlwJARJzZQ9WjE/bRGlr7Pj+X/7vbm7iLsGfoygF3gDhdy49SAMtTHE+QAojjs/xo1/pzQnfqmm9VyGjPErgDWBlc7HoKYDFCrelQAFbEFru+Rw/QteZ/ePtSUPjp209h47gYTDDQH04JzgnCcwGcUpUj7gAItzObAnBGOKZLASAizuyq9eWEZdeaX5tPrWfQegKMr/U5AXcAZMCZTQE4IxzTpQAQEWd2jR5g6ZpfWx+tzwm4A9RmdHD/FMDgBNUOjwKojfDg/kv0AKz5DUkufU7AHaAheSMuRQGMyErDmCiAhmCPuNQlPQBrfkcmE84JTJxyB+hI5ghLUwAjsNAxBgqgI/gjLG2qF6eARQ/Q+rt6QQ1EFJXP2GnxBv4Vf7i85h+vz7VzzwW4A+QyMPl8CmByAnPDpwByEZx8fsr/CBI1v3u+xppsjre2f3NAygT9fxZFHXAHiMKz/iAFsD7H0QwpgCg86w+m9AAChdr3udp9+PGY15IcDnD0ATW0uH+B3raVxu/q+p1Y4S7sYRAwAQB3AAGfP4MC8Me5yJgCEHD4M/Z6AKwZa6MS1MzPc+cLPc0W5CfT4w4g8XBnUQDuKJcJUwASD3eWuCc8ZS96gNL3rbXv80djMDh3gABL4wvut53PCwjOuQMgYs5sCsAZ4ZguBYCIOLP3zgGGhkCrqVrw1rN+63pW/1q8tce5A9RGeHD/FMDgBNUOjwKojfDg/tv3AMrZdG28sKaXrtnov3Y+uf65A+QiOPl8CmByAnPDpwByEZx8vtoD4Fly7bPrXDy1ml66RrdeT3uWYsWPO4AVscWupwAWI9SaDgVgRWyx68Wz4QdyE58PeOCa89u5PQL2HGfHiS+sNdl6PYZhnW/Fp0DNj3LMHQAZdWZTAM4Ix3QpAETEmR2tDw9gYeoJ0Ie1BuL83B4B/ZW2nzx9Llwe8buIr76KcTQuqPmXcHheljvAGQqfLygAn7yfs6YAzlD4fJFVPxIhi/YM1p4gtwfQ1sv1//Hmj4CFvxso4KAxGgIsAaMx0jgeCqAx4KMtl9IDYA1PmXM/Tzkfvr+O/+Pm/kQPrxN6jjy8ty06nzuAB5VFcqQAIuB4GKIAPLAcyXHvM4GyZkcmlxjCs2/vPcEOpshHtKZb53MH2EHM01sUgCe2d3KlAHZA8fTWXj3BmqPhgT7kfOW+nz1AHN6Ec4K4g3BU8MUdIATI1TsUgCu6w2QpgBATV++IenDKXNRwfH6u1iSl5rtCt0KyGv4JfAnOuQNUIGkmlxTATGxViJUCqADqTC73ngVE48caE724wWDrc4TW6yGEpfHnDoAIO7MpAGeEY7oUACLizFZ7ALzvLF2DnOE9XLrcAYajpG1AFEBbvIdbjQIYjpK2Aak9AIaj9QS175PRf/C7ePBbuhh/aVvDo/R6mj+MR7ueO4CG0OLjFMDiBGvpUQAaQouP7/UA4nnx//zF5wMQj6DmwOcB8HqrrdZ8cIjX537PAP0FPUfr9WG9BBP5FFO4Awg4/BkUgD/ORcYUgIDDnxGtD4lwRHuEq2cvhJvDUV7+9/cvMZ5gaDHLBRIcGi9puz72VPpvLmnxiXS5Awg4/BkUgD/ORcYUgIDDn2GqFxfCk1uTrTHmrodpWtfH+bnx5K6P8QibO4CAw59BAfjjXGRMAQg4/Bn/AKLLBse18egGAAAAAElFTkSuQmCC";function he(e,A,t){const n=e.slice();return n[7]=A[t],n}function De(e){let A,t,n,s,i,r=e[7].login.substring(0,17)+"",o,l,c,g,a,u;function m(){return e[3](e[7])}return{c(){A=h("div"),t=h("div"),n=h("img"),i=R(),o=V(r),l=R(),c=h("button"),c.textContent="INSPECT",g=R(),k(n.src,s=e[2](e[7].login))||f(n,"src",s),f(n,"alt",""),f(n,"class","svelte-16l7oqr"),f(t,"class","svelte-16l7oqr"),f(c,"class","svelte-16l7oqr"),f(A,"class","item svelte-16l7oqr")},m(d,w){I(d,A,w),D(A,t),D(t,n),D(t,i),D(t,o),D(A,l),D(A,c),D(A,g),a||(u=U(c,"click",m),a=!0)},p(d,w){e=d,w&2&&!k(n.src,s=e[2](e[7].login))&&f(n,"src",s),w&2&&r!==(r=e[7].login.substring(0,17)+"")&&hA(o,r)},d(d){d&&v(A),a=!1,u()}}}function tn(e){let A,t,n,s,i=e[1],r=[];for(let o=0;o<i.length;o+=1)r[o]=De(he(e,i,o));return{c(){A=h("div"),t=h("div"),t.textContent="Players",n=R(),s=h("div");for(let o=0;o<r.length;o+=1)r[o].c();f(t,"class","title svelte-16l7oqr"),f(s,"class","items"),f(A,"class","listing svelte-16l7oqr")},m(o,l){I(o,A,l),D(A,t),D(A,n),D(A,s);for(let c=0;c<r.length;c+=1)r[c].m(s,null)},p(o,[l]){if(l&7){i=o[1];let c;for(c=0;c<i.length;c+=1){const g=he(o,i,c);r[c]?r[c].p(g,l):(r[c]=De(g),r[c].c(),r[c].m(s,null))}for(;c<r.length;c+=1)r[c].d(1);r.length=i.length}},i:p,o:p,d(o){o&&v(A),TA(r,o)}}}function nn(e,A,t){const n=["quentin.briolant","dumeig_a"],s=["mareo"],i=[qt,_t,$t,An];let{game:r}=A,o=[];r.players.subscribe(g=>{t(1,o=g)});function l(g){if(n.includes(g))return Zt;if(s.includes(g))return en;const a=Array.from(g).reduce((u,m)=>u+m.charCodeAt(0),0)%i.length;return i[a]}const c=g=>r.selectPlayer(g);return e.$$set=g=>{"game"in g&&t(0,r=g.game)},[r,o,l,c]}class sn extends _{constructor(A){super(),q(this,A,nn,tn,W,{game:0})}}const{window:on}=Pt;function Qe(e){let A,t,n,s,i,r,o,l,c,g,a,u,m,d=e[0].closeButton&&pe(e);var w=e[1];function C(Q){return{}}return w&&(r=new w(C())),{c(){A=h("div"),t=h("div"),n=h("div"),d&&d.c(),s=R(),i=h("div"),r&&K(r.$$.fragment),f(i,"class","content svelte-ktxllv"),f(i,"style",e[8]),f(n,"class","window svelte-ktxllv"),f(n,"role","dialog"),f(n,"aria-modal","true"),f(n,"aria-label",o=e[0].ariaLabelledBy?null:e[0].ariaLabel||null),f(n,"aria-labelledby",l=e[0].ariaLabelledBy||null),f(n,"style",e[7]),f(t,"class","window-wrap svelte-ktxllv"),f(t,"style",e[6]),f(A,"class","bg svelte-ktxllv"),f(A,"style",e[5])},m(Q,P){I(Q,A,P),D(A,t),D(t,n),d&&d.m(n,null),D(n,s),D(n,i),r&&G(r,i,null),e[42](n),e[43](t),e[44](A),a=!0,u||(m=[U(n,"introstart",function(){eA(e[12])&&e[12].apply(this,arguments)}),U(n,"outrostart",function(){eA(e[13])&&e[13].apply(this,arguments)}),U(n,"introend",function(){eA(e[14])&&e[14].apply(this,arguments)}),U(n,"outroend",function(){eA(e[15])&&e[15].apply(this,arguments)}),U(A,"mousedown",e[19]),U(A,"mouseup",e[20])],u=!0)},p(Q,P){if(e=Q,e[0].closeButton?d?(d.p(e,P),P[0]&1&&b(d,1)):(d=pe(e),d.c(),b(d,1),d.m(n,s)):d&&(T(),H(d,1,1,()=>{d=null}),S()),w!==(w=e[1])){if(r){T();const y=r;H(y.$$.fragment,1,0,()=>{j(y,1)}),S()}w?(r=new w(C()),K(r.$$.fragment),b(r.$$.fragment,1),G(r,i,null)):r=null}(!a||P[0]&256)&&f(i,"style",e[8]),(!a||P[0]&1&&o!==(o=e[0].ariaLabelledBy?null:e[0].ariaLabel||null))&&f(n,"aria-label",o),(!a||P[0]&1&&l!==(l=e[0].ariaLabelledBy||null))&&f(n,"aria-labelledby",l),(!a||P[0]&128)&&f(n,"style",e[7]),(!a||P[0]&64)&&f(t,"style",e[6]),(!a||P[0]&32)&&f(A,"style",e[5])},i(Q){a||(b(d),r&&b(r.$$.fragment,Q),tA(()=>{c||(c=OA(n,e[11],e[0].transitionWindowProps,!0)),c.run(1)}),tA(()=>{g||(g=OA(A,e[10],e[0].transitionBgProps,!0)),g.run(1)}),a=!0)},o(Q){H(d),r&&H(r.$$.fragment,Q),c||(c=OA(n,e[11],e[0].transitionWindowProps,!1)),c.run(0),g||(g=OA(A,e[10],e[0].transitionBgProps,!1)),g.run(0),a=!1},d(Q){Q&&v(A),d&&d.d(),r&&j(r),e[42](null),Q&&c&&c.end(),e[43](null),e[44](null),Q&&g&&g.end(),u=!1,N(m)}}}function pe(e){let A,t,n,s,i;const r=[ln,rn],o=[];function l(c,g){return g[0]&1&&(A=null),A==null&&(A=!!c[16](c[0].closeButton)),A?0:1}return t=l(e,[-1,-1]),n=o[t]=r[t](e),{c(){n.c(),s=aA()},m(c,g){o[t].m(c,g),I(c,s,g),i=!0},p(c,g){let a=t;t=l(c,g),t===a?o[t].p(c,g):(T(),H(o[a],1,1,()=>{o[a]=null}),S(),n=o[t],n?n.p(c,g):(n=o[t]=r[t](c),n.c()),b(n,1),n.m(s.parentNode,s))},i(c){i||(b(n),i=!0)},o(c){H(n),i=!1},d(c){o[t].d(c),c&&v(s)}}}function rn(e){let A,t,n;return{c(){A=h("button"),f(A,"class","close svelte-ktxllv"),f(A,"aria-label","Close modal"),f(A,"style",e[9])},m(s,i){I(s,A,i),t||(n=U(A,"click",e[17]),t=!0)},p(s,i){i[0]&512&&f(A,"style",s[9])},i:p,o:p,d(s){s&&v(A),t=!1,n()}}}function ln(e){let A,t,n;var s=e[0].closeButton;function i(r){return{props:{onClose:r[17]}}}return s&&(A=new s(i(e))),{c(){A&&K(A.$$.fragment),t=aA()},m(r,o){A&&G(A,r,o),I(r,t,o),n=!0},p(r,o){if(s!==(s=r[0].closeButton)){if(A){T();const l=A;H(l.$$.fragment,1,0,()=>{j(l,1)}),S()}s?(A=new s(i(r)),K(A.$$.fragment),b(A.$$.fragment,1),G(A,t.parentNode,t)):A=null}},i(r){n||(A&&b(A.$$.fragment,r),n=!0)},o(r){A&&H(A.$$.fragment,r),n=!1},d(r){r&&v(t),A&&j(A,r)}}}function cn(e){let A,t,n,s,i=e[1]&&Qe(e);const r=e[41].default,o=nt(r,e,e[40],null);return{c(){i&&i.c(),A=R(),o&&o.c()},m(l,c){i&&i.m(l,c),I(l,A,c),o&&o.m(l,c),t=!0,n||(s=U(on,"keydown",e[18]),n=!0)},p(l,c){l[1]?i?(i.p(l,c),c[0]&2&&b(i,1)):(i=Qe(l),i.c(),b(i,1),i.m(A.parentNode,A)):i&&(T(),H(i,1,1,()=>{i=null}),S()),o&&o.p&&(!t||c[1]&512)&&it(o,r,l,l[40],t?st(r,l[40],c,null):ot(l[40]),null)},i(l){t||(b(i),b(o,l),t=!0)},o(l){H(i),H(o,l),t=!1},d(l){i&&i.d(l),l&&v(A),o&&o.d(l),n=!1,s()}}}function gn(e,A={}){return function(n){return new e({...n,props:{...A,...n.props}})}}function an(e,A,t){let{$$slots:n={},$$scope:s}=A;const i=Ct(),r=ht;let{show:o=null}=A,{key:l="simple-modal"}=A,{ariaLabel:c=null}=A,{ariaLabelledBy:g=null}=A,{closeButton:a=!0}=A,{closeOnEsc:u=!0}=A,{closeOnOuterClick:m=!0}=A,{styleBg:d={}}=A,{styleWindowWrap:w={}}=A,{styleWindow:C={}}=A,{styleContent:Q={}}=A,{styleCloseButton:P={}}=A,{setContext:y=r}=A,{transitionBg:Y=Le}=A,{transitionBgProps:x={duration:250}}=A,{transitionWindow:E=Y}=A,{transitionWindowProps:F=x}=A,{disableFocusTrap:M=!1}=A;const J={ariaLabel:c,ariaLabelledBy:g,closeButton:a,closeOnEsc:u,closeOnOuterClick:m,styleBg:d,styleWindowWrap:w,styleWindow:C,styleContent:Q,styleCloseButton:P,transitionBg:Y,transitionBgProps:x,transitionWindow:E,transitionWindowProps:F,disableFocusTrap:M};let X={...J},iA=null,PA,bA,yA,NA,_A,$A,Ae,ee,te,ne,se,ie,oe,re,le;const Te=B=>B.replace(/([a-zA-Z])(?=[A-Z])/g,"$1-").toLowerCase(),fA=B=>B?Object.keys(B).reduce((uA,$)=>`${uA}; ${Te($)}: ${B[$]}`,""):"",ce=B=>!!(B&&B.constructor&&B.call&&B.apply),Se=()=>{t(5,_A=fA(Object.assign({},{width:window.innerWidth,height:window.innerHeight},X.styleBg))),t(6,$A=fA(X.styleWindowWrap)),t(7,Ae=fA(X.styleWindow)),t(8,ee=fA(X.styleContent)),t(9,te=fA(X.styleCloseButton)),t(10,ne=X.transitionBg),t(11,se=X.transitionWindow)},MA=()=>{};let ge=MA,YA=MA,ae=MA,HA=MA;const fe=(B,uA={},$={},z={})=>{t(1,iA=gn(B,uA)),t(0,X={...J,...$}),Se(),Je(),t(12,ge=AA=>{z.onOpen&&z.onOpen(AA),i("open"),i("opening")}),t(13,YA=AA=>{z.onClose&&z.onClose(AA),i("close"),i("closing")}),t(14,ae=AA=>{z.onOpened&&z.onOpened(AA),i("opened")}),t(15,HA=AA=>{z.onClosed&&z.onClosed(AA),i("closed")})},oA=(B={})=>{iA&&(t(13,YA=B.onClose||YA),t(15,HA=B.onClosed||HA),t(1,iA=null),Ve())},Ne=B=>{if(X.closeOnEsc&&iA&&B.key==="Escape"&&(B.preventDefault(),oA()),iA&&B.key==="Tab"&&!X.disableFocusTrap){const uA=yA.querySelectorAll("*"),$=Array.from(uA).filter(AA=>AA.tabIndex>=0);let z=$.indexOf(document.activeElement);z===-1&&B.shiftKey&&(z=0),z+=$.length+(B.shiftKey?-1:1),z%=$.length,$[z].focus(),B.preventDefault()}},We=B=>{X.closeOnOuterClick&&(B.target===PA||B.target===bA)&&(le=B.target)},xe=B=>{X.closeOnOuterClick&&B.target===le&&(B.preventDefault(),oA())},Je=()=>{NA=window.scrollY,ie=document.body.style.position,oe=document.body.style.overflow,re=document.body.style.width,document.body.style.position="fixed",document.body.style.top=`-${NA}px`,document.body.style.overflow="hidden",document.body.style.width="100%"},Ve=()=>{document.body.style.position=ie||"",document.body.style.top="",document.body.style.overflow=oe||"",document.body.style.width=re||"",window.scrollTo(0,NA)};y(l,{open:fe,close:oA});let FA=!1;ze(()=>{FA&&oA()}),wt(()=>{t(39,FA=!0)});function Ze(B){wA[B?"unshift":"push"](()=>{yA=B,t(4,yA)})}function qe(B){wA[B?"unshift":"push"](()=>{bA=B,t(3,bA)})}function _e(B){wA[B?"unshift":"push"](()=>{PA=B,t(2,PA)})}return e.$$set=B=>{"show"in B&&t(21,o=B.show),"key"in B&&t(22,l=B.key),"ariaLabel"in B&&t(23,c=B.ariaLabel),"ariaLabelledBy"in B&&t(24,g=B.ariaLabelledBy),"closeButton"in B&&t(25,a=B.closeButton),"closeOnEsc"in B&&t(26,u=B.closeOnEsc),"closeOnOuterClick"in B&&t(27,m=B.closeOnOuterClick),"styleBg"in B&&t(28,d=B.styleBg),"styleWindowWrap"in B&&t(29,w=B.styleWindowWrap),"styleWindow"in B&&t(30,C=B.styleWindow),"styleContent"in B&&t(31,Q=B.styleContent),"styleCloseButton"in B&&t(32,P=B.styleCloseButton),"setContext"in B&&t(33,y=B.setContext),"transitionBg"in B&&t(34,Y=B.transitionBg),"transitionBgProps"in B&&t(35,x=B.transitionBgProps),"transitionWindow"in B&&t(36,E=B.transitionWindow),"transitionWindowProps"in B&&t(37,F=B.transitionWindowProps),"disableFocusTrap"in B&&t(38,M=B.disableFocusTrap),"$$scope"in B&&t(40,s=B.$$scope)},e.$$.update=()=>{e.$$.dirty[0]&2097152|e.$$.dirty[1]&256&&FA&&(ce(o)?fe(o):oA())},[X,iA,PA,bA,yA,_A,$A,Ae,ee,te,ne,se,ge,YA,ae,HA,ce,oA,Ne,We,xe,o,l,c,g,a,u,m,d,w,C,Q,P,y,Y,x,E,F,M,FA,s,n,Ze,qe,_e]}class fn extends _{constructor(A){super(),q(this,A,an,cn,W,{show:21,key:22,ariaLabel:23,ariaLabelledBy:24,closeButton:25,closeOnEsc:26,closeOnOuterClick:27,styleBg:28,styleWindowWrap:29,styleWindow:30,styleContent:31,styleCloseButton:32,setContext:33,transitionBg:34,transitionBgProps:35,transitionWindow:36,transitionWindowProps:37,disableFocusTrap:38},null,[-1,-1])}}const un="/assets/yakalogo-9c226523.png";function Ee(e,A,t){const n=e.slice();return n[1]=A[t],n}function ve(e){let A,t,n=e[1]+"",s,i;return{c(){A=h("div"),t=h("div"),s=V(n),i=R(),f(t,"class","name svelte-1qcloh3"),f(A,"class","item svelte-1qcloh3")},m(r,o){I(r,A,o),D(A,t),D(t,s),D(A,i)},p(r,o){o&1&&n!==(n=r[1]+"")&&hA(s,n)},d(r){r&&v(A)}}}function dn(e){let A,t,n,s,i=e[0].achievements,r=[];for(let o=0;o<i.length;o+=1)r[o]=ve(Ee(e,i,o));return{c(){A=h("div"),t=h("div"),t.textContent="Achievements",n=R(),s=h("div");for(let o=0;o<r.length;o+=1)r[o].c();f(t,"class","title svelte-1qcloh3"),f(s,"class","items svelte-1qcloh3"),f(A,"class","svelte-1qcloh3")},m(o,l){I(o,A,l),D(A,t),D(A,n),D(A,s);for(let c=0;c<r.length;c+=1)r[c].m(s,null)},p(o,[l]){if(l&1){i=o[0].achievements;let c;for(c=0;c<i.length;c+=1){const g=Ee(o,i,c);r[c]?r[c].p(g,l):(r[c]=ve(g),r[c].c(),r[c].m(s,null))}for(;c<r.length;c+=1)r[c].d(1);r.length=i.length}},i:p,o:p,d(o){o&&v(A),TA(r,o)}}}function Bn(e,A,t){let{player:n}=A;return e.$$set=s=>{"player"in s&&t(0,n=s.player)},[n]}class mn extends _{constructor(A){super(),q(this,A,Bn,dn,W,{player:0})}}function Ie(e){let A,t=e[1].login+"",n,s,i,r,o,l,c;return{c(){A=h("div"),n=V(t),s=R(),i=h("button"),i.textContent="Goto",r=R(),o=h("button"),o.textContent="Achievements",f(A,"class","current-player svelte-eeciu1")},m(g,a){I(g,A,a),D(A,n),D(A,s),D(A,i),D(A,r),D(A,o),l||(c=[U(i,"click",e[3]),U(o,"click",e[4])],l=!0)},p(g,a){a&2&&t!==(t=g[1].login+"")&&hA(n,t)},d(g){g&&v(A),l=!1,N(c)}}}function wn(e){let A,t,n,s,i,r,o=e[1]!=null&&Ie(e);return{c(){A=h("header"),t=h("div"),n=h("img"),i=V(`\r + CREEPS`),r=R(),o&&o.c(),k(n.src,s=un)||f(n,"src",s),f(n,"alt",""),f(n,"ondragstart","return false;"),f(n,"class","svelte-eeciu1"),f(t,"class","title svelte-eeciu1"),f(A,"class","svelte-eeciu1")},m(l,c){I(l,A,c),D(A,t),D(t,n),D(t,i),D(A,r),o&&o.m(A,null)},p(l,[c]){l[1]!=null?o?o.p(l,c):(o=Ie(l),o.c(),o.m(A,null)):o&&(o.d(1),o=null)},i:p,o:p,d(l){l&&v(A),o&&o.d()}}}function Cn(e,A,t){const{open:n}=Dt("simple-modal");let{game:s}=A,i=null;s.currentPlayer.subscribe(c=>t(1,i=c));const r=()=>{n(mn,{player:i},{styleWindow:{background:"#1b1f24"}})},o=()=>s.moveTo(i),l=()=>r();return e.$$set=c=>{"game"in c&&t(0,s=c.game)},[s,i,r,o,l]}class hn extends _{constructor(A){super(),q(this,A,Cn,wn,W,{game:0})}}var L=(e=>(e.Empty="a",e.Water="b",e.Rock="c",e.Wood="d",e.Food="e",e.Oil="f",e.TownHall="g",e.Household="h",e.Smeltery="i",e.Sawmill="j",e.RaiderCamp="k",e.RaiderBorder="l",e.Road="m",e))(L||{});const Dn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAADBdJREFUeF7tXV1zHMUVndldA5WybFnS6sP7IccFv4biKyBZFuYVZFmY14BJqoCQZ8D6tHh02cg2hgT+BVAUpHhLJci7K9mSkQzmIWG1O6mkKlV7zlB96eqRtDJHb6vu6Zm5c/qe2/fevh1He/x39tx00nnLUnkAnqBRvwu/F+bmY9cjWuPFMV5+4fdvOMcLFQc/jzWe9X7W9aHtuyqMn3s464MJAKGf1O96AcBPXmZvaQBDRNIAKKCuo4Cp6bPA0fw9F+cXnFrj9PgzcH1vcQSGYM7n8S0KmJ45B+MnCT6uNX4+j4//j7/fgUdYvrTo9X49fYNw/clHh5xTgO/Hne9vbcC/rl77aFe1dGpwAUAAkAZwzGHWcNIAJCxRwANGAeVKET5xbRXX6UuLuE5nAPBkYpuA2+9trjs5cOY82gDNn1BhVU/gB0iSJozXbuMd2SaorW5Bh8WFOaBJ6/1YIzCnW8sIX85nm4jHn5/F5+d20wYQAAQAaYAOCUgDiAKcRvKBowBe9lWqwzDjG3Vcl/pyjDVjeDzmwMnxJ0DgPf0luCSfzxPHE8knOWgvV4/B77X6fbw++RfaAPNLXn4B630sG4DbZ86/DO/f2kH8tcmoYRuIvx/bBLEAIAAApKQBpAFEAR0SWPy1UQAv+9g3v3V7DQCy8uHHwJEc7GGOnn3vopdvm22Io4NluH+ctLxodaeJNsLDj6AN0Wohx4YGa86cwtjIb3rRxjr5GPpZOFbA+Qy5HNk05KdptdDv0aijX4O/R8oGEAAEAKIA9PxJA3gpnEgagJZpooAuo4DJsacwfj9YBYjf27iF6+QIKfyD624bgOP1TDE8n15/9U2n7z0fIwf2DLiDLzx+EiPnb6/9E22am5962Sg8/unnnkR5DqHNUh3F5202kbPjGCmIOZxtgtT7UX4Et7fJZIoFAAFAGqBjmqxIA4gC/Mw87H3gKaCV4Do5Js5kzk/5qltIMmwDJG2k2Moo7gtgG4A/xvizyLG0LP4F3w5tCL6A3++tP18ADfmH196GF+Dn4XW2d05kDdftUUyxjV/whj5dUjaAAIBGrQAgDSAN0KlSRAEPGAVYfPHi1EswA5jjrOutds7jt2yAiTG0AazxC4WHoMvlqzecfobD/biPYXkBcx4tzmebp28I8xd81+3W+1njtSK0yX7cuI2xFOsGAoAAIA3QMUukAci3b2kQq10U4EwxtMSXamcK8qYAjr8zJxbcy2jvBz5ewhw99nW//uqfgnzz1gNZOYtWnv6ZU89izh75URLKV+gb+S08UkLx+xzFWtqRGyCp/gmKa3uzDvdjIz4lXAEAISMAkFUsDYAAkQawdKzRLgrAcPC+U8DE2NNAOszJRwcwocH6/pzDxr9bFDvg8UJz8qzny7r9+QnMAeS9iNb9egfQb9BOdpyX5OICtH93uwa/C5j+EF25/heg/ZQNIABYn8jdLgCQfKQB/AAlDUDyEgXsMQUwXl+YHAObgHPYuH+O1q20LI2OFCtwSS7CeDfnC+SIw6z97vw8U2exnkCpegTvHz8Cvxs1zIKen/Pbx8D3Z0rl9jhCDo9i9N1bsYS768j5h/LoqLm84q4xZDpZBAABQBrAj8ahtzQA6RhRAKKp6ykgAPz/u/T0OO47sADAjqH6rW14BK5JxM937uUZp/Oc99dXRvucr7jWwPvPXZw1adNHZs9PoHzabb9gSxyhkXjl2idez+fV2efF/t9XALD8BgIASEgaQBoAACEKcGuQzCnAio/39GEe/6XFZaOGjp8NUCojJ/PeOHYMWbWDLdqyagtbtYt5fK6PwLEUXz+G9fyh7WY+AN9AAPA7wEIA8FwFSAOEzmm/66UB6MgaFt8DTwFWcWcWCK+jDx16GLrMzb7jtglo/3zPAObhc/SQzyeYPv8KrPN/uIM5b771AkJtgBcmnsM6hlSvYHgYbabNze9AXhffdfsVzk4bfo32v2G89HkDGP9PxSIEAPxAvhpAAJAGkAbonDWiACwBc+ApYHjkqNOsXG/8AO0t4qTlpfczdTe/+fZrMOPWb/8I99+m+PixIbQxUi+TqiXcj46o2ib8Zj9Eqo4h5Uxa+Q18PgLXEyjkcW9jcYjyGchx+M2XX8HzXr0WaAMIAAKANECHBKQBCA6iAEwD57T5rqeA8WceB04dKJ2AT2yfy4c5favf4vkCy0uXgmwA3p5erqCRlc9j+L9ew3W25RdjV207ckfjFmcxRezMafQD8D4Hrvt3ZYXqKtI6Py6guPIRJkUOjRyGV+IaTt98+Tdov7Jy0yn/WABA+QgA0gBOpSENkPKdiwI6EXPwKIDq7vUPY21bng5p3zkCgOP3Ea2zF+bdvu+szwewbAD2nfMZPPyb99fz+JyfUKni2cK8r+KPF7D+weQYGZWDFCuhmkdb66vWK5JfAPcJxFzyRABAQAsAhC9pALTipQFoa5coALeidT0FTI79jurbI+f4+gHW1+7hpCAbYG72Pa9z+PrIl++7394iSNZonACyvcE1dv7qPCPJvh/aBBFNIOu8BB7fOouZ+3PsIRYAMB9AAKAZJw0gDQBaxDICRQFuEiiVu4wC2BXcVzqJvmaqc8e++Hb7J+jPe+m2N/CcQWsdbe1L8OU8m5PDKGBqBs/25XMMORhk1Seo1+7AI39/F+WXUMEF3/MIOFaQigUIAFggwjICBQBpAKyqRhpTGkAUgDaUUaJmzymAOZJtgmIZa9um6vrROj/OYXw+axuAXbNWDZ3dtgFYXv3HR+GWqbqIOygfrk/A+QxWBlKwDSAAhBmBAoA0AExpaQBRwMGmAKYErnLFnMb9W02sWbNyE33nFidzO5de5XWw73jcn20K9nyu3HDn1fturbPyK6zNqNb9dpoYzj75KOZQfv351+jnsQQoAAgAwHHSADhlrBlpTTArGum7CpAGsCRO7aIAT4Htd3crVhD6fNYRMZaNxPsAeovucwNjyvvn8wG4PoKlcXifA2uE+9ue5waGCjTr6wUATBplR5AAEIg4aYBAAe725dIAXaYBuC5e1gCwDowIBYTvjLfeb/IU5li22+4DH3i8D667/Sbp6uO47reej/cSBm3c/O/NBAAUuQBgQdCzXRoABSYNQAASBewxBfiqfLMOX20LP2nsfiFLI3gqmFR36/0KBTzj5+K77n0Ooc9jXT8x9qTzfATLpvC2ASwBWcEObm8IANY3drYLAEHiS19sAVwa4Ny014H3ooCMEUrDZa4B+DTsw8XjcEvOe+fXY1ektTmSo4u3vsWybHmqmcP9Q8/wmZp+ic5KpoMK6QWtjTG8OfbeZgNGsM5M8oVLqE2UsgEEAAEAZoQ0AM5JaQDa+CAKcJfI6XoKsBwpRwexZpBlAzAg+HwBzlHb2XGv+y2bgOPv87MLzqUte9KODaKNY3FwuVKELq1WE37z3kje2xdqA1RH8f63VtFm4gSXpYVFd51AAUAAcC7rpAFQJ0gDGDaAKACPmu16CjhzChMMmi3k5IGRCnxT5hiLM632cgXr83MNIPYrcN68NT6vk0NtgHYL71g9gXn37Kf46rMv4ALey8j7EKz3Yb+K9T3Y1c51GmMBwM8GEAAyLtMlDeDlWY+kAepYwcNSmaIADLenKIAFODn+BEAyiTD+nXWNHs6LHyn1YuwhxmXsftsAqfMFSCNyDmCBavsyZ/N4FqCZgiqjxrF3FG4XAMaeBoD7OoIEgKJxCpcFYWqXBvDLyZEG2Gcb4IHXADyBeX/+kf5sNQDfL5/HcGyqJpGnhsnaCPS8febd2RPp60do1PFMJ1P/CACZf8OgAQUAT/FJA6DApAECVwGe+Mu8+55rAE46LOSQo3sGdtcmMCXoeSYRxwLYqOODH33X6WyzfL+BOYHHjmPdRd/8Cq48Wq5iLCUtLzwH0VsDCACmmUQJIhgtEgDMKRzYQRrAEKA0AAhIFOC5DGR4cQpZLsJo1hHaRxA4v1OXh+7MsQCQdayDayVbNoV1f44lsDxYYFwjiEy4yI/goigSAPwgLQD4ycvsLQ2AGVvSAJ7bs0UBOMe8KYCPmmXfvTmFjQ4cnmVfd+heOCvWkXHCU+ptuSaRlZYfKk/+Ppev3oBvLgBMYFKsAGBAThogbE5KA4gCQOvuNwX8B21/fr9Ep6LWAAAAAElFTkSuQmCC",SA="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABs1JREFUeF7tnTFvFTEQhPNQFCFRUVIgfgEFBT+Lip6/TBUJRRHQ5jaSP41m7fN7Gaog363Xs+PZtX137/Lpx9d/dy/+3T/cv/zvdn8/Pz0ffOr2992H4/j/Ph772w2Qikf1j/C5hABHyEKAKMCBEVGAzTQvKeAYEDsFfP757VADdMe7Smq1r84wlwDu/YRPdwpR7anju4QAvUWvGrBuQoUAgKgKEAWotocABZGkAG8ZqRJKJTimANVgd8DVGVivd4sk6l8dr4unWjOR/yGAuewNASZLPjGY2qMAY4SiAFGA8T7A7Bmk5kSa8d3t3f7NxlMtGmUFUA8bKCDdAFN/anu3fyFAiUA3wGqA6fpu/0KAEGDIOTq+JcLKKeDLr++Hs4C6zpzN2Nn2CTBqn+2fqzDqMrSO9xICjCkQApQncGYXgd32aYZTewgQAkzN2dunANpbd4sWmmGuIqhFkaoI7vipP2p3x4c1QAhwRMCdsRRQtT0EAMRcgGZPADXg9Xp3fFEAMQI3pwCzHwkT8b1zawJ3Xaz6S9e7M5Tsq+0VXzwLUDtwrw8BXAS1fY0QYC7ed1EAEeAogAiYeHl7CuhmeLX39PuPtBHj3i/i+ery3WoQmlB2CggBjhwIAcy3ad0Z7N4fBRARiAK8MQXoljiyp9YAxN+aEx8+vj/c4j53r04IdWOp275cA1DAVADJXggwVhjCmwgWAkQBtNfDacYSI+kwo7ZHASYrgPqJGMpBJDmUo1e3dxOa/Kd1ufp8AcWD/JG/EUQdhgDaXny9OgQgyja3RwHEz8RFATwGbp8CXEnqHqAHt343EVy1SHi4eKv+1Otf1QCuQzRgNce5A1TvDwEKYmrAQoAjgISHO+FUgkcBALE3pwD1mcDuZVy3PZfxq+8nBVAVttv/V1vB3QHrttcNwGx7IcDkr3vPDqBrPwQIAYYc2i4FuIyn+90ii1KKa5/8p3aa8d1VP+FB/srHwWSQ2t0A0YBd++Q/tYcAk5dZIcB4n0FNKVEAmtJi+80rAM1AwkuVaAK0Mt61r84g8m92zlft2y+GhADnbvUS4YjAIUCZMi6hKSDqDCUFpf5CAPFn30IA8TeDVAa6OVmdQRRQ1f/a/9lvHpFCUHt7CqAAhQC9v0lEAab2EMD87F0UQAQwCnBjClAlxs2ps+2RfaqaqQZQX4Qhie5up/jYO4HUgQpwt70QYPyrZSGA+JMxakrrntGqPZpQIUAIoL0cSpJKy0KVwbl+jADtexB+2ykAOZz28VmEWnOFAFfOqCjAlQfQdf90ArgDcO93AXD7p5qIJNl9O5mqfOrfTgHdAKr2QoDxOj8EUBllXq8SMgqwGHCzO7z96gigfiPIzTmIIFxwdv+U89V9kO6dRZWA8jeCzg7A2f2HAOJxsDvjuwHfzZ8ogBiRKEDv1rD8iRg1x1R3VcZTwNWcS/7Udjrvd/Gg8c3+lnEIUJ4iDgEKAnUjwWV8FGB8mFMJGAWAojMpQCui6gSc/omYs3e6CB56ype2Usm+2u7iRf2FAAWhEKC8GeTm+NlVtiv55F/9PH0UQHxmjgB2q+wQYHz6Z6cAMuC207p39YzbzR91leTGY/nzALsBvps/IYCZctQZEQKIr4erAN/6YY6LB9VMtBXt9o8pYPa61B2Au2pZfX+3xLv2QgDzS6YqgdyAdStGCBACjF8NSwoYJ6k3pwBUlKyuqtUAdNcctDE1ewK59uUUEAJoz+G7ASLCuvZDAEK4tKsK5waI3HPthwCEcAhw/MgRpQB144dyKMVn9YxU+1P9X30W0q4AIYD2VbDVRWyNTwhQECGFiwI8aufRBFhSwBHP7VIA5TC1nQjhAtAtqd3+dtujlEt4YgpQA0zX7wbAan93G38IAAzoDli3vSgArNNJAqMAix8IIcB3a++esbvZW54Cdgsw+bNbwEjy1VVVCHDlNYBL0BAgBNAeCKGdMpIotygjye5+5Ir6U9tn71Oo+KICuIB2D5gAd/0l+257Nx6uvRDAjah4vxuwboUNAcQAupdfPQEqAFQTuFWqCrj7hIzbH+Gh2u+e8fh9gNqhC2gI4Ib8eL+rICGAeJxN4VtddIYAEBFXsSjgpJA3lwLOHrAakNn+riaYO366H1cBswElB932bokOAcSfZ3cD6N4fAowRjAKIDHvzCiDiJV/uVrlqh6uXqd3rehov4SkrAHXotpPDrn0KQG1XD1dU/2aPl+yHAJv9/kE34UIAmJJJAZs/E0gM7l6mqv2R5NMqpLs/8qf2t10KoBxNEkmAqwBRf2SP/AkBRImmgBDgFLDugJA/3f2p44sCFMS6A7I7Af4DZz1gdckJRZUAAAAASUVORK5CYIIA",Qn="/assets/water-b463aada.png",pn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABaZJREFUeF7tnU2KFTEUhUu08RcfCEIjoqgDwT2IA8duwAW6AceC4gKcCQ5UdCANivrEX7pFp+Y21OF4U9WpyufQSlLJyZdzbyX1uo4N/OtagWNdj57BDwDQOQQAAACdK9D58HEAAOhcgc6HjwMAwLoUuHP/7p/MiJ48eNTVoljdYAHAwx8Agl44gAdQc6VxAG9KmncAd0J/X9kpFDh1/aylyP7jz0X56Ahuf9TNj9pxACDMEAAoZGe+7q44HMCbIBwAB/CIyZZ2V/T3zYF1y5Ob01b5mCPEEBAbiw4Tr9fOOazB/Efh2R0AAMpZUjnHf8ypVQUAwlMCDmDx4xfGATpzgDjhbkz3EStruDlBvN+v7Y/iv9z2Ws8JJg8BAFB3Iyq7IGJ9ABCK4gBJ5HAAHKA4n485QIypKmZun31IIjltdTdHiL05/nZ/9Cyidu+PPAQAQDmlACBO73CAuh6AA9TVc+g+BKikzxUo5gQ/X30rpixm6XE+1f3mzjlUfxYfAgBg3FIAIHlahwPUjVnVcwAcAAewnvuzPGdzAPc833Ugd3wxREydEzTvAEpAAFAKjV8HgKCPeirAAQRwtXMAxTcOoBRqzAFUd9VjkprwbPuqfryu+pMdz5ntiUnPBmYPAUrgrGDZ9lV9AEiGACUwAJQK4QCBGGW5WcBUfRwgKKCSPlfQucsrx3EnXPU/3k8B3bwDAICa8vI6AHh6TV4aB0hKjAN4Ai7eAeaecLVC1c7d1G8QTf1KW3M5AACMx/TaQAKAeH+gtuCeoQ+HXgGr3R8AAIC2toJjCNgOX0cXzc7mVHHdTYJUDhBvHldg7Rwg25/YX9W/qd8PsM8CACD3BygAIFi62gnLrji1wrIxX9XP5gQ4QPIlUgAYR/TIQ4C71+46QtZhsvXd8cXyq3cAVyAAqPvjURxAhBgcQBz/Zh8DcYDxGN1cCIjdnXtrWGXd7nV3X8Jtv3b52juDdggAgNpT6rUHAJ5esjQOICUaL0AISApoVm/OAVRIiEliPBswx999cQDoHAEAAIBCgewXR9JPAYSAeYlcvANEuWJOsL/9WRTJ5gyxPXX/eafz8N1ifzfDuaorPt5xdgdQEwAA5QIAgPBGkbtCcYBxxXCAJGAukKp8dyFACeKGjGz51uqvPgQAwLgCABD0UU8Nra1gt7+x/wAAAMt6DHQ3htwQsPbyU6/4yfcBACCHKADk9Ft8bQBY/BTmBrA6AFRIUHKpl05V/ShoLJ9tX2Xtqn/Z0zzVvrpefSdQ3dD9cmh2ggBgfEYAQPy6WQGNA5gK4QClYN2FAJOXIQvMtb3y27/x/q93x3/urUJIbO+oJ9TVd/YQ4HYQAFzFvPIAgAN4xMxdGgeYVvHmHcAdfgTmwt57q4mPuxeL8kuL6dZgh2EAgKAYALgINVYeB/AmBAfAATxiWi997/at4ruFJ3bKb+7cuHR+dAgv3nwsrj98+nx1i+TfAa5ucADgLVEACHrhAB5AzZXGAbwpWb0D3Lx6wVIEB7Dkaq9wdAAAGJ8jHIAcoL1VnOkRDuCpt3oHcPcBXr77Uih4sH+w6n0BAAgLBgA8B2mudPYxEACam1KvQwDg6dVdCIjy9H42AACdHw4BAAB4MaP10ioHIASUCizOAdw/Tn35xadixCrmR0DWfjYAAMLSAKAxz8cB6k4IDoAD1CWqdmtTr/i48xdzhLXvDDbvAABQe0kt7CkAAACgeM37+6Y8no3yuI99hIBpAbNbV5+nV98PiACojZ8IgCq/tsfC5nIAALDXTKoCAIQ3gHCAFE/5yjhAXkOnheYcIHZe/YGI+Pt/9RzvngWs/WwAAJzlMgwDSaApWLY4DpBVcLw+DmDqiwOYglG8bQWad4C25Vt+7wBg+XOYGgEApORbfmUAWP4cpkYAACn5ll8ZAJY/h6kRAEBKvuVX/guK0yjM3bNIbwAAAABJRU5ErkJgggAA",En="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAB7xJREFUeF7tnburXkUUxb+oJBhEbiIEIr5Im8JWURDRwkILQWzsFQtt1EIMiBAQCTamENPbiJ0KFoqNiv9ABBGCieGmkOReokQTfBU2WauY393OOd89OWfd7jLnzDezZ521H7P3zJ5V/hYtgT2Lnn0mvwoAFg6CACAAWLgEFj79MEAAsHAJLHz6YYAAYOESWPj0wwABwMIlsPDphwECgGlL4IkT9/5z/Qg/f+2sgPaBFw9L+8aRvTIhf37as13/6CbPAAHAuKAIAMaV7+R7DwAmv0TjDnByAPjikftFp/+6eV4k8PSPF5tjJpXx6Ot3S//7Dt4k/V+99Lf8/9XbP8vvUf+0XL3vU//V9gAgAKhiZtznwwDjytd7DwOEAcZFnOs817Gug1849ZsM6PRV1clfv3S7tG+fuSb/f/f+hSao3Qa4+I3GDe586s9m/7du3CLtPn6S5tTiEqMzQACgkAgAzMoOAxBnjNseBogKqCHMKd3fdh3v7eR3/76tOtjf91g/2RROucfvOSBxgKP7NA7wwfO3NeMCPn63QchGoDhDbTX6ny4zQACggAkADIRhgLaXEAYAvzsqoJ/WKz2UVYDvv1d1nvvdPtg7HlK/nvx0skFcZz988nJTPl8+pzYAAfL494ekP9+7ePPwhrR7nGG33cIAwOAQAAB/hAFUQGEACI260RMVoG7uDacCqqFd0tGuY8mm8P42P1Gr23UsxQm8vToesik+uu+gDNltHIqLeD5CxcDbybNlGyAA0DhAAACx/TBAGKAZWq1SblTAToh958+gCqjm0JGRR/vtFOt/+eMrzdmR3002QdWmqM6XbA6qaxg6pzAAsMhkAGDfVxhA3baqW0teiavAMICVdrnAowLapXI71/7/PVlWAYRYGgDtFlLs33MG33lcc/r8Czry7pbG4vfeLP976Nd/f/9RtTm8f/Jy3M93FeNxAZcvRRqpToLWIwCwzZ8AAGyAMIAyThjAdDZRTlSAhq4nrwJ8Qd0rqOos19ke+ycbgFKwiKEoDkAArQauqD+yEd66sC1L4HUSx85toRpvfZTllwMAdQtp8yoAsOreMIB+j2EAyyeIClAbYddVAEUC3a+lAVPKFe0FkJFJOpre9/aqjUN1BQRwlyfFIXoTStAGCABU51NgJgAAqzUM0K5GDgPAXgBReFQASUjbUQVQHIBy2n75QWPpdz3Yrr3z36P+fcGvnN6vsX+r968mlJCN4/15PoIHet74VjOEqI7A+x+6riAAgKTSAKAzPyAMoJVOYYCoAPmkZqcCXGdR7J6+CHKrKJJW1cHvPaM2BMUFqqFgT2gZ+gykmgm4g4SQqhEYALQPngwALPQbBhj2FLQwgFn1UQFtSJTdwN4zdnw41SRP8otpv59KuShSSTq/mlZOgSs6h3D0vQAXeADQPgImAIBTtsIAqvPDAMVSr6gAlcCuqwBfEKqHryKeaulcJ5MVXN2Pr9bz0+9T3MJj/VRH0Ht+QLcRGAAopQcAcCJGGEADRWQ0hgHsAAoCEH2BUQGd+QAUGiYBU5o05QN4O/n91dA06ehnf7rUxBjdZ0BxBKo+3vV8gAAgABAMVG/gCAPUzhImRl27GxgGWDgDUJp47xdOVq9/Ea6T6fx/6p9qC8lqp7iFf0BUB0FG79rjAAFA7WBKOmw6AIBDmuj08DCA3mxKbrC3lyOBYYCFMwAdFUsZPpRzR1av62Dyy3v3Jqrj8Vo+9/sf+1DvRSSbheIca/cCAgCtFaRSrgDAzgcIA4QBmnZKlXKjAs6W7bjrF6D8Ml0b15tzVy2/9roD8rOpTqF6HkD1bGK3AXq30+muZPIKAgBLUw8AADJhgPMioTCAASYqoH249A2vAujWMDfiKJLnfvOTn/3Rtd9O73veP+3/05lHtP9PoV46/6A31j+4DRAA1Eq5AgC4CTQM0C4mDQMYhxHlRgUQ6XfmBFIomHQa3bFDsXQ6E8gDQ5vX/pIZn3nlQFNCHtr1h2l8ZFPQ4dCTuzHEBRAA6KFXlOTZm4Dimz1rvzQqAFAJhAFO6J01tF1Jac5Vio0KWPOdQTWTYrWqJoyQzUA5cfS+j58ARLd8VX+PrqBxFVINRY9+Z1AAoH5/AACICAOogMIAlvRZtRmiAg4JovxcwcmrgN48+6Hz8Enn+lnD7rc7AbpKePXTjeaCeUYUycfvSdz1O4PIJqA7hTzQQQtM7dVCjACgMxIYAKgEwgCGiDDAwlWAM0QVEE7pVGdQzcghN47aKY5ASaq+meXy8vlPbjeQVEAAUKseDgDgipgwQF/tH32w5axg6jAMsHAGoEggbW86gMgPpgQRukPIk1h7a/Wo7oByJsfW+S7fwRkgANArYuhybA80BQAG0TBAVenWng8DnLwsEosKqAFo7U9TWjr58d5OhSzHzm3JR+IqjvYGaPOrt76/dwEGZ4DeAdH7AQBJqNYeAJgKcPGFAWqAGv3pMMCwIp48A1AaNKWpu7iGdrPo94f+vWGX/3/cGzj0AKi/AIAk1NceBuiT3yoM0ClAej0MQBLqa588A/RNL2+TBAIAktDM2wOAmS8wTS8AIAnNvD0AmPkC0/QCAJLQzNsDgJkvME0vACAJzbw9AJj5AtP0AgCS0MzbA4CZLzBNLwAgCc28/V/fzAVEqDvghQAAAABJRU5ErkJgggAA",vn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABHpJREFUeF7tnVty2zAMRZUtpPtfYr2FdtrxJJZimwTxIAie/BokgXsPIMlOnI+Dn60V+Ni6eoo/AGBzCAAAADZXYPPymQAAsLkCm5fPBACAzRXYvHwmAABsrsDm5TMBAKC8An+cK1y6iZZOvtNYAHgjFAB0UlRVQwAAAL0CwTt4j3TrclI3WerkXjgBAIaIAoChmC+2Sq1x6uSYAHvSKRrxvz4/36r0+3bzV1F2QqqmS5XMXUcAkAGligYAlXxDi1NpnioZJsAQUKpFGQB4O/JnX+Mdzs+g+Rc0GZIBAFUP6xYDQEM/JoAOsJ7VTIAelZxiZkwAkeEJn+NPVlwnxEC+MzyYeg8AAOduBoBHPQw6ymlYPt/WIF8AAIBQZk+HRdBXauS3rFptIgBAy1Hh6wDwUzAmgAyiiKYMfQoAAAD4VsBgRMrknBxtUK/rRHDd/NmnewaCTLZUdrxBva4euW4OAMcBAMdxugcwEETWgpOjDep1bVKPzbe66ZPylQ0IAJA6qIwHgMtv8Q58eqa0YO5yAACAE4EDDWA6tU03465fPl1mTwQAkHtmugIATOVcbzMAWM8z04wBwFTO9TYzAOBatOiyLgrulHfrd/46NfoKAwCpYsXiAaCYodJyygMgFYR4tQKiy7oouDM10d/3d+5JWL8CIk9FwZ05AECnUE5hIk9FwZ0JA0CnUE5hIk9FwS8SxnAnJwe3FXkqCgaAQUtil4k8FQUDQKyTg6eJPBUFA8CgJbHLRJ6KggEg1snB00SeioIBYNCS2GUiT0XBABDr5OBpIk9FwQAwaEnsMpGnomAAiHXy32kDHxaJPBUFAwAAPFOAdwIduWACOIq7wtYZAaDjA8kBgECxMx4FABldCcwJAALFznjUcgAMJJxR9zQ5DegperQXBd9V4QsgAvEAgECxMx4FABldCcwJAALFzngUAGR0JTAnAAgUO+NRAJDRlcCcMgJwLZ/HQkcgAMBR3BW2BoAVXHLMEQAcxV1h6xUA4J7AkCRvw6+pjnwW0CqXm8KWQm9eBwCFeBWWAkAFFxU1VACAewIAOCnAPYEACCbA7SaQq14oAADAieqO/yegepJTLR7sP75K9kG46I6PeB+gxQUAAMC3AgMd0AJsqdcH6jed2qabdSrPBGACvEZloCM6ucsRZlCfadOabtYp8dbvCwDA5V/JXqExEKiTwzlhBvWZNq3pZp2SMgEehOp4znd9cpsBQOnPCq4dfi12tuGuNHVOAACQCeXapK6bd9ZZ6pLABOh0/SEMAN5r5tqkrpvLWfi/YioQrQ5u1TRwjZ96WQaAi/wA0ELc/3UmgL/GXycwAZgAgbiNHbX69xJmbLLUE0D0PsEYU6GrAEApNxNAKeC75anpvCcOAJsD0CrfG5AVmqSl0cvXKxQHAMP2HwcAtMWroBEToO1zaY32LE5h+jZLS4+3bVxUFAoACvEqLAWACi4qagAAhXgVlgJABRcVNQCAQrwKSwGggouKGgBAIV6FpQBQwUVFDQCgEK/CUgCo4KKihr/+fgyfHzM2+gAAAABJRU5ErkJgggAA",In="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABjFJREFUeF7tnU2LXUUQhm+UqMMkjAZlnCwEEYIQ/FgYCEHBjSKIG/duBH+Dv8HfIIjg3ixUEN0YlCCYhQgBCYrgwnFAoiEZRg1+4M6qGbry3qo+03fOk92kP6q76q236nT1OffYgn+z1sCxWe+ezS8AwMxBAAAAwMw1MPPtwwAAYOYamPn2YQAAcLQ08NL5E//03NHHX96SnOb1V8+Y9dy+/Ze0vOPH7zb933n/miQ/ElY6WSRsinYAoGkZAGj6WsAAosKm7g4DaBpfOQaIDLy797emAbH3+tpdzRGeIV575TGTAzz4wH2SxF9+/d30f++D70ttVjqZtLMlOwMAANDM8mEAzbNgAE1fC0KAqLBsd0/5qofv/ZE7Fli7V/MRDxCfE7z5hj0XWF8/YVS0u3vL/P3W27XP/d4e2u6y1lxiPAAAAMaFYYAlvKgxBAYI9EkIqAVcOFs15Z96+P5QZqvD9Z9/M81ZQDz1xGkzHzmA0z4AmHkSCAAAQGnSRwhoR8BDTwJ7e/yzT2+lcoAvvt4246tzggvnz8z7HAAAAICulA8DEAIIASMdBI1O+RFaeucE/pzgyNUCAICFmC8eAYDABX11zz/mZWM+DBBpINkOA8yMAXob/Owjp5KQzA2/+uP1rucE6i1kdTfdD4IAgKbi6EKJauCov7a6aLYD2gGApmIA4EAUJX2EgCW88n9DNHjegazeHn8HSxiqS3XtoDonAACd4QIAxDd1IsrvbK/y6QEAADCgyl4pGy4E9I752ZO9hzZOGgNcvHSt6eW95Y3GCOkcAABYPEWAAwDiY15vj/R00FseAAAAQ+UEcgjoTfnVHunr9z/t3GjmAKc3N0x7lhG8fC/8sBkBADiLAIDgSRgG0I4KYAAx5hMCNFLOFo9Cab093hdzfH1dLfb48T7mv3DuUYOxT7/6QcoJsuuJ9jt1TgAAAEA7psEA9qkABig+248oMatwQkD707b7QkBvj9dy6Hzv6Lk/ygn8Y2F+RdoMvXMCABAkhQCgmPI1/Od7wwD2y6a+nAwDwADWy9QcILrBE52lR+XTaHzEEVPXAqr3k30XMTooSjMAANDuA6iABgDFX/iIcoJsMQgGcJ9lixBfrTAfEggBYhLoFfjM42vNj+1Wv53rDRYBKMoBIkBUF58iedn9RCHBy7/y7V7zuD+sBQAAFWK2fzWgAUDOHouoPp/1UBigOGnrbRBCQNKjXnx+y+QIavHGi8/eB0hup3x49X78fJ98th2G8damUoP/mxgAtDEDAESfqlaYKL68e/V+YIByE/WdcHYA6KvO/bPfuNn+Hb/e69k42fd3CqP1D5cDRAuubgcAgyWB1QaO5gMAACDCSNd2QoA7B1APbtRikO//7offGQNfOJv7jaAILZev2t8Qevm5TTNE3U8kL5pvuBwAALQ/SFGtHwAAA6QO81KDDzoJrEa4n48QYD9xs/IMkK2effT5zlA5QHY/UU7gq5kAAACkWDw1uCIEZD0GBhjsHEDNAQBARPq2ffgQMPV9AP9cPvU5QCRvdsUgAGA9FgBoDLdQFQYDDJYDwAAzZwDR4dPdfTVwa9MexaYFuAm2d26a/6EY5IpB1QqP5gMAg4WAyGDV7QAAABhMEQI0Fzv0k8Co3k0xqF1eXvlaAABoe2ykHwDAfYAUi6cGVxSDIoQTAo54CKAYpCVtwxeDqAa2q3fV+ln5HAAGgAGMBtQvanAhZLCDoNGKQZe/+dPeGXzyHs3lXG+1+qhWN6PF8XawaBAA0IZU+WMgDDDzcjAAmDkAohhW3U41cLAksNrA0XwAAABQDo68pNFengQm1rLUUBhgMAZQjzopBlEONhq4eMm+/Uo18IhXA2EAGAAGaGAgchCqgbwenkrkU4MrbgRRDtYefrgQ4vRFOXjFHwNhgCPGAKMVgzT1xr25D+B0dNi/F6AaJDZxu4cqjwshosZVhakGEZezr7sqT91PtD5uBDkNqQaJFBy1q/JmB4BIgdXtfC18sKeAagNH8wEAABBhpGs7XwgZ7AshXa19wOSzB8DUCkderQbStYDa5TDb1BoAAFNrfDB5AGAwg0y9HAAwtcYHkwcABjPI1MsBAFNrfDB5AGAwg0y9nH8BQiiE6tlyKbkAAAAASUVORK5CYIIA",Pn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAACURJREFUeF7tXd9rHUUUvm1Kk5g2pqFpLaVRK4RKBRUk1GjRB0FRX/sg+AcI+ig+ivgoPir4Bwg+9FVFwYdKNZYgqGCxBKzaUmqbksa0MUlposzuPTune8/cM7M/7u69++WpvTtzdubMN985c+bM7I4W/hqtgR2N7j063wIAGg4CAAAAaLgGGt79RjHASyf2/Ocz3l+du90YvTSmo2bgAYBO+AMAAiWAAXx4ssZlXDN9bX3bq9VjozvFcoMIjIFkAADAC+dRIQBA0BUYwB9AlZeUZrsv1Yc2XgJGv5uFvmcAACAUxveW7ysA5B3s9U2vMEBrdNhfLf3OCv49zQe0QmoDAIWo8R4hAICgUzBA8UALkph3Geei+pOzR73acXbholjOFxj9tIqoJQMAAF44LaQQACCoEQxQCLb8hJTh2Lmoft/ksFejbi5viuUkYPiaBSOwjiuGyhkAAKh267mnAOjVYPOZ7prNXlTQarU0Wf3OCgCAggQAwHeqeJQDA3QqqWq/oBQGKGsZN/nARKTB49OTiSYlx47T/m+Lf3lA013k0ZkHvd91/tJyVHb575W+iSMAAAo8AIAM8wcM0CAG6JVdNzgkin32iUMiLIn6Oe2//tZ7GSBsq3z6ka1PbOCKJ3z389UOE8VfXscVQ24TAADYIR54APRqsLUZxhlAcvj4rB8ftw4jDdX777yZjNq7H3zclSFWV2PHzvwRG7j8AgKAxlB1YoUgBgAAYnMAADAIh+TfSdu0UtweDOA/L/PGEcQ3leXFhwy2xMuSjZUcPon2jTz6/e03XkvEf/jJZx2v4rTPH9LvkmPo46RKfZJC1b3cjQQAAIBOXIIBrOPXeAbQbLyvXc+1GG9XpjgADwVrJkAyB5oJkAbd/OZrAnj7iug3ycgSR+A+gnSGQTUBAIBlg8YAgKP2qWOjXZPpaYOmSKSHyNq5cSspTut/PuvLZoDtkb0hzS28rGvjiV7044X1rksKdb0BAHRnAACgvUVbOLQ9BYIB5I2nwhhAGodnZqcSszB77EBSZG39rtewjY3uSsqRY2d+IOfJV46pc+nylWATwBvJHUKp8TxULPkA00cOe/XZFKJ+S302z337zfW3cOF68v7vF5ZURk83NriCEQAA2B1CAAAMAAZIa8BFZZy6qI6LDum5JIvLyRIH8B4xtvY3dbRloNbWPH3mJoS3v1YmoNuguToAAHRuV4dMoMoB8OLckQSQvjn4fLePNniMENpH95Vj6mgMwGeLa5MozQhZN4M0ZqF+S302dX37zfX39fzlap1AAMBmDQMAjjN1acWAAeLcQc56A8EAiQ/wrxwPGLvPrv+prIsOu8mS5Jjy8+cWo2paSpg2U/lzKSVs7sSMKGJN6HdRfY58KEF/tTIBAEAn8AEANleKUgYYwCq1VgxAFPjDgrVxnCufno3z+fkASiaAU6kki+S4ZEn7AyG0z8vy9C/a+OFZv1naqpm9b85Yz17THwDA7CIpFgDwh3vuvQA+G2i23rizR2zB/t23o9/5DP5pcSkp++TMVPRvPuslWSTHJeuhqfFEJt8s8leLLclj/X8urUYPqJ1Z2yr1mcsK0R9nk0o2gwAAa+58wQoAtH0Bg3owQMx6YABGrUWagCy076oDE9DWDM8HqLsJAAC6a2DgnUAAoOEAkHIQQkDBt2ZhAvrQBAAADWeAl0/Zg6Dffn460sZzr54StSI9//K0PTwKBuhDBgAAwACJBsAAnWAY+FUAZwDqPgEhrQ7JNMAECAzST3EAAAAmoEMDYACrkoE3AXwZ6PL+0wjhAEEcoM9NAADQcBMgBYK0OABXGRhggBiAugIANNQHAAAaGAeQfABtFQAnUNku66c4AAAAJzDRANl+MEDJPoC23x6SFZxFFs8KllYBIcevQ1YBvm3VkkJ95ZhytcwKDumAlhSaRRYAoGmtQAbgx8Olw5FSU0JOBmldkWS5AECz+ZeL8fmE9N/jR+PzDJw1JAZwnQzybavrZFAW/dXyZJCvItIURor1VUQ0WMLJIABAGwEwABigrYHcm0FV3xAiXTbBGYCPtIv6XaYg/TulhLk+WaPNO1wR09ZQkTeEAAANvyMIAKgYAPyqWKLAkHV23mviOO2SLG4CJNo/dFC+4fvqNXvzOMmllYH5P5kA1/cAcE9gW2sAgIVlUZdjppen9IbK7wms+rJo6eLpf27tFP0xmvkHxuRPIFxfi31iiQnM7/fv3Y6ecwbwveCZDyAuiy7wtnAAoOG3hQMAPQQAbQO7bunS1sFlP5eonzt8LupPt4tMgcsckCkouz+h8imCGnJVTFAgCACIhwQAEG6sDEVrGeXBAPFFlYUyAM/+IerPulnjW4+bGK3O3a3dHVhy0b7vUXHu2WvmYNfQna5YDukLCcpSJ1pltCcm15kGBtUEAABWRdLysJEA0L6Myde5HI1S1FCK5IXUmT9vv5olrfN9Z71rGktswIEwd3yiKwPwQA3NUE1/Up10/EF6Kem9dAbQOgAA2OEBANgV6mCA+Lp8bQLVngH4fji/2PiF5+PPx/CUJ05HlDsg1eH1pDrmOdWj95jfvjh7LZluZAIe3j+U/Hbl5kiuBcfhfRtJ/T9ubEX/5ibglZMHk+dS+3jKFpkATX9SHfMSqheiv1KcQK0DAID9jhIAwEwAGCA2AdoEqj0DbKzYL2PwC5LpFu+RCftpGE7ntGSW6hjFUD2pjnlO9fht4ZtDNg6gmYBff7cfgu5mFx57xH7KTTMBw1s2DiC1j4cpyARo+pPqmPZSvRD9lWICtA4AADbtHABgJgAMEDOjNoHAAAJoYAJgAuADtH0v+ADtT88YVoATaP0NyYmGE8gCQVgFdK59Mu0Gak4MVgFYBSRQQxzAzjrEAdoxkxAnhudbIBAUB+BC9NdIH4Anf65s2G8YZvEBJkYsnUvnBhAJZB+JrEsoGACwoXowABigq6M/kKsAMAAYIHG94QMsgQEIDXACCwoEaQkNVWcE9dIEICXsjL2hoi45gQBAyT6AltVadVp4rixQj8o4FzBtU6YkfQEAVis4F1DBuQCPSZyrSGMZIJfWSqosHQ4t6VWiWO1sYC/bIr2r0Ehg1Z2R3g8AdB8VAKBk1A48A5SsP4ivWAPqXkDF7cPrS9YAAFCygusuHgCo+wiV3D4AoGQF1138/6AOznGr4VpfAAAAAElFTkSuQmCC",bn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABhxJREFUeF7tnU9vFlUUxgewWqDI25KQl5RQ/lTCG8EUIYALjcaNa3d+Erbd8kn4CJoQEiIBLEEoAimJQAtB7KLWitA2FNCw6zkvuU9Ozp3pzJyHXbl/5p5zf/c5Z+69nW4q+C+0BzaFtp7GFwQgOAQEgAAE90Bw86kABCC4B4KbTwUgAME9ENx8KgABCO6B4OZTAQhAcA8EN58KQACCeyC4+VQAAuDzwFcnuv/5eojV+udf52u16NyDIQA2gAmAzV+tq00AWjelNoMaBwCS+Jcrr20eCF57+9YPkh6oGhCYAxCAvMQSgLz+bFxvBKBxU5Z3wLUHQEu+N8Z72+d1f/m9oQlGI0Dtc+cIfTkAAUBTlC5HE4h6R+0JAPLgBpejCUTDQ+0JAPLgBpejCUTDQ+1rBwCK8d29h5HNtS6/dPk6fFVeb8CRA53k2QiaYOQM1N4KiDsHIAByygiAQpgKIB2CVjAVAHmg4vJwIUD7F0la7+iJ5JR0dg5VPGW+x+3p7hYdXJ26LX62AmH1Z26FQDkBTHAIAAFIZrVUAJvioAVFBbD5M3tthgDg0q+/PCUUYbizQ7TIHfOnb94Q/U98fjI5Qmt9RFBuID7r7U0q6qvVF8khIYXQ5e4cQI+GAPhyAgKAlpwqt65oa300HCqA8hAVgAqQzAHQirKWzz28L5rsP3Qk2YW1vnU8uv7fS/+a9glQCPht5mny1Ry9RdyfXYKv9usHbKr8riFSAK9DdXvrhFrre8dLANRbgNehBIAKIBiwrmhrfS+w4RXA60Dd/u3y49xdiv42bxsrtX90VuDNAb77Yjy5j/DTtQemsG6q/L4cILc3CUA6BBAAJ3FUAOlAKoATKN08XAg4MLYnqwsfzvwi+jt29NNk/3fu3kvW1+WHemdc4/XuDHpzgO+/6YkcYHl1TdhTeQ5AAGw7gwQArD8qQDoJpAIogBgCWh4CXAH7PY29OYDucvbxn5WeBYRTAAIgPUAAnERQATLvA5T9FuCc777mBCAzAPpOYO4Jq3t/VR8G1S4EEIBqL4QQgJpJAhWg5AshNZvvvuGEB8A7Qf88T9+D9/aP2u/8OO/vLpZ9GFS7EIAcjMoJgPQQuhRKABBRxnIqgNFh+lawsXlfdSpAwxXAuhGkz9N/vHBFeGD/vrz3CzRxc0/k3v3EsU9MDFvvA+jj362DHyaft7L6SpTrkFC7EEAA0vcBCIDinQpABRBIMATIFdL6EKAD4PSd3xuVA+jxo/sADAEgxSIAVAAqwDoPMATU/DWQIQB8I8j0Ul0UhX4vr3ofwPs8dBh0+vhBcY/fug8wdeuR+OWd2u0DeO8DEIB0DkAArJIC6ucGjgrgvA+Qe0IQL7mfFx4A5HBUrg+DBga2oCau8rW1N6J92aeBrc8BXLNRFAUBaHgOQACkB/SNICoAIIQK0HAF4HGwPA5eXHgmZlS/91v3AfTO4HhXfpu5cd8HaPtxMAEAkk8AbPcBqADeLFO1L/tKGBXAOGFtOw5eebGQzAFGuyNJD/0xvyjKtQKMdj4S5Y3LAbT1BEB6hAA0/DiYCsAQECsElH0c/ODRE+HQ8YP7jIjJ6mUfBhWvn4sH6ph/dru0p5iQ4zt3RdqnQ8LIoPy254bnAARAfh+AABjXJ1qRVAD5VkAFYAio12ugccH3VW/bYdDI0Fth4+SueWmzivlFT7lkRv48ebEr/2P1JQHwQFf2hRACYJwdKgAVQHig6VfCwikA7wPI+wAQgB+ARJ5XOcBfNc8BCAABMEX9tt8HoAIAHAhA8BDQ9uNgvRU80pHfIZz8Vu0LTKdj/uKS/I5i7XYCrTkAASAAgoG2XQihAphSwqIgAA0PAWUfBxt5gtXR6SPsQFXQvxyKbgTpnEA/T8d8fSdweHBzcoiV/91AAiDvAxAA4xLKvSLR43M/jwrA7wMI5sIpAFpxqLxtH4tG9pZdjv5egX7+hv/1cAKQFwkCYPRn7i+EGB+fvToBMLqUABgdxurt8oA5B2iX+bSGAARngAAQgOAeCG4+FYAABPdAcPOpAAQguAeCm08FIADBPRDcfCoAAQjugeDmUwEIQHAPBDefChAcgP8BwpNE6iNz+YQAAAAASUVORK5CYIIA",yn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAB39JREFUeF7tnS2SFUEQhN+7AHIjwGM4A1fAwQkwaBQKgUKtxnACcGuRcAUiiPVsBJILgKVygvk2o7rnzdvNlds9/ZOdlVVd3TPveDjzv7evX/z5dwqPLh6szujVm4/HmVPW8VBf7y4/TR0P9X/SzmlwtykPAW6D0v/rhAA9/BZPRwEGA0rNRQEIofXyhQIQg0/ts2h8FAMoHD9//S7/ovk9f/a0xBxPHj8sz1P/2p+O5/v1TfnX56uvU1U6BAgBKgfJwshCeoLET9P4yAKjABWBKEAUYF0B1KJcn8k27dUYrQCuImgMoM9rTKA+nWY72+dr/6gAIUBN1IQApmQS493yKICLWHMbGAW44wpAiRTat87eFdC+27UHIrS2R/Mjl+D6dFI4Go+LxzEEqImgEEBO06IA66d1UYDJx5lxAVWTTu4CKFc92oeNJoDrI0cDTv0TfvS8O147BggBaAl65SGA4BcF8AgVBfDwwtouoNggVNhcAcjCKJet+9zRE6AoW3Pv7gKQS3Pbc+sTXnS62T2bOYYA217AUIKEAIKISm4UYP2WcxRArmS5EhwXIHfcCEDX54/2YaQINH4q1/l9eP+y3AF03ysgiafxaDmdZbhB6yIGoAGFAN6LJSEAvKnj+rAoQI0JXPzUwKMAgsi9cwEk+XuTsK4C6ALTNph2JW57hDeVUwzgHmfjSwchwPqNoBCAKCvlxGCKYqMA6zFAFAAI6VrsvXMB5BNNg29XJ0XodkCKQnf6ulfquuOn5wm/RQwQAlRIQ4BmqpUYSuXEYHqeyqMAglAUIApQct9qQd3zdzdKJQvWcrJoHT8pDBmEe9ZB9yvoewOjb2ljDBACjP0gRAggjCILjAKM3fcvzgK6EuouUFxAvYFECkuJsy6emAomn+oSgLZVbnvko932KPFDC6blXcnX9rqnf6gAriK4AIcAFTEK+kIAYFgUoPel0bgACErJBdK2+OxdgCvxbn06bqZdAimAu0+noIoIoc/T4VM3pui6VFQAd0Hd+iHAekxAQWUIMPnLne6uIApgSkAUYGcKQD7OzaXTtpK2QbTvpRhA+3djAopBTL4vqhPepCjd/ttnAS5AtGCU+SJJpqg8BKiUCQHEhEhxuhZHikjtd4M+zASSJMUF0BJ55YT3dBdAkuxN53Agl9Dtb2sX4OYFugbi4t2tj98HcDsIAeoPSBAeLr6j64cAEANEAUzKEePjAkxAJ1dHBXC3Ta7F0Pwo6nUJNXs+tA0lAyE8RpeHAJNdABnE6AV12wsBQoCxt16J8aP3vXEBrs1LJnA2gLN93uzx00ekRhO6t5z+0+gCtEk3iAoBKoIU1PpL2HsiBIAYIAogAEUB6k+5xgU0o2gSML0wQi7FjQmof1IAfZ6+F6D13e8O0ni1XPFQFzTdBdCugCYUAhBC6+UhQPP7BlGAZgwQBVj/2PO9dwHks90rYuQDXUGlbRtdanW30V1C0HhU0U4eA4QAlSIhgPjsKICnWVEAwcvdpyvccQFmEKgA0i3b2S7Asx+/NlmcGwOMxkv7//LtR/nX8BggBFgnUTeT6hpMCOAbtfVEFADgGi1p1J61egMqnz0B3H0zvcvnugDqf/QdO1owOmvojpdiAiL4cBdAE9LyEKAiQgtCIuNuc6k/ijEWQWAIUBGIAsDPyEUB7rgCdBVBn3dP09z+KVHjSib5YBofxSyzYwBqH10ATZBighCgvhu4dQwQAggCUYB6HB0FmHzYdOdcgOsStD75aJLIbjkpALVPuwI6bHIJoePpfg+BXLL9nUCacAhQEQgBruo1arK40eVRgIro4kaQC3gUYD0P4O6SCP/duQAa8Ohyyt27PpPG141ZXANxXWa3fe3PjgEIwNHlIYCnOC7+IYAgFgVwKTS5fhRg5wpAPsn9bp674O5x6mS+bt484U+K1nYBNIAQYC4nCP8Q4LL3mzpzl6/feghwsf7DipTK7S/BaVvYnADdzJq7b3dTqW5MQPM5NYEoJuqOz44BCDDXHkZnukIAbwVCAPjNoa6FecuxrB0FMD/wEAXwKDdcAehast650+HqadWpYwAiVPfOIy0XKQDhTa+bhwDmz84pgUMAuGKlDI8CkM3X8ijAiWOAuAAhrLsNJB9Fkqr24sYE3bzD1gQgiyf90PFuHgPoAEMAWjJP8qm1EAAQchNPUYC4gIIAuSw6fSML3p0LcAdEkt/dFRCAWk4L0o1p9E0b6s/F053vcBfgDjgEWL8G7+IZAlzfuBiU+mSRUQCA12VsFODMFKBrAS3zPBwOlBmcfRrnzp/OLlRxuu27+JIBal5g+ncCaQIhACHklYcAHl6HroXSYVC3fXM6hxDARKy7QHeOAKNz78TI2YkV4gNdqqTnKe9A7XfPNtzxaUy1iAFCABfSWp+CwNH4uqMNASC17QIaBQDE4gLqbzPvTgF0QOSzyEK6Po2CKuq/W07zp8wi9U/t0/MugSiPsrgT2B1gCLC+hF18QwDXRMz6tEBRAAA0CnDmCmAazKI6WRC137Uwaj/lFQH7vQACMAQghPZVHgLsaz02H00IsDnk++rwL9AvSbcAuaMiAAAAAElFTkSuQmCC",Mn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABW9JREFUeF7tnM1qFUEQhW/8wYgR/wJuxJW4dSn4FiL4AuLSpU/iUnwBQXwLIUu34kZxI8Q/jJigRrfpY5hD0dNze6a+7G76Z7pOnT5VXT33bqz4S43ARmrrMX4FAZKTAAJAgOQIJDcfBYAAyRFIbj4KAAGSI5DcfBQAAiRHILn5KAAESI6AmP/51urv0X9dfr3saikKAAFQgKMIoADJ+QABkhMgav7cCUMOEPX4wnIGCAABKhFIPpwQkIwAc3e4uosQECQwBAgCtrTuEGBpHg3aAwGCgPXe3TlU29Weud8VpM8BIEDvW7Tx+iBAY4B7nx4C9O6hxutzMd49nhzAIdR5OwTo3EGtlwcBWiPc+fwQoHMHRZfnkjqdzxHg5+2tYsjZnb3BJc0tJ1hcHQACxLYMBJC3gBU+FCBGqLX3RgFiLkinANGYr3BqDjC3mK/2QABBRCUfAsQUZe29XQhAAUoXoQAowNo3bdUC3I52kzvJJwQ4BNfcDgHqHDD7EAABIEDxde4oHISAKGKd9Y8qQNTh5ACdOTx6meNKu1HzKARFEWvcHwWoAzhdEkgImHkhaN07Xvebuwtwlcm6/Vs/enYKAAHqnX50Bghg8Kx9AwgFGJewKxRgXEC7UwC3YxwBokne4f0S0BPPhwF2x0C3PpczjOtePxsEgACeJVP2QAGmRHvV38+gQgAIELrcqY35Cnc0B4i6ixzAIOaSqNraviZ9ECBK4cb9IUBjgGX67k8BDg5CgENouH3xBHCSHw0B2t9VCqN3B3XujI+GAIKZSwIhQJxkoRFj5wAoACEgREAUIARX+86qCLVJ3+GlB8WiT3x5NmiEI4TLAXo796ux3eUAukAI0HaTQQAUoC3DamdHAWoRnFkSWBsCNOvXmO/g1JyAHMAh1rg9qgAQIOaQxeUAEAACFAgQAmaWA9y7vVW8D/B0v/xdPlcHiCrA2HWAh5vl7wq+2NkrVNa98BLbv/W9uwsBEKDeqZEZIMDIdQAUIEK/Y/qiAJUABodPrgDqYF2vxnxtdzmA9p/6NvDRhSvFEvYPDorPzj6nIEH/2u4QQCByhR9FVC+DIIDhHAow/GvjKIAc+wgB5THSanqwQ/MQoDt+88yZYolPvn0KLnm4ezRHcA939/06/u6vc8W/rm1vukcU7dcv/i4+v/n4p/isdYXQ5Md0hgAGQQhQSTEUAAUoSruEgOEdNfsQoDv+5tWTgxa//3qqaP+wuz8YQ8fOGSoFzg7XnEAH3LlR2q/ts8sBIEDpQgiAAgyqBApACBgkyOJCwNgxX0uvrXMElfSXp38UDtT1aFLn7N8+X57Mxz73K9tGrwO4HMABoIUT51AIYPPQwQ4QIIgfCmAAQwHK6+B0IUD5oYTY/V7+BJBKvgKm82kI0fZoHcHtaJ1fQ44+z2X1U5/zncCNHgIgwHBhBwKgAJPe9qEAch2rpwpCgKPIyO0uSYw+7tXb8v5cY/Djd98Gz+kuZ4jmJC4naF3YieLXPAdwOYG7LHIGQQCH0HA7BDC3jyhAHcH+G00IaPuKV9RdkytAbUjQOoDboQ4QF0LceHes0/bWtf3oeiGASSKjgGqSBwEqS8euEogCRCla9kcBUIA6Bo092n1zSJ9Xe4x0ku3m7+1cH/XH2hXAJYXOIOcgNx4COIQmbkcBpgUcBZCvXkVDDCFgWsJWF5aiDnOK1Nu5PuqO7hQgakC0sggBOjsGRh3ukkaXFEIACFAg4CScEFC7RScev3SHjQ3n7HMAFxJ6r8WP7dDofBAgitjC+kOAhTk0as7iCBAFIHt/CJCcARAAAiRHILn5KAAESI5AcvNRAAiQHIHk5qMAECA5AsnNRwEgQHIEkpv/Dw0ZdL1pN6qnAAAAAElFTkSuQmCC";function Yn(e){let A,t;return{c(){A=h("img"),k(A.src,t=SA)||f(A,"src",t),f(A,"alt","")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Hn(e){let A,t;return{c(){A=h("img"),k(A.src,t=SA)||f(A,"src",t),f(A,"alt","")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Fn(e){let A,t;return{c(){A=h("img"),k(A.src,t=Mn)||f(A,"src",t),f(A,"alt","")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Rn(e){let A,t;return{c(){A=h("img"),k(A.src,t=yn)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function kn(e){let A,t;return{c(){A=h("img"),k(A.src,t=bn)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Un(e){let A,t;return{c(){A=h("img"),k(A.src,t=In)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function On(e){let A,t;return{c(){A=h("img"),k(A.src,t=Pn)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Gn(e){let A,t;return{c(){A=h("img"),k(A.src,t=vn)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function jn(e){let A,t;return{c(){A=h("img"),k(A.src,t=En)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function zn(e){let A,t;return{c(){A=h("img"),k(A.src,t=pn)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Kn(e){let A,t;return{c(){A=h("img"),k(A.src,t=Dn)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Xn(e){let A,t;return{c(){A=h("img"),k(A.src,t=Qn)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Ln(e){let A,t;return{c(){A=h("img"),k(A.src,t=SA)||f(A,"src",t),f(A,"alt",""),f(A,"ondragstart","return false;")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Tn(e){let A;function t(i,r){return i[0]===L.Empty?Ln:i[0]===L.Water?Xn:i[0]===L.Rock?Kn:i[0]===L.Wood?zn:i[0]===L.Food?jn:i[0]===L.Oil?Gn:i[0]===L.TownHall?On:i[0]===L.Household?Un:i[0]===L.Smeltery?kn:i[0]===L.Road?Rn:i[0]===L.RaiderCamp?Fn:i[0]===L.RaiderBorder?Hn:Yn}let n=t(e),s=n(e);return{c(){s.c(),A=aA()},m(i,r){s.m(i,r),I(i,A,r)},p(i,[r]){n===(n=t(i))&&s?s.p(i,r):(s.d(1),s=n(i),s&&(s.c(),s.m(A.parentNode,A)))},i:p,o:p,d(i){s.d(i),i&&v(A)}}}function Sn(e,A,t){let{tile:n}=A;return e.$$set=s=>{"tile"in s&&t(0,n=s.tile)},[n]}class Nn extends _{constructor(A){super(),q(this,A,Sn,Tn,W,{tile:0})}}const Wn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAFxklEQVR4Ae1dTWsUQRDdlag5xGMk4iGg4J/L0aOEBII/wT8nKHgIRHNQ0IOShTXCsGw9O13d09Of9XLa2unuqnrv0VXTk0lWK/4QASJABIgAESACFhFYD5D0tnIOXWP4qDJ4dF8ZAQqgMgG13VMAtRmo7L/H+uWt+berw6yQHq9+a+t3hSl3AI3Owa9TAIMTrKVHAWgIDX79oIP8vDX/8uBIprDZSHthC/1dbn6hB2+894Ob6hG4AyB9xmwKwBjhmC4FgIgYs5uqRxP23hqa+z4/lf8PB/62ytEzVOWAO0Aq453PpwA6JzA1fAogFcHO51etPxN2Xdf8WP5be5bAHSCWwcHGUwCDERqbDgUQi9hg42v0AFVr/uPzd4LCu6v3wsbr4mKAgevhFDwncJwL4JSsHHEHQLiN2RSAMcIxXQoAETFmZ60vE5ZVa35uPrWeQesJML7S5wTcAZABYzYFYIxwTJcCQESM2Tl6gKFrfm59lD4n4A6Qm9HG16cAGicod3gUQG6EG19/iR6ANb8gyUufE3AHKEhei64ogBZZKRgTBVAQ7BZdzekBWPMrMhlwThDFKXeAimS24JoCaIGFijFQABXBb8F1VL2YAhY9QOl39QJqoBdXLd7c63uDm3Ex9VyAO8AM0EeaQgGMxOaMXCiAGaCNNCWkBxA1H5PXaiqOT7UDap7XhRZv7vW9wc24GNCzeDnmDjAD9JGmUAAjsTkjFwpgBmgjTfHWhylR0QNoNTQVHK2mbbcinGh367VMGf/u38Xdz+g19yfg+vvX/n3OjV9ADyMA4A6ADBmzKQBjhGO6FAAiYsx2/VG7tCLbGYD4fv5FZ/FjuNjTYH44njsAImLMpgCMEY7pUgCIiDFb3BNOuYseYOn71tz3+a3x1+C5gOCcO0BriikcDwVQGPDW3FEArTFSOB7XOUDhEOLcaTVVWy32WUKsv9j1tXhzX+cOkBvhxtenABonKHd4FEBuhBtfX9wTTrFmPQfQnldrNTS2Jmv4l/aH8Sx9zoLrO/AWnHMHQMSM2RSAMcIxXQoAETFmq+cAWENy16xU/EvX9NL+tGcpsfhxB4hFbLDxFMBghMamQwHEIjbYeHFP+EBu4lzggTG7r1N7BOw5dgsHfoitybHjMYzY+bH4LFDzvRxzB0BGjdkUgDHCMV0KABExZnvrwwNYRPUEuEZsDcT5qT0Crre0/fT4RCy5hXcRr799F9fRmFHz53C4c8sdYAeFzQ8UgE3ed1lTADsobH5Iqh+BkHl7htieILUH0Pylrv/j/ErAwv8bKOCg0RoCLAGtMVI4HgqgMOCtuQvpAbCGh8zZz1PMx/fXzzab/bHmPgf0HEl43wPqnc8dwJzkZMIUgMTDnEUBmKNcJuz6nUBRs+Xw5S08+7beEzgQRj68NT12PncAB2KWvqIALLHtyJUCcIBi6StXD6Dlr9UkcV2778ceQHM+2vUZzyYEvql4cAdIRbDz+RRA5wSmhk8BpCLY+XzXPaWoMVijtLPrZ6evBSSfv1wLm0YaAhr+AXwJzrkDpPHR/WwKoHsK0xKgANLw6362qAdTNt4eoLWM8Rwh97OE0v5S8Xb0DIJz7gCpCHc+nwLonMDU8CmAVAQ7n68+C8AagveZnedvPnzuAMYlQAFQAMYRMJ6+2gMgPlpPkPs+GdfH/4t3tjrEkLPaGh5ZnTsWx3gcQ8RXLAECDnsGBWCPc5ExBSDgsGe4egBxVnwPiXg2gBBhzblcHeGQJFur+bj4yRv5+wg3Hz/hkCg71v+r05di/bfXX4Ud+6wC/YvFXMb/r1oin2IWdwABhz2DArDHuciYAhBw2DO89SEQDm+P8OT5C7HMeiuH/7m9EdcDDC1m6SBgwcghRf3jexV47uGIXYtPTOEOIOCwZ1AA9jgXGVMAAg57RlS9mAlPak2OjTHVH6YZ6x/np8aT6h/jETZ3AAGHPYMCsMe5yJgCEHDYM/4C9gb53u1K2DsAAAAASUVORK5CYII=",xn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAFwklEQVR4Ae1du24UQRA8IwQklp3wTAgg5Gv4BBJCIogIHUECIX/ABxGSkFgghGSLBIvgMNLp5C6tp7end2Znpovo+nYe3VWl7t7ZPbzZ8B8RIAJEgAgQASIQEYGDAYLerhxD1xjeWBk8br8yAhTAygSsvT0FsDYDK+/fY/1K1vzfR8nLbrgPz1XI1AFuJxZcgBlgQTB7XIoC6JG1BX2mABYEs8elbnbgdLKov9q8rhoC7vdx8x73T/p7ObipHoEZAOkLZlMAwQjHcCkARCSY3VQ92mGfrKGl7/O9/L89fyOWmOgRxPVLY1UOmAGQjmA2BRCMcAyXAkBEgtmr1p8d1l3XfKteWnuWwAxgZXCw8RTAYIRaw6EArIgNNn6NZwFN1/w7n3wM/3mZnp/xLKFon8YMkOZr+KsUwPAUpwOkANL4DH+1aH3Zodd0zfcyrPUMWk+A+9c+J2AGQAaC2RRAMMIxXAoAEQlml+gBhq75pfVR+30CZoDSjDa+PgXQOEGl3aMASiPc+PpL9ACs+RVJXvqcgBmgInktbkUBtMhKRZ8ogIpgt7hVzvsArPkrMjnjfQKTd8wAJrjGG0wBjMepKSIKwATXeINzzgFED1D7t3oZZ+WCNc3f0usLZxYwvOcCzAALkNDzEhRAz+wt4DsFsACIPS8xpwcQNR+D1WoqjvfaM2pecgvN39LrJ53LuDijZ0lyzAyQAfpIUyiAkdjMiIUCyABtpCnJ+rALVPQAWg31gqPVtO1WuGPe7uBAhoxn6x+278xrXp2A61+99v9zafxm9DACAGYAZCiYTQEEIxzDpQAQkWD21PsAviLbGYD4//h92Ph6gLXDx54G40P/mAEQkWA2BRCMcAyXAkBEgtninnAXu+gBlr5vLX2f3xp/DZ4LCM6ZAVpTTGV/KIDKgLe2HQXQGiOV/Zk6B6jsgm07raZqq1mfJVj3s66v+Vv6OjNAaYQbX58CaJyg0u5RAKURbnx9cU+487XoOYD2vFqrodaarOFfez/0Z+lzFlx/Am/BOTMAIhbMpgCCEY7hUgCISDBbPQfAGlK6Znnxr13Ta++nPUux4scMYEVssPEUwGCEWsOhAKyIDTZe3BNeE5s4F7hmzP5rb4+APcd+4ZkfrDXZOh7dsM634rNAzU9yzAyAjAazKYBghGO4FAAiEsxO1odrsDD1BLiGtQbifG+PgOstbd+++0AsuYXfIv66OBXX0cio+Tkc7rdlBthDEfMDBRCT933UFMAeipgfXPVjJmTJnsHaE3h7AG0/7/p/P8twtb8bWLvmI2fMAIhIMJsCCEY4hksBICLB7Dk9gCxqm82cOVdhFPPx9+snR33/Hv9qoDmfZ/QcLrwvfUrOZwbIYW2gORTAQGTmhEIB5KA20JypdwJFzS4dK94HR+8JJvBGPpI13TqfGWACsUhfUQCR2J6IlQKYACXSV1M9gBa/VpPEde2+H3sAbfPRrmc8mxD4evFgBvAi2Pl8CqBzAr3uUwBeBDufP3VPKWoM1ijt7Prw8RMByenZV2HT8CGg4T+DL8E5M4CPj+5nUwDdU+gLgALw4df9bFEPdtEke4DWIsZzhNLPEmrv58V7omcQnDMDeBHufD4F0DmBXvcpAC+Cnc9XnwVgDcH7zM7jD+8+M0BwCVAAFEBwBIKHr/YAiI/WE5S+T8b18e/inVT+u38aHohfaRv90fZjCdAQGvw6BTA4wVp4FICG0ODXp3oAcVZ8Gb94NoB4YM3BdwBxvNXWaj6ud3z/mfjq7McXYVsN6/6Pjp+KLV58ey5s67MK3F8sNs9APsUsZgABRzyDAojHuYiYAhBwxDOS9WEmHMke4da9h2KZg60cfvHzu7g+w9B8lhvMWNA4pOr+2FPhuceE75p/YgozgIAjnkEBxONcREwBCDjiGaZ6kQmPtyZbffTuh2Fa98f5Xn+8+6M/wmYGEHDEMyiAeJyLiCkAAUc84x+0bw/TULWLkAAAAABJRU5ErkJggg==",Jn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAgKADAAQAAAABAAAAgAAAAABIjgR3AAAFxElEQVR4Ae1dvYoVTRDdq6KRoeJPYCArgi9hIAiCT2EmmO8jmAsbrU8hYmLqI4jCYmCigrGBuHBd8TLcOrfv1NTU9Ex31/miWzP9U3XOoaqmZ9bv4ID/EQEiQASIABEgAhERWDUQ9HrhGKrG8MLC4HH7hRGgABYmYOntKYClGVh4/xrrV2/Nf3qaF9E3h+r6VWHKDKDy2fYACqBtftXoKAAVorYHXKogvN6af/8ZhnCWNSTc7/Prnf16/T13rqgegRkgq1zKX5wCKJ+jrB5SAFnhLX/xourRBq7eGpr7Od9L2elL7EnkiomeYVEOmAEkP+EsCiAc5TJgCkDiEc5atP5s0K665lsVU9q7BGYAK4ONjacAGiPUGg4FYEWssfH9D615gl205j+/9UpEdfzthbDxvrg5wMD1cMqIdwlZ+zRmAGQomE0BBCMcw6UAEJFgdtb6ssFy0Zqfm0+tZ9B6AvRv7nMCZgBkIJhNAQQjHMOlABCRYHaOHqDpmp9bH/g9QeL7AXTBxSEzAMIZzKYAghGO4VIAiEgw21U/Nlix5s8omqnPCZgBZiSvxK0ogBJZmdEnCmBGsEvcasz3AKz5CzI54HsCk3fMACa42htMAbTHqSkiCsAEV3uDx5wDiB5g7r/VG3FWLljT/M29vnBmAsN7LsAMMAEJNS9BAdTM3gS+UwATgFjzEkPOAUTNXzrYAe/HXS7mXt/lXGKy91yAGSABaqRLFEAkthOxUgAJUCJdGnIOIHoA7TnaC572HL5eC3fM261WMmSsoZ9O/pjX3J6A62/f+/c7N37WcwFmAGQomE0BBCMcw6UAEJFgduocwFdkKwNw57n/pLIAwF3saXbig/HMAABINJMCiMY4xEsBACDRTPlQ/D960QNM/dya+zm/NAILPBcQnDMDlKaYmf2hAGYGvLTtKIDSGJnZn9Q5wMwu2LbTaqq2mvVdgnU/6/qav7nvMwPkRrjw9SmAwgnK7R4FkBvhwtefvQfQzqZz44U1feqajevnjse7PjOAF8HK51MAlRPodZ8C8CJY+Xy1B8BvzKZ+NzA1flpNn7pGz72f9i7FiiczgBWxxsZTAI0Rag2HArAi1th48W54T2zi+4A9Y7rL3h4Be45u4YE/rDXZOh7dsM634jNBze/lmBkAGQ1mUwDBCMdwKQBEJJjdWx/2YGHqCXANaw3E+d4eAdeb2r5y7YZYcg1/i/j4w3dxH40RNX8Mh922zAAdFDF/UAAxee+ipgA6KGL+cNWPgZD19gzWnsDbA2j7edd/96v//02sYTZg/0k5YwbQGGn8PgXQOMFaeBSAhlDj94fUE6zhQ+Zswybm49+vHx6dbY8N9ztDzRd4nwPayxczQDjJyYApAIlHOIsCCEe5DDj1TSDWEDljYgvPvqP3BAl4kY/emm6dzwyQQCzSJQogEtuJWCmABCiRLqV6AC1+rSaJ+9pzP/YA2uat3R/xbkLg68WDGcCLYOXzKYDKCfS6TwF4Eax8fuqZUtQYrFHa2fXVO3cFJA/ffxE2DR8CGv4D+BKcMwP4+Kh+NgVQPYW+ACgAH37Vzxb1YBNNbw9QWsR4jpD7XcLc+3nxTvQMgnNmAC/Clc+nACon0Os+BeBFsPL56rsArCH4nFl5/OHdZwYILgEKgAIIjkDw8NUeAPHReoLcz8m4Pv7bw4dH6HFeW8Mj7+67q6M/uyPkFZYAiUc4iwIIR7kMmAKQeISzxLnwnujFu4E9Y7rL2jeA3cCBP7Saj8tcvPdAXHry9qOwrYZ1f/we4vajr2JL67sK3F8sljCwJzof0ssxM0ACxEiXKIBIbCdipQASoES61FsfBgLR2yNcvn5TLLNay+G/f/4Q9wcYms9ygwELGofMuj/2VIkaj+5r/onxzAACjngGBRCPcxExBSDgiGeY6sVIeLw12eqjdz8M07o/zvf6490f/RE2M4CAI55BAcTjXERMAQg44hl/AV7j/OgJ907tAAAAAElFTkSuQmCC";function Vn(e){let A,t;return{c(){A=h("img"),k(A.src,t=Jn)||f(A,"src",t),f(A,"alt","")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function Zn(e){let A,t;return{c(){A=h("img"),k(A.src,t=xn)||f(A,"src",t),f(A,"alt","")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function qn(e){let A,t;return{c(){A=h("img"),k(A.src,t=Wn)||f(A,"src",t),f(A,"alt","")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function _n(e){let A,t;return{c(){A=h("img"),k(A.src,t="https://cdn.discordapp.com/emojis/843490991566880808.gif?size=128&quality=lossless")||f(A,"src",t),f(A,"alt","")},m(n,s){I(n,A,s)},p,d(n){n&&v(A)}}}function $n(e){let A;function t(i,r){if(i[0].opcode==="raider")return _n;if(i[0].opcode==="citizen")return qn;if(i[0].opcode==="bomber-bot")return Zn;if(i[0].opcode==="turret")return Vn}let n=t(e),s=n&&n(e);return{c(){s&&s.c(),A=aA()},m(i,r){s&&s.m(i,r),I(i,A,r)},p(i,[r]){n===(n=t(i))&&s?s.p(i,r):(s&&s.d(1),s=n&&n(i),s&&(s.c(),s.m(A.parentNode,A)))},i:p,o:p,d(i){s&&s.d(i),i&&v(A)}}}function As(e,A,t){let{unit:n}=A;return e.$$set=s=>{"unit"in s&&t(0,n=s.unit)},[n]}class es extends _{constructor(A){super(),q(this,A,As,$n,W,{unit:0})}}function Pe(e,A,t){const n=e.slice();return n[13]=A[t],n[15]=t,n}function be(e,A,t){const n=e.slice();return n[16]=A[t],n[18]=t,n}function ye(e){let A,t,n;return t=new es({props:{unit:e[7](e[3]+e[18],e[4]+e[0].map.viewY-e[15]-1)}}),{c(){A=h("div"),K(t.$$.fragment),f(A,"style",""),f(A,"class","svelte-4b2ujb")},m(s,i){I(s,A,i),G(t,A,null),n=!0},p(s,i){const r={};i&25&&(r.unit=s[7](s[3]+s[18],s[4]+s[0].map.viewY-s[15]-1)),t.$set(r)},i(s){n||(b(t.$$.fragment,s),n=!0)},o(s){H(t.$$.fragment,s),n=!1},d(s){s&&v(A),j(t)}}}function Me(e){let A,t,n,s=e[6](e[16],e[3]+e[18],e[4]+e[0].map.viewY-e[15]-1)&&e[2]==e[2],i,r;t=new Nn({props:{tile:e[16]}});let o=s&&ye(e);return{c(){A=h("div"),K(t.$$.fragment),n=R(),o&&o.c(),i=R(),f(A,"class","tile svelte-4b2ujb")},m(l,c){I(l,A,c),G(t,A,null),D(A,n),o&&o.m(A,null),D(A,i),r=!0},p(l,c){const g={};c&2&&(g.tile=l[16]),t.$set(g),c&31&&(s=l[6](l[16],l[3]+l[18],l[4]+l[0].map.viewY-l[15]-1)&&l[2]==l[2]),s?o?(o.p(l,c),c&31&&b(o,1)):(o=ye(l),o.c(),b(o,1),o.m(A,i)):o&&(T(),H(o,1,1,()=>{o=null}),S())},i(l){r||(b(t.$$.fragment,l),b(o),r=!0)},o(l){H(t.$$.fragment,l),H(o),r=!1},d(l){l&&v(A),j(t),o&&o.d()}}}function Ye(e){let A,t,n=e[13],s=[];for(let r=0;r<n.length;r+=1)s[r]=Me(be(e,n,r));const i=r=>H(s[r],1,1,()=>{s[r]=null});return{c(){A=h("div");for(let r=0;r<s.length;r+=1)s[r].c();f(A,"class","lines svelte-4b2ujb")},m(r,o){I(r,A,o);for(let l=0;l<s.length;l+=1)s[l].m(A,null);t=!0},p(r,o){if(o&223){n=r[13];let l;for(l=0;l<n.length;l+=1){const c=be(r,n,l);s[l]?(s[l].p(c,o),b(s[l],1)):(s[l]=Me(c),s[l].c(),b(s[l],1),s[l].m(A,null))}for(T(),l=n.length;l<s.length;l+=1)i(l);S()}},i(r){if(!t){for(let o=0;o<n.length;o+=1)b(s[o]);t=!0}},o(r){s=s.filter(Boolean);for(let o=0;o<s.length;o+=1)H(s[o]);t=!1},d(r){r&&v(A),TA(s,r)}}}function ts(e){let A,t,n,s,i,r,o,l,c,g,a,u,m,d,w,C,Q,P,y=e[1],Y=[];for(let E=0;E<y.length;E+=1)Y[E]=Ye(Pe(e,y,E));const x=E=>H(Y[E],1,1,()=>{Y[E]=null});return{c(){A=h("div");for(let E=0;E<Y.length;E+=1)Y[E].c();t=R(),n=h("button"),n.textContent="UP",s=R(),i=h("button"),i.textContent="DOWN",r=R(),o=h("button"),o.textContent="LEFT",l=R(),c=h("button"),c.textContent="RIGHT",g=R(),a=h("span"),u=V("X = "),m=V(e[3]),d=V(" / Y = "),w=V(e[4]),f(n,"class","up svelte-4b2ujb"),f(i,"class","down svelte-4b2ujb"),f(o,"class","left svelte-4b2ujb"),f(c,"class","right svelte-4b2ujb"),f(a,"class","coords svelte-4b2ujb"),f(A,"class","grid svelte-4b2ujb"),gt(A,"background","url("+SA+")")},m(E,F){I(E,A,F);for(let M=0;M<Y.length;M+=1)Y[M].m(A,null);D(A,t),D(A,n),D(A,s),D(A,i),D(A,r),D(A,o),D(A,l),D(A,c),D(A,g),D(A,a),D(a,u),D(a,m),D(a,d),D(a,w),C=!0,Q||(P=[U(window,"keydown",e[5]),U(n,"click",e[8]),U(i,"click",e[9]),U(o,"click",e[10]),U(c,"click",e[11])],Q=!0)},p(E,[F]){if(F&223){y=E[1];let M;for(M=0;M<y.length;M+=1){const J=Pe(E,y,M);Y[M]?(Y[M].p(J,F),b(Y[M],1)):(Y[M]=Ye(J),Y[M].c(),b(Y[M],1),Y[M].m(A,t))}for(T(),M=y.length;M<Y.length;M+=1)x(M);S()}(!C||F&8)&&hA(m,E[3]),(!C||F&16)&&hA(w,E[4])},i(E){if(!C){for(let F=0;F<y.length;F+=1)b(Y[F]);C=!0}},o(E){Y=Y.filter(Boolean);for(let F=0;F<Y.length;F+=1)H(Y[F]);C=!1},d(E){E&&v(A),TA(Y,E),Q=!1,N(P)}}}function ns(e,A,t){let{game:n}=A,s=null,i=[],r=!1,o=0,l=0;n.map.tiles.subscribe(C=>{t(1,s=C),t(3,o=n.map.startX),t(4,l=n.map.startY)}),n.map.units.subscribe(C=>{i=C,t(2,r=!r),t(4,l=n.map.startY),t(3,o=n.map.startX)}),n.map.update();function c(C){switch(C.key){case"ArrowDown":n.map.moveDown();break;case"ArrowUp":n.map.moveTop();break;case"ArrowLeft":n.map.moveLeft();break;case"ArrowRight":n.map.moveRight();break}}function g(C,Q,P){return i.some(y=>y.x===Q&&y.y===P)}function a(C,Q){const P=i.filter(y=>y.x===C&&y.y===Q);return P.length==0?null:P[0]}const u=()=>n.map.moveTop(),m=()=>n.map.moveDown(),d=()=>n.map.moveLeft(),w=()=>n.map.moveRight();return e.$$set=C=>{"game"in C&&t(0,n=C.game)},[n,s,r,o,l,c,g,a,u,m,d,w]}let ss=class extends _{constructor(A){super(),q(this,A,ns,ts,W,{game:0})}};function is(e){let A,t,n,s,i,r,o,l,c,g,a;return n=new hn({props:{game:e[0]}}),i=new ss({props:{game:e[0]}}),l=new sn({props:{game:e[0]}}),g=new Wt({}),{c(){A=h("main"),t=h("div"),K(n.$$.fragment),s=R(),K(i.$$.fragment),r=R(),o=h("aside"),K(l.$$.fragment),c=R(),K(g.$$.fragment),f(t,"class","game svelte-71xqxf"),f(o,"class","svelte-71xqxf"),f(A,"class","svelte-71xqxf")},m(u,m){I(u,A,m),D(A,t),G(n,t,null),D(t,s),G(i,t,null),D(A,r),D(A,o),G(l,o,null),D(A,c),G(g,A,null),a=!0},p,i(u){a||(b(n.$$.fragment,u),b(i.$$.fragment,u),b(l.$$.fragment,u),b(g.$$.fragment,u),a=!0)},o(u){H(n.$$.fragment,u),H(i.$$.fragment,u),H(l.$$.fragment,u),H(g.$$.fragment,u),a=!1},d(u){u&&v(A),j(n),j(i),j(l),j(g)}}}function os(e){let A,t;return A=new fn({props:{$$slots:{default:[is]},$$scope:{ctx:e}}}),{c(){K(A.$$.fragment)},m(n,s){G(A,n,s),t=!0},p(n,[s]){const i={};s&4&&(i.$$scope={dirty:s,ctx:n}),A.$set(i)},i(n){t||(b(A.$$.fragment,n),t=!0)},o(n){H(A.$$.fragment,n),t=!1},d(n){j(A,n)}}}function rs(e){const A=new Vt("quentin.briolant");return A.currentPlayer.subscribe(t=>t),document.addEventListener("contextmenu",t=>t.preventDefault()),[A]}class ls extends _{constructor(A){super(),q(this,A,rs,os,W,{})}}new ls({target:document.getElementById("app")}); diff --git a/rushs/data-clash/step-0-agents/registration.txt b/rushs/data-clash/step-0-agents/registration.txt new file mode 100644 index 0000000..405aa72 --- /dev/null +++ b/rushs/data-clash/step-0-agents/registration.txt @@ -0,0 +1 @@ +dd6f5d991515e782698f8f7a3d374dbd0c1723b2aa1ddf3226c89248c762e118 diff --git a/rushs/data-clash/step-1/filtering.sql b/rushs/data-clash/step-1/filtering.sql new file mode 100644 index 0000000..fc980bb --- /dev/null +++ b/rushs/data-clash/step-1/filtering.sql @@ -0,0 +1,2 @@ +DELETE FROM investigation.mirrored_reports +WHERE target_id != 'martial.simon'; diff --git a/rushs/data-clash/step-1/injecting.txt b/rushs/data-clash/step-1/injecting.txt new file mode 100644 index 0000000..c56c4c5 --- /dev/null +++ b/rushs/data-clash/step-1/injecting.txt @@ -0,0 +1 @@ +test');SELECT * FROM reports; INSERT INTO reports (author_id,target_id,report_content) VALUES ('martial.simon', '1', 'test diff --git a/rushs/data-clash/step-1/mirroring.sql b/rushs/data-clash/step-1/mirroring.sql new file mode 100644 index 0000000..60a3c4c --- /dev/null +++ b/rushs/data-clash/step-1/mirroring.sql @@ -0,0 +1,19 @@ +CREATE SCHEMA investigation; + +CREATE TYPE investigation.danger_level AS ENUM ( + 'low', + 'medium', + 'high', + 'critical', + 'unknown' +); + +CREATE TABLE investigation.mirrored_reports +( + id SERIAL PRIMARY KEY, + target_id VARCHAR(255) NOT NULL, + report_content VARCHAR(255) NOT NULL, + report_date TIMESTAMP NOT NULL, + on_case TEXT, + danger_level investigation.danger_level DEFAULT 'unknown' NOT NULL +); diff --git a/rushs/data-clash/step-1/tracking.sql b/rushs/data-clash/step-1/tracking.sql new file mode 100644 index 0000000..691af8d --- /dev/null +++ b/rushs/data-clash/step-1/tracking.sql @@ -0,0 +1,4 @@ +SELECT on_case AS investigating_id, COUNT(*) AS report_count +FROM investigation.mirrored_reports +GROUP BY on_case +ORDER BY report_count DESC, investigating_id ASC diff --git a/rushs/data-clash/step-2/geo_data_mrhrsn.sql b/rushs/data-clash/step-2/geo_data_mrhrsn.sql new file mode 100644 index 0000000..06ea8ef --- /dev/null +++ b/rushs/data-clash/step-2/geo_data_mrhrsn.sql @@ -0,0 +1,6154 @@ +CREATE SCHEMA IF NOT EXISTS geo_data; + +CREATE TABLE IF NOT EXISTS geo_data.population_tracking ( + id SERIAL PRIMARY KEY, + latitude DOUBLE PRECISION NOT NULL, + longitude DOUBLE PRECISION NOT NULL, + timestamp TIMESTAMP NOT NULL +); + +CREATE TABLE IF NOT EXISTS geo_data.points_of_interest ( + name TEXT PRIMARY KEY, + latitude DOUBLE PRECISION NOT NULL, + longitude DOUBLE PRECISION NOT NULL +); + +INSERT INTO geo_data.points_of_interest (name, latitude, longitude) VALUES +('Family Business, Pizza Place', 11.914200762534946, 28.44332044400506), +('Mementos City Hall, City Hall', 11.936349621422892, 22.861889724343932), +('The Blue Room, Bar', 12.61710790155203, 19.872525685019447), +('The Great Wall, Chinese Restaurant', 11.93647672585398, 22.86135933515832), +('Green Park, Park', 16.604000813212796, 21.112253171660615), +('Napoleon Sr. Memorial Park, Park', 21.1689838283104, 23.40865133123954), +('Central Plaza, Public Square', 11.93647672585398, 22.86135933515832), +('Desert Oasis, Natural Landmark', 13.522667246705916, 19.411090965255877), +('Sunset Ridge, Viewpoint', 13.420587799059835, 14.871003381518648), +('Savanna Outpost, Village', 17.255725619828823, 9.970303722357833), +('Nomad’s Camp, Cultural Site', 22.298565120220413, 4.9622328395314295), +('Canyon Base, Exploration Spot', 18.650902274349928, 3.7334344745283903), +('Highland Lookout, Scenic View', 17.59031697127502, 2.5887676420961774), +('Golden Pathway, Hiking Trail', 15.568462926603907, 0.962558678243255), +('Coastal Refuge, Fishing Spot', 9.435601877304086, 1.687774322872442), +('Riverbank Village, Settlement', 12.798990598046624, 3.2261105387525033), +('Eagle’s Nest, Hilltop', 7.697212166245492, 7.797166723081861), +('Emerald Forest, Natural Reserve', 6.608333695523336, 10.38987580328413), +('Silver Bay, Coastal Landmark', 3.719829050135626, 6.324272947029642), +('Mountain Pass, Remote Trail', 1.9639876026049448, 10.455804498250407), +('Forest Haven, Camping Site', 3.610174244504905, 11.642521007643602), +('Crystal Lake, Tourist Spot', 5.778360135162506, 16.674248562677327), +('Amber Fields, Agricultural Area', 4.837458889518594, 19.24546766636258), +('Eastern Watch, Observation Post', 2.227521877218744, 23.179213132684477), +('Valley Crossroads, Trading Point', 3.522440846283747, 24.937311665118813), +('Prairie Rest, Rest Area', 7.3717097067026875, 22.123985746464584), +('High Desert Camp, Shelter', 9.848527242007643, 19.574742874434786), +('Eastern Horizon, Hill Ridge', 10.151515478257606, 15.201472775004293), +('Northern Meadows, Plain', 12.564317400088632, 7.862537654801148), +('Rocky Foothills, Geological Site', 14.14649918375826, 7.357642089973268), +('Twin Peaks, Scenic Spot', 16.477851430271258, 9.225621780684783), +('Hidden Springs, Hot Springs', 16.456776938448492, 11.269411324639714), +('Golden Valley, Archaeological Site', 4.235247215614179, 35.91642632138404), +('Explorer''s Base, Historical Landmark', 1.3273874812854451, 26.689379197506945), +('Western Border, Frontier Point', 3.4578470400608157, 32.307625668489884), +('Lake Haven, Resort', 0.8763786139011992, 32.88175304508671), +('Red Sand Dunes, Desert Landmark', 4.480586623368505, 47.72704663994671), +('Nomad’s Rest, Campground', 22.728402448180663, 18.65159592515183), +('Eastern Cliffs, Hiking Spot', 10.091744573100888, 24.351860592791446), +('Savannah Hills, Nature Reserve', 13.890251065923575, 33.39708108001947), +('Riverbend Camp, Riverside Spot', 16.329894976959256, 31.968626022416544), +('Desert Peak, Mountain Summit', 16.90592745686526, 27.51038848493731), +('Golden Plains, Farming Region', 17.884238547000113, 25.582960863505253), +('Great Plateau, Panoramic View', 19.978766753126543, 27.469379386608995), +('Frontier Ridge, Outpost', 21.245384256655196, 28.330570451504183), +('Sandstone Canyon, Landmark', 2.47490736158716, 40.22320896672353), +('Azure Basin, Watering Hole', 4.8483735201279465, 44.570173389527845); +INSERT INTO geo_data.population_tracking (latitude, longitude, timestamp) VALUES +(11.290544903029852, 27.514454965194197, '2077-11-22T00:05:45.635Z'), +(11.457513290805583, 27.454020328141773, '2077-11-22T00:05:48.635Z'), +(11.67819084648074, 27.34413916986464, '2077-11-22T00:05:53.635Z'), +(11.861058739009563, 27.250740185329054, '2077-11-22T00:05:57.635Z'), +(11.990068309178724, 27.168329316621183, '2077-11-22T00:06:00.635Z'), +(12.188837034344685, 27.080424389999454, '2077-11-22T00:06:04.635Z'), +(12.33379067864122, 27.30018670655377, '2077-11-22T00:06:09.635Z'), +(12.129759073455785, 27.366115401520048, '2077-11-22T00:06:13.635Z'), +(12.194207106644265, 27.56939554433277, '2077-11-22T00:06:17.635Z'), +(12.033057827382413, 27.63532423929908, '2077-11-22T00:06:20.635Z'), +(11.904068741857753, 27.717735108006917, '2077-11-22T00:06:23.635Z'), +(11.780396722515137, 27.794651918800938, '2077-11-22T00:06:26.635Z'), +(11.683571045671439, 27.827616266284096, '2077-11-22T00:06:28.635Z'), +(11.55980012499032, 27.91552119290578, '2077-11-22T00:06:31.635Z'), +(11.479050448447264, 27.964967714130495, '2077-11-22T00:06:33.635Z'), +(11.55980012499032, 28.102319161976943, '2077-11-22T00:06:36.635Z'), +(11.66743013486687, 28.261646841478793, '2077-11-22T00:06:40.635Z'), +(11.898692863179543, 28.140777567373952, '2077-11-22T00:06:45.635Z'), +(12.027684513079885, 28.063860756579928, '2077-11-22T00:06:48.635Z'), +(12.247901840173247, 27.964967714130495, '2077-11-22T00:06:53.635Z'), +(12.392822941280585, 27.877062787508812, '2077-11-22T00:06:56.635Z'), +(12.516210789675442, 27.81662815045635, '2077-11-22T00:06:59.635Z'), +(12.634178786716113, 27.712241050093063, '2077-11-22T00:07:02.635Z'), +(12.1190162173467, 29.080261470643563, '2077-11-22T00:07:33.635Z'), +(12.264008132603937, 29.01982683359114, '2077-11-22T00:07:36.635Z'), +(12.430381973578992, 28.937415964883268, '2077-11-22T00:07:40.635Z'), +(12.569839322333486, 28.838522922433835, '2077-11-22T00:07:43.635Z'), +(12.714580339913503, 28.750617995812103, '2077-11-22T00:07:46.635Z'), +(12.869951050092245, 28.695677416673536, '2077-11-22T00:07:49.635Z'), +(12.99846100039574, 28.60777249005181, '2077-11-22T00:07:52.635Z'), +(13.105501851207519, 28.547337852999387, '2077-11-22T00:07:54.635Z'), +(13.223193024766722, 28.481409158033117, '2077-11-22T00:07:56.635Z'), +(13.298057875622849, 28.52536162134398, '2077-11-22T00:07:57.635Z'), +(13.383589396111025, 28.684689300845832, '2077-11-22T00:08:00.635Z'), +(13.474433357435874, 28.871487269916987, '2077-11-22T00:08:04.635Z'), +(13.602624874058563, 29.080261470643563, '2077-11-22T00:08:09.635Z'), +(13.533196374226597, 29.146190165609838, '2077-11-22T00:08:11.635Z'), +(13.394278704557353, 29.23958915014542, '2077-11-22T00:08:14.635Z'), +(13.228541278054431, 29.371446540078004, '2077-11-22T00:08:18.635Z'), +(13.078745987431915, 29.442869292958136, '2077-11-22T00:08:21.635Z'), +(12.92350490535602, 29.54176233540757, '2077-11-22T00:08:25.635Z'), +(12.869951050092245, 29.41539900338887, '2077-11-22T00:08:27.635Z'), +(12.773525313551689, 29.272553497628575, '2077-11-22T00:08:30.635Z'), +(12.730657601553853, 29.157178281437545, '2077-11-22T00:08:32.635Z'), +(12.628817782018967, 28.964886254452573, '2077-11-22T00:08:36.635Z'), +(12.548389249577845, 28.84951103826154, '2077-11-22T00:08:39.635Z'), +(10.778327996237604, 27.80018530617452, '2077-11-22T00:09:24.635Z'), +(10.91861851964204, 27.71228037955279, '2077-11-22T00:09:27.635Z'), +(10.778327996237604, 27.81117342200222, '2077-11-22T00:09:30.635Z'), +(10.589372204221789, 27.910066464451656, '2077-11-22T00:09:34.635Z'), +(10.481344999700033, 27.99247733315953, '2077-11-22T00:09:37.635Z'), +(10.367875873452869, 28.036429796470394, '2077-11-22T00:09:39.635Z'), +(10.281395577945478, 28.080382259781256, '2077-11-22T00:09:41.635Z'), +(10.151630786606196, 28.179275302230693, '2077-11-22T00:09:44.635Z'), +(10.243552989883295, 28.333108923818692, '2077-11-22T00:09:47.635Z'), +(10.303017879651355, 28.415519792526524, '2077-11-22T00:09:49.635Z'), +(10.351662630876723, 28.525400950803707, '2077-11-22T00:09:51.635Z'), +(10.421913946417906, 28.629788051166994, '2077-11-22T00:09:53.635Z'), +(10.508355349135561, 28.822080078152002, '2077-11-22T00:09:57.635Z'), +(10.551566993539115, 28.898996888945987, '2077-11-22T00:09:58.635Z'), +(11.031821130749766, 29.69004201104079, '2077-11-22T00:10:18.635Z'), +(11.188160511595571, 29.574666794849758, '2077-11-22T00:10:22.635Z'), +(11.371347482709643, 29.508738099883487, '2077-11-22T00:10:26.635Z'), +(11.49520144128521, 29.398856941606347, '2077-11-22T00:10:29.635Z'), +(11.629763563673034, 29.33292824664007, '2077-11-22T00:10:32.635Z'), +(11.796530229998515, 29.266999551673756, '2077-11-22T00:10:35.635Z'), +(11.839550397150752, 29.42083317326176, '2077-11-22T00:10:38.635Z'), +(11.882563793978015, 29.470279694486475, '2077-11-22T00:10:39.635Z'), +(11.710469677503827, 29.563678679022054, '2077-11-22T00:10:43.635Z'), +(11.581328651722728, 29.607631142332917, '2077-11-22T00:10:46.635Z'), +(11.51673572028392, 29.64608954772993, '2077-11-22T00:10:47.635Z'), +(11.619000976858612, 29.706524184782346, '2077-11-22T00:10:49.635Z'), +(11.667429338600833, 29.816405343059486, '2077-11-22T00:10:51.635Z'), +(11.635144701077428, 29.882334038025803, '2077-11-22T00:10:52.635Z'), +(11.527502241596743, 29.942768675078224, '2077-11-22T00:10:54.635Z'), +(11.468281278096336, 29.997709254216797, '2077-11-22T00:10:55.635Z'), +(11.312093904448448, 30.102096354580084, '2077-11-22T00:10:59.635Z'), +(11.312093904448448, 30.211977512857217, '2077-11-22T00:11:01.635Z'), +(11.365961302012803, 30.332846786962108, '2077-11-22T00:11:03.635Z'), +(11.414433258570877, 30.44272794523924, '2077-11-22T00:11:05.635Z'), +(11.468281278096336, 30.519644756033262, '2077-11-22T00:11:07.635Z'), +(11.49520144128521, 30.563597219344082, '2077-11-22T00:11:08.635Z'), +(11.619000976858612, 30.519644756033262, '2077-11-22T00:11:10.635Z'), +(11.710469677503827, 30.437233887325387, '2077-11-22T00:11:12.635Z'), +(11.855681215603463, 30.371305192359113, '2077-11-22T00:11:15.635Z'), +(11.947071144174801, 30.3053764973928, '2077-11-22T00:11:17.635Z'), +(12.05454921487116, 30.255929976168087, '2077-11-22T00:11:19.635Z'), +(12.161984248135962, 30.22845968659882, '2077-11-22T00:11:21.635Z'), +(12.231793770208993, 30.1625309916325, '2077-11-22T00:11:23.635Z'), +(12.312320305851525, 30.091108238752373, '2077-11-22T00:11:25.635Z'), +(17.05533287537712, 26.530642833494277, '2077-11-22T00:13:35.635Z'), +(13.688745953899698, 23.360408125222506, '2077-11-22T00:15:16.635Z'), +(11.415025146575516, 40.56903948886672, '2077-11-22T00:21:32.635Z'), +(12.232531579992184, 11.603629842842249, '2077-11-22T00:32:02.635Z'), +(8.8635740450862, 31.339514190678017, '2077-11-22T00:39:19.635Z'), +(17.901480277389876, 18.64363527119158, '2077-11-22T00:44:59.635Z'), +(21.553872836295014, 45.12618087606324, '2077-11-22T00:54:18.635Z'), +(7.545810841909976, 48.385255244729734, '2077-11-22T00:59:37.635Z'), +(22.644491055784908, 13.426695247305044, '2077-11-22T01:13:16.635Z'), +(7.649560882726058, 5.834570280642247, '2077-11-22T01:19:26.635Z'), +(3.3365608886623552, 49.3449194771338, '2077-11-22T01:35:33.635Z'), +(2.93825031703014, 28.249119363212873, '2077-11-22T01:43:21.635Z'), +(16.939089535269865, 30.63827329189649, '2077-11-22T01:48:36.635Z'), +(10.989393848342663, 10.615256290811741, '2077-11-22T01:56:07.635Z'), +(18.130227951673884, 10.051732292356908, '2077-11-22T01:58:46.635Z'), +(2.307881131229697, 38.314646308948014, '2077-11-22T02:10:35.635Z'), +(7.5435672714966335, 19.028646793927884, '2077-11-22T02:17:57.635Z'), +(3.430113435159045, 33.85641665579869, '2077-11-22T02:23:37.635Z'), +(1.1160376485229282, 3.4782892549640967, '2077-11-22T02:34:53.635Z'), +(6.121570519232528, 11.73366520565139, '2077-11-22T02:38:27.635Z'), +(6.378652672377503, 25.3286962865847, '2077-11-22T02:43:27.635Z'), +(5.469851830225478, 21.757148760390418, '2077-11-22T02:44:48.635Z'), +(23.089394979519138, 46.50716691824607, '2077-11-22T02:55:47.635Z'), +(16.15099209746365, 18.734346922406235, '2077-11-22T03:05:47.635Z'), +(15.246845563882356, 43.122596385926485, '2077-11-22T03:14:29.635Z'), +(4.68354551743562, 46.68305938252822, '2077-11-22T03:18:36.635Z'), +(0.47509743740699917, 9.651508393318842, '2077-11-22T03:32:23.635Z'), +(8.543033358701102, 32.961583458116955, '2077-11-22T03:41:29.635Z'), +(2.0273048828290148, 49.35562844838598, '2077-11-22T03:47:59.635Z'), +(12.701032623949962, 20.05462579126473, '2077-11-22T03:59:26.635Z'), +(18.74002096022091, 20.49596117189118, '2077-11-22T04:01:40.635Z'), +(1.905265107794612, 47.37273965763531, '2077-11-22T04:13:14.635Z'), +(17.085273429257292, 20.256181824895194, '2077-11-22T04:24:36.635Z'), +(6.880677253811157, 14.856985346819325, '2077-11-22T04:28:51.635Z'), +(7.563212622783998, 48.81216380143576, '2077-11-22T04:41:20.635Z'), +(15.078554241487325, 29.994030943272286, '2077-11-22T04:48:42.635Z'), +(16.207404548775138, 22.190729773259793, '2077-11-22T04:51:30.635Z'), +(18.812939625431692, 0.685696260599481, '2077-11-22T04:59:09.635Z'), +(18.76610100507236, 47.83133318097079, '2077-11-22T05:15:38.635Z'), +(0.7095327608170606, 3.3121888826474777, '2077-11-22T05:33:08.635Z'), +(1.4794175922554127, 2.3976741065922447, '2077-11-22T05:33:34.635Z'), +(3.1261787761147732, 0.6620969420505758, '2077-11-22T05:34:27.635Z'), +(17.968359766203893, 5.591966930968983, '2077-11-22T05:40:14.635Z'), +(3.6385624530991434, 31.26902576484994, '2077-11-22T05:50:57.635Z'), +(9.742266176427082, 24.758508991689393, '2077-11-22T05:54:14.635Z'), +(7.151740207559462, 21.405157536844744, '2077-11-22T05:55:47.635Z'), +(23.50426634731757, 12.208045529178277, '2077-11-22T06:02:40.635Z'), +(15.752912825093434, 11.21555282887932, '2077-11-22T06:05:33.635Z'), +(7.063886765564424, 10.779319989023305, '2077-11-22T06:08:46.635Z'), +(14.511082125549988, 15.863703877696635, '2077-11-22T06:12:05.635Z'), +(14.592346497816198, 35.01143172022072, '2077-11-22T06:18:57.635Z'), +(23.050659606744365, 15.584507823274617, '2077-11-22T06:26:26.635Z'), +(7.586764112826354, 7.855496699293388, '2077-11-22T06:32:47.635Z'), +(15.483751892775258, 16.480389447624336, '2077-11-22T06:37:04.635Z'), +(3.4690901868482915, 10.928438702142, '2077-11-22T06:41:57.635Z'), +(12.399114565310219, 7.9033088403386085, '2077-11-22T06:45:26.635Z'), +(22.361906813052368, 42.31753330568675, '2077-11-22T06:58:07.635Z'), +(20.29187385333603, 10.152047678825555, '2077-11-22T07:09:13.635Z'), +(21.64147372462707, 9.329273648236697, '2077-11-22T07:09:47.635Z'), +(15.446244897501668, 9.225166461787706, '2077-11-22T07:12:04.635Z'), +(9.42532770947714, 23.26397724026072, '2077-11-22T07:17:36.635Z'), +(15.345229941006856, 1.2937716771227965, '2077-11-22T07:25:50.635Z'), +(8.201787964803993, 3.5208399870292983, '2077-11-22T07:28:36.635Z'), +(5.712479158977054, 33.32938517203478, '2077-11-22T07:39:36.635Z'), +(18.59971100347019, 43.06039457801776, '2077-11-22T07:45:31.635Z'), +(2.523706071732583, 27.871854054737646, '2077-11-22T07:53:38.635Z'), +(23.519290921420804, 19.47380133733631, '2077-11-22T08:01:58.635Z'), +(9.772040245554477, 1.8861609525878837, '2077-11-22T08:10:00.635Z'), +(15.011703835633265, 7.490338031105918, '2077-11-22T08:12:48.635Z'), +(21.48239178850508, 3.966891294908268, '2077-11-22T08:15:29.635Z'), +(5.741858453593176, 41.82187471624113, '2077-11-22T08:30:15.635Z'), +(7.4961057756439065, 37.33814815737089, '2077-11-22T08:32:01.635Z'), +(7.655216975906031, 25.337298336984105, '2077-11-22T08:36:25.635Z'), +(9.630959463019831, 19.172530183338168, '2077-11-22T08:38:47.635Z'), +(0.13958887512676954, 21.448668894074487, '2077-11-22T08:42:24.635Z'), +(21.083204314084636, 16.34327867794462, '2077-11-22T08:50:22.635Z'), +(8.847388147027647, 15.457973604792473, '2077-11-22T08:54:54.635Z'), +(5.93098669015197, 20.488181642118306, '2077-11-22T08:57:02.635Z'), +(17.488326433808265, 6.250083696911558, '2077-11-22T09:03:44.635Z'), +(3.3310198750701536, 13.47499264853887, '2077-11-22T09:09:36.635Z'), +(6.090650299099828, 20.702537418728266, '2077-11-22T09:12:27.635Z'), +(2.4298271936173155, 38.38998147844414, '2077-11-22T09:19:07.635Z'), +(13.274744686299421, 24.201800303659876, '2077-11-22T09:25:41.635Z'), +(3.872959549828321, 36.178933925628115, '2077-11-22T09:31:17.635Z'), +(14.014664745105735, 0.34171577362382605, '2077-11-22T09:44:54.635Z'), +(22.89923140770117, 13.038703660898399, '2077-11-22T09:50:26.635Z'), +(17.333468688059174, 11.570506296176465, '2077-11-22T09:52:33.635Z'), +(2.385329407659069, 35.467640048058385, '2077-11-22T10:02:51.635Z'), +(6.257032271613216, 41.199872439125905, '2077-11-22T10:05:24.635Z'), +(15.544564089206718, 37.08842004705776, '2077-11-22T10:09:09.635Z'), +(17.28469689932263, 30.35779840085281, '2077-11-22T10:11:37.635Z'), +(8.170181715328726, 2.4218326614367403, '2077-11-22T10:22:15.635Z'), +(21.278288108391166, 23.718020567513282, '2077-11-22T10:31:16.635Z'), +(11.662890681480393, 4.405847362958378, '2077-11-22T10:38:59.635Z'), +(1.8892792373210843, 15.209561314130596, '2077-11-22T10:44:21.635Z'), +(17.22506041829383, 12.813066851294304, '2077-11-22T10:50:06.635Z'), +(0.38201055395649064, 19.17590036454247, '2077-11-22T10:56:45.635Z'), +(21.581037611990105, 30.217377848746004, '2077-11-22T11:05:33.635Z'), +(19.11544429500532, 7.137940948121948, '2077-11-22T11:13:36.635Z'), +(2.6559277468320186, 27.4744225305343, '2077-11-22T11:23:10.635Z'), +(18.62973678374198, 24.281553407320388, '2077-11-22T11:29:11.635Z'), +(1.35201441261931, 24.152357514917107, '2077-11-22T11:35:35.635Z'), +(15.083550137889434, 14.591496346930805, '2077-11-22T11:41:45.635Z'), +(17.83482422960961, 11.243583634452076, '2077-11-22T11:43:19.635Z'), +(19.55548679175975, 43.80278060670251, '2077-11-22T11:54:44.635Z'), +(14.933060783513186, 42.21325166529065, '2077-11-22T11:56:32.635Z'), +(9.801454844561144, 3.3558928424835854, '2077-11-22T12:10:42.635Z'), +(15.697688495354729, 29.973471211591615, '2077-11-22T12:20:33.635Z'), +(18.672185062771984, 26.28225357861973, '2077-11-22T12:22:15.635Z'), +(12.087074525959055, 18.121592715375368, '2077-11-22T12:26:03.635Z'), +(13.344450674255981, 6.740137861043467, '2077-11-22T12:30:11.635Z'), +(13.877898916537667, 1.0803934207677095, '2077-11-22T12:32:13.635Z'), +(21.086849631498684, 3.3819267599379867, '2077-11-22T12:35:00.635Z'), +(1.25868062311108, 15.546427294275905, '2077-11-22T12:43:33.635Z'), +(16.414102437139302, 35.5166843666038, '2077-11-22T12:52:45.635Z'), +(17.975001728974913, 3.554968198343628, '2077-11-22T13:04:04.635Z'), +(16.662151063588126, 34.56257254618049, '2077-11-22T13:15:02.635Z'), +(1.8370385562086982, 23.045928303022997, '2077-11-22T13:21:56.635Z'), +(3.924110769201773, 11.520467749367478, '2077-11-22T13:26:16.635Z'), +(5.187293205134666, 11.25638097166927, '2077-11-22T13:26:44.635Z'), +(14.492008290817534, 40.781958720132046, '2077-11-22T13:38:02.635Z'), +(12.762847708136198, 48.43210766566624, '2077-11-22T13:40:51.635Z'), +(7.746712941526524, 40.996350452675294, '2077-11-22T13:44:08.635Z'), +(9.122796795638854, 5.210110383186315, '2077-11-22T13:57:15.635Z'), +(9.202490555101297, 22.16767809577706, '2077-11-22T14:03:27.635Z'), +(20.826931923157144, 43.95840470151274, '2077-11-22T14:12:20.635Z'), +(0.47334311439421656, 18.33773163150228, '2077-11-22T14:24:17.635Z'), +(12.858777200942846, 2.599942511639386, '2077-11-22T14:31:39.635Z'), +(8.890966107512964, 37.86564441660242, '2077-11-22T14:44:33.635Z'), +(13.086921211932868, 43.58431059743295, '2077-11-22T14:47:08.635Z'), +(18.907084525088987, 23.65680339459521, '2077-11-22T14:54:32.635Z'), +(10.313675402022874, 12.902670434040113, '2077-11-22T14:59:31.635Z'), +(15.916391870312705, 29.30575099189824, '2077-11-22T15:05:47.635Z'), +(6.9819061977560155, 44.3116113077251, '2077-11-22T15:12:09.635Z'), +(11.989486131040886, 32.093593209176866, '2077-11-22T15:16:59.635Z'), +(19.247832469828893, 47.4726733581813, '2077-11-22T15:23:05.635Z'), +(9.988045566854472, 17.633954280805078, '2077-11-22T15:34:18.635Z'), +(20.822833798440985, 49.53903060994918, '2077-11-22T15:46:21.635Z'), +(7.33711146386923, 2.6635222661757756, '2077-11-22T16:03:51.635Z'), +(6.242498132564082, 43.07326586299015, '2077-11-22T16:18:43.635Z'), +(3.1254836035559475, 32.33143438340815, '2077-11-22T16:22:50.635Z'), +(0.854745149721436, 38.50048828470899, '2077-11-22T16:25:16.635Z'), +(16.82764636574029, 23.16405921116351, '2077-11-22T16:33:24.635Z'), +(8.726324081409855, 12.837998467536726, '2077-11-22T16:38:11.635Z'), +(14.211982298839823, 24.91586171591222, '2077-11-22T16:43:01.635Z'), +(19.464157805656736, 32.482837496563754, '2077-11-22T16:46:19.635Z'), +(11.805439925504498, 38.290396261620856, '2077-11-22T16:49:49.635Z'), +(6.674532256610161, 9.76237609033077, '2077-11-22T17:00:25.635Z'), +(5.363966651544495, 18.238191977836934, '2077-11-22T17:03:34.635Z'), +(23.410498638531575, 19.15879525680666, '2077-11-22T17:10:15.635Z'), +(21.53603558684576, 33.15920434231208, '2077-11-22T17:15:05.635Z'), +(21.18296504764851, 2.7097271530318796, '2077-11-22T17:25:34.635Z'), +(19.732853844415, 23.46642341084914, '2077-11-22T17:32:47.635Z'), +(21.309610903934804, 7.845892020621865, '2077-11-22T17:38:14.635Z'), +(18.0653569484071, 1.1309890450877622, '2077-11-22T17:40:52.635Z'), +(7.483764444718166, 31.201023357673776, '2077-11-22T17:52:23.635Z'), +(9.232723603019977, 9.408894041717932, '2077-11-22T18:00:23.635Z'), +(0.8468564075677091, 20.269641659455335, '2077-11-22T18:05:27.635Z'), +(13.459522523945932, 7.052867192048032, '2077-11-22T18:12:11.635Z'), +(12.560451920108058, 4.643826877315634, '2077-11-22T18:13:06.635Z'), +(19.82936488612228, 32.9987693047042, '2077-11-22T18:23:31.635Z'), +(2.106578122629504, 13.435892924167836, '2077-11-22T18:33:10.635Z'), +(17.229188939488147, 10.316448379856059, '2077-11-22T18:38:53.635Z'), +(19.324308256866505, 0.579989652586511, '2077-11-22T18:42:23.635Z'), +(20.577778148307278, 43.51488163540247, '2077-11-22T18:57:18.635Z'), +(4.829495476532555, 7.042143132365581, '2077-11-22T19:11:40.635Z'), +(23.429232753254578, 8.971082242849633, '2077-11-22T19:18:35.635Z'), +(23.23045124054535, 47.12002322867786, '2077-11-22T19:31:31.635Z'), +(8.41952048445291, 37.497659548526244, '2077-11-22T19:37:59.635Z'), +(2.5209366794316894, 13.773898593035764, '2077-11-22T19:47:00.635Z'), +(15.005480720016573, 14.994133671218162, '2077-11-22T19:51:38.635Z'), +(15.844362273531427, 16.19550920289613, '2077-11-22T19:52:09.635Z'), +(21.62860784234284, 12.949998382175728, '2077-11-22T19:54:34.635Z'), +(17.467623062683195, 43.469394861285096, '2077-11-22T20:05:19.635Z'), +(13.168091034044947, 22.94483772655103, '2077-11-22T20:12:49.635Z'), +(3.0239681851855322, 31.281010656027444, '2077-11-22T20:17:39.635Z'), +(10.95562486603237, 46.50686414527348, '2077-11-22T20:23:58.635Z'), +(2.3421950642303155, 49.02910680397351, '2077-11-22T20:27:17.635Z'), +(6.151996512497615, 49.24257546888282, '2077-11-22T20:28:41.635Z'), +(16.78493241833087, 26.02618474632085, '2077-11-22T20:37:58.635Z'), +(2.1914383857368747, 23.484463716150252, '2077-11-22T20:43:27.635Z'), +(16.574687783482407, 12.622659324843598, '2077-11-22T20:50:05.635Z'), +(20.65824659697903, 29.410970889094916, '2077-11-22T20:56:10.635Z'), +(9.94401504318167, 22.970662415724362, '2077-11-22T21:00:45.635Z'), +(10.466084301423814, 34.21787316650761, '2077-11-22T21:04:51.635Z'), +(11.215973390778942, 49.2886206297413, '2077-11-22T21:10:20.635Z'), +(23.534463033808763, 44.52099598358812, '2077-11-22T21:15:11.635Z'), +(2.7076841959157587, 0.49969684785851026, '2077-11-22T21:32:44.635Z'), +(1.8297714147652502, 34.882488101804206, '2077-11-22T21:45:28.635Z'), +(20.49253643853973, 2.8568902718800255, '2077-11-22T21:58:57.635Z'), +(4.783462091427928, 49.47203865689684, '2077-11-22T22:16:42.635Z'), +(1.7232965445311348, 7.5626875989411415, '2077-11-22T22:32:14.635Z'), +(5.522484556455036, 28.687738906077048, '2077-11-22T22:40:10.635Z'), +(19.572574978334245, 23.989635586025845, '2077-11-22T22:45:38.635Z'), +(0.5853164700145078, 34.36699279740664, '2077-11-22T22:53:36.635Z'), +(17.663624801595546, 47.881199360706695, '2077-11-22T23:01:37.635Z'), +(0.21259844529025512, 40.627216026731766, '2077-11-22T23:08:36.635Z'), +(6.093954366469059, 38.180886500023014, '2077-11-22T23:10:57.635Z'), +(15.378459376210493, 16.438186570457187, '2077-11-22T23:19:34.635Z'), +(16.9558571031433, 45.55817892179921, '2077-11-22T23:29:56.635Z'), +(10.95266287487437, 42.43377393734016, '2077-11-22T23:32:25.635Z'), +(15.450350015016872, 15.61961496122674, '2077-11-22T23:42:13.635Z'), +(21.660527056698186, 15.241616241053187, '2077-11-22T23:44:31.635Z'), +(18.3199464991499, 16.973521283891095, '2077-11-22T23:45:53.635Z'), +(22.084858524288084, 1.755475408825844, '2077-11-22T23:51:21.635Z'), +(15.100324102247907, 3.649533964676873, '2077-11-22T23:54:01.635Z'), +(21.521231370844735, 25.853390199227427, '2077-11-23T00:02:10.635Z'), +(14.155820508546919, 7.068166036213771, '2077-11-23T00:09:19.635Z'), +(2.4741757530265875, 35.895432841393315, '2077-11-23T00:20:43.635Z'), +(17.18208970352765, 9.978222970467382, '2077-11-23T00:31:36.635Z'), +(6.471789292386684, 16.634058547889826, '2077-11-23T00:36:14.635Z'), +(8.691982796217653, 22.11158344581859, '2077-11-23T00:38:24.635Z'), +(15.579871474584403, 4.270685351171231, '2077-11-23T00:45:20.635Z'), +(23.367127727393303, 18.113931540802415, '2077-11-23T00:50:57.635Z'), +(18.705731890538964, 31.294436314885985, '2077-11-23T00:55:49.635Z'), +(12.507919291162226, 19.86363455992812, '2077-11-23T01:00:29.635Z'), +(18.12934218232469, 40.993331938539264, '2077-11-23T01:08:18.635Z'), +(18.383264165559073, 36.913358394412676, '2077-11-23T01:09:44.635Z'), +(18.32993593086394, 22.69591041120959, '2077-11-23T01:14:44.635Z'), +(3.9704150907784856, 1.0350757481693451, '2077-11-23T01:24:13.635Z'), +(23.085373517760225, 14.12772827629616, '2077-11-23T01:32:42.635Z'), +(11.167433189105019, 46.24277122910986, '2077-11-23T01:44:51.635Z'), +(20.693205913548695, 39.14386923158709, '2077-11-23T01:49:11.635Z'), +(19.312440896733772, 21.129982660425153, '2077-11-23T01:55:28.635Z'), +(7.168422040681603, 43.46824779247787, '2077-11-23T02:04:40.635Z'), +(17.788174323139074, 13.658934269001243, '2077-11-23T02:16:07.635Z'), +(0.6639391635725889, 23.420152930062937, '2077-11-23T02:23:23.635Z'), +(0.9724802417923935, 1.8929627873375117, '2077-11-23T02:31:21.635Z'), +(11.82473074004662, 40.887191312698256, '2077-11-23T02:46:14.635Z'), +(22.686323040917454, 49.95345654117229, '2077-11-23T02:51:22.635Z'), +(1.942478146726228, 43.385945545610184, '2077-11-23T02:59:24.635Z'), +(22.15536412330739, 44.006548920523684, '2077-11-23T03:06:53.635Z'), +(10.520371033274794, 23.36576979650509, '2077-11-23T03:15:22.635Z'), +(21.183218500874748, 4.515860375966853, '2077-11-23T03:23:09.635Z'), +(22.723554179742536, 3.6351417291318335, '2077-11-23T03:23:47.635Z'), +(4.266460092614134, 44.360841182829304, '2077-11-23T03:39:53.635Z'), +(22.79834990451628, 22.436200779171454, '2077-11-23T03:50:19.635Z'), +(17.040945388330787, 22.033692038018245, '2077-11-23T03:52:27.635Z'), +(3.50825870224933, 11.205529729524065, '2077-11-23T03:58:49.635Z'), +(21.278533224250086, 9.242631105000122, '2077-11-23T04:05:26.635Z'), +(4.580762157828439, 13.916112910061678, '2077-11-23T04:11:50.635Z'), +(13.103808568775937, 18.475634825541245, '2077-11-23T04:15:24.635Z'), +(10.414513952480517, 24.829013362220405, '2077-11-23T04:17:54.635Z'), +(5.656920062415998, 10.71141389903687, '2077-11-23T04:23:22.635Z'), +(17.600150011048132, 7.37044488074379, '2077-11-23T04:27:57.635Z'), +(5.633393951618901, 37.44241203192409, '2077-11-23T04:39:42.635Z'), +(7.810084642604652, 19.19850851889012, '2077-11-23T04:46:27.635Z'), +(0.7154530893235818, 20.979036969347245, '2077-11-23T04:49:09.635Z'), +(12.049881010545041, 1.9728026148350972, '2077-11-23T04:57:18.635Z'), +(7.32152794740703, 40.91818231468685, '2077-11-23T05:11:37.635Z'), +(8.314745914551821, 24.098481546309447, '2077-11-23T05:17:48.635Z'), +(14.88603644731225, 12.849431491462193, '2077-11-23T05:22:33.635Z'), +(21.69715370964829, 48.13805688278778, '2077-11-23T05:35:11.635Z'), +(0.4689726402047502, 7.684513984893771, '2077-11-23T05:51:46.635Z'), +(14.869589480531394, 13.947632586684046, '2077-11-23T05:57:34.635Z'), +(19.415403800816566, 37.120653712172945, '2077-11-23T06:05:56.635Z'), +(13.049513042105715, 38.04199125130962, '2077-11-23T06:08:18.635Z'), +(14.660947249653532, 43.02627768352047, '2077-11-23T06:10:11.635Z'), +(13.70803564011045, 1.003524257987138, '2077-11-23T06:25:16.635Z'), +(9.775362842078364, 20.673136058948508, '2077-11-23T06:32:32.635Z'), +(21.174177736877503, 43.08070556978702, '2077-11-23T06:41:33.635Z'), +(8.126772222803794, 37.35049235605684, '2077-11-23T06:46:48.635Z'), +(9.226788635617872, 37.153522580860574, '2077-11-23T06:47:12.635Z'), +(13.172290985474971, 9.78457542506153, '2077-11-23T06:57:15.635Z'), +(7.255159057093144, 29.894007184190713, '2077-11-23T07:04:54.635Z'), +(20.710480787790967, 46.89793447014396, '2077-11-23T07:12:46.635Z'), +(21.777183505133888, 10.474115082792036, '2077-11-23T07:25:19.635Z'), +(1.7943728693052796, 36.15760439187169, '2077-11-23T07:37:10.635Z'), +(15.178704967591282, 29.144018506097378, '2077-11-23T07:42:45.635Z'), +(14.78602340382338, 1.4171363304169027, '2077-11-23T07:52:40.635Z'), +(2.774372931964812, 32.90255138082075, '2077-11-23T08:05:00.635Z'), +(19.7023673547413, 48.443982594968155, '2077-11-23T08:13:25.635Z'), +(12.7641925116917, 35.192147623391776, '2077-11-23T08:18:47.635Z'), +(0.798305909856934, 44.44422189206079, '2077-11-23T08:24:22.635Z'), +(6.7730080435979, 3.20197364748931, '2077-11-23T08:39:46.635Z'), +(20.75594453401483, 47.556900253130394, '2077-11-23T08:56:29.635Z'), +(21.527642224168126, 14.666291248028156, '2077-11-23T09:07:50.635Z'), +(5.951473690018532, 14.834684779978454, '2077-11-23T09:13:36.635Z'), +(6.7389305967996735, 38.511778095083606, '2077-11-23T09:22:19.635Z'), +(16.730353991167657, 46.258738554424234, '2077-11-23T09:26:57.635Z'), +(22.12329153392005, 48.570479955548514, '2077-11-23T09:29:06.635Z'), +(1.7529500676158887, 9.217288010587733, '2077-11-23T09:45:09.635Z'), +(1.6182717202085786, 32.668375429246204, '2077-11-23T09:53:50.635Z'), +(19.048768086953334, 16.656232881955255, '2077-11-23T10:02:31.635Z'), +(11.90328813244374, 2.6273729921515927, '2077-11-23T10:08:10.635Z'), +(21.371012204261305, 21.91214671846383, '2077-11-23T10:15:51.635Z'), +(6.257475568996812, 20.636777487688775, '2077-11-23T10:21:28.635Z'), +(9.630135732869213, 5.014953357867453, '2077-11-23T10:27:20.635Z'), +(14.619068957030207, 12.219189654863097, '2077-11-23T10:30:31.635Z'), +(6.146767646869536, 21.46248929739279, '2077-11-23T10:35:07.635Z'), +(17.36306975763957, 46.49066880106567, '2077-11-23T10:45:05.635Z'), +(18.51410923542526, 8.59580849671714, '2077-11-23T10:58:25.635Z'), +(17.242643225247555, 20.42356630420708, '2077-11-23T11:02:36.635Z'), +(2.4967823665289286, 37.92506662530015, '2077-11-23T11:10:59.635Z'), +(20.669854849103828, 16.030600331799384, '2077-11-23T11:21:22.635Z'), +(10.895709609725943, 18.936011387697295, '2077-11-23T11:25:08.635Z'), +(15.56141977793159, 11.242648923967694, '2077-11-23T11:28:24.635Z'), +(9.688033113623755, 32.34475409695107, '2077-11-23T11:36:19.635Z'), +(0.9487205740280928, 25.989863011575565, '2077-11-23T11:40:18.635Z'), +(7.73631716532741, 6.609339991150467, '2077-11-23T11:47:53.635Z'), +(15.52177151207991, 27.35291022162525, '2077-11-23T11:55:56.635Z'), +(18.530919420710287, 18.59826834813617, '2077-11-23T11:59:13.635Z'), +(2.501609655026213, 2.6561983873732666, '2077-11-23T12:07:30.635Z'), +(13.848095376043467, 10.157235151239421, '2077-11-23T12:12:31.635Z'), +(4.411229977371025, 50.09247625211469, '2077-11-23T12:27:31.635Z'), +(2.5906898055760754, 10.382015522549523, '2077-11-23T12:42:13.635Z'), +(10.152192423545234, 44.308019625224425, '2077-11-23T12:55:00.635Z'), +(6.5687663711338065, 13.886717236160353, '2077-11-23T13:06:13.635Z'), +(19.220527201749608, 29.390968383241702, '2077-11-23T13:13:30.635Z'), +(8.059129691063271, 16.734367991554993, '2077-11-23T13:19:38.635Z'), +(3.9785208317710223, 0.11239561712636238, '2077-11-23T13:25:56.635Z'), +(17.511053385498233, 4.849828545945328, '2077-11-23T13:31:14.635Z'), +(7.799216186347317, 20.647763337385438, '2077-11-23T13:37:58.635Z'), +(17.0854395530244, 33.03497368925086, '2077-11-23T13:43:36.635Z'), +(10.34591403254195, 8.413629858672174, '2077-11-23T13:52:48.635Z'), +(2.8931685904975026, 2.8528387057703712, '2077-11-23T13:56:14.635Z'), +(19.500274736812855, 41.27949905015728, '2077-11-23T14:11:26.635Z'), +(2.8544604197783037, 44.74530283760071, '2077-11-23T14:17:43.635Z'), +(14.477759771922807, 16.767857007203453, '2077-11-23T14:28:49.635Z'), +(3.4033866411670575, 30.332115987094756, '2077-11-23T14:35:15.635Z'), +(10.62323336877013, 23.481893632594986, '2077-11-23T14:38:55.635Z'), +(5.754332626432232, 45.461434686734144, '2077-11-23T14:47:10.635Z'), +(10.698808852428538, 40.63348777414851, '2077-11-23T14:49:42.635Z'), +(21.7257092812045, 25.02444805291106, '2077-11-23T14:56:35.635Z'), +(12.428395318096465, 35.81324767815856, '2077-11-23T15:01:43.635Z'), +(23.137115704739895, 11.960539056603894, '2077-11-23T15:11:00.635Z'), +(4.720432332405313, 15.875816215246855, '2077-11-23T15:17:58.635Z'), +(22.31855429485598, 29.426873568825794, '2077-11-23T15:26:06.635Z'), +(22.99675970699474, 25.69346044817266, '2077-11-23T15:27:24.635Z'), +(9.01078312524411, 33.510071430893305, '2077-11-23T15:33:16.635Z'), +(16.177085598503577, 16.85601248845874, '2077-11-23T15:39:50.635Z'), +(11.16482892909967, 35.84477269492886, '2077-11-23T15:46:54.635Z'), +(3.195827644945769, 7.5593443681709385, '2077-11-23T15:57:42.635Z'), +(22.697400673523997, 42.42724334610693, '2077-11-23T16:12:09.635Z'), +(20.930474851097085, 39.53172072383828, '2077-11-23T16:13:20.635Z'), +(20.198573035004724, 5.010969637831129, '2077-11-23T16:25:17.635Z'), +(23.477802226889473, 13.271499768258966, '2077-11-23T16:28:22.635Z'), +(14.763025548748683, 21.751416133871913, '2077-11-23T16:32:45.635Z'), +(13.835214829010713, 18.259359288617464, '2077-11-23T16:34:03.635Z'), +(16.580478112200918, 13.81403200537296, '2077-11-23T16:35:56.635Z'), +(22.4994640491289, 31.73882229905925, '2077-11-23T16:42:33.635Z'), +(0.07755681696160582, 44.035753010101914, '2077-11-23T16:51:58.635Z'), +(6.361369756825704, 6.9939667291721515, '2077-11-23T17:05:51.635Z'), +(5.030971395439022, 16.32129354125174, '2077-11-23T17:09:19.635Z'), +(17.282927461707462, 30.31896610251712, '2077-11-23T17:16:07.635Z'), +(3.88538548570629, 37.98985161688769, '2077-11-23T17:21:48.635Z'), +(18.097361090661877, 38.81952113974946, '2077-11-23T17:27:04.635Z'), +(2.876827894740431, 40.727209621825644, '2077-11-23T17:32:45.635Z'), +(15.84202897746563, 3.3613103567329707, '2077-11-23T17:47:11.635Z'), +(17.488796660252383, 24.716233651432326, '2077-11-23T17:54:47.635Z'), +(5.538366923774132, 8.5749451696756, '2077-11-23T18:02:07.635Z'), +(20.387867476083173, 28.572398920820767, '2077-11-23T18:11:10.635Z'), +(3.492627535198171, 22.28143139163722, '2077-11-23T18:17:49.635Z'), +(20.34613983019615, 35.72179727578885, '2077-11-23T18:25:43.635Z'), +(8.048221701638926, 1.14109473729733, '2077-11-23T18:38:54.635Z'), +(21.334100048234713, 17.524837960466844, '2077-11-23T18:46:33.635Z'), +(4.230119384453341, 29.992717687225763, '2077-11-23T18:54:19.635Z'), +(19.73053718545072, 24.378385906675735, '2077-11-23T19:00:24.635Z'), +(21.561876751210352, 17.03294263447653, '2077-11-23T19:03:02.635Z'), +(8.582846174334755, 34.75671493455705, '2077-11-23T19:10:58.635Z'), +(21.521511230605675, 11.589983256676762, '2077-11-23T19:20:31.635Z'), +(13.970413596708804, 45.78351166326739, '2077-11-23T19:32:52.635Z'), +(2.0197652482529276, 48.62475966462268, '2077-11-23T19:37:25.635Z'), +(23.06900309799668, 11.794424101772792, '2077-11-23T19:52:46.635Z'), +(0.4965687152723895, 15.88967887083441, '2077-11-23T20:01:15.635Z'), +(17.463569782933856, 38.59212785748165, '2077-11-23T20:11:38.635Z'), +(4.892587453766559, 5.778274216103057, '2077-11-23T20:24:24.635Z'), +(10.945639232384872, 32.09470359462336, '2077-11-23T20:34:18.635Z'), +(22.919216623885692, 37.0231479788688, '2077-11-23T20:39:04.635Z'), +(17.33490090887941, 38.19802205789826, '2077-11-23T20:41:10.635Z'), +(1.0938666221495017, 41.80078792817223, '2077-11-23T20:47:19.635Z'), +(15.914071531178006, 39.975378586904675, '2077-11-23T20:52:51.635Z'), +(1.0228377636718866, 14.474866780781875, '2077-11-23T21:03:40.635Z'), +(15.267289826347119, 5.520879613883868, '2077-11-23T21:09:52.635Z'), +(12.441416318868303, 23.09585746066675, '2077-11-23T21:16:16.635Z'), +(11.899031304344419, 40.41781714506444, '2077-11-23T21:22:32.635Z'), +(10.685826288077243, 22.910241865948418, '2077-11-23T21:28:54.635Z'), +(5.325730656245754, 16.911202409308498, '2077-11-23T21:31:51.635Z'), +(10.585208994777048, 6.975233425564935, '2077-11-23T21:35:59.635Z'), +(21.170801323927584, 0.7163315080821827, '2077-11-23T21:40:29.635Z'), +(17.37991493152537, 0.9115856460531758, '2077-11-23T21:41:53.635Z'), +(21.60588436788363, 14.746394458798047, '2077-11-23T21:46:57.635Z'), +(20.657109608369336, 5.625481601147141, '2077-11-23T21:50:07.635Z'), +(21.07749888233607, 17.037706863440935, '2077-11-23T21:54:04.635Z'), +(5.8658422107026, 40.72116401348282, '2077-11-23T22:04:16.635Z'), +(7.218298830721681, 14.528313120246152, '2077-11-23T22:13:55.635Z'), +(9.804974846036737, 44.839864136541415, '2077-11-23T22:25:03.635Z'), +(9.157170955700597, 14.594474217745397, '2077-11-23T22:36:06.635Z'), +(11.28452126647205, 16.894941444590614, '2077-11-23T22:37:15.635Z'), +(18.688502643102527, 42.466017325631384, '2077-11-23T22:46:47.635Z'), +(16.852297714589607, 34.70024606986821, '2077-11-23T22:49:36.635Z'), +(15.873785999275038, 34.59586407822705, '2077-11-23T22:49:57.635Z'), +(16.850609857555582, 5.4384563831566695, '2077-11-23T23:00:18.635Z'), +(0.2569075080687484, 29.734330612183854, '2077-11-23T23:11:05.635Z'), +(14.207560309969356, 36.920595841976365, '2077-11-23T23:16:53.635Z'), +(4.298956006628145, 32.20658873621644, '2077-11-23T23:20:56.635Z'), +(5.2054662113718075, 2.5871107580070998, '2077-11-23T23:31:52.635Z'), +(17.22662371610018, 19.24983083386532, '2077-11-23T23:39:22.635Z'), +(18.504120486624846, 2.5206080458165285, '2077-11-23T23:45:17.635Z'), +(18.7950518080797, 5.366641536821786, '2077-11-23T23:46:17.635Z'), +(6.223525040824289, 21.83459392606689, '2077-11-23T23:53:50.635Z'), +(7.3033273154274045, 49.254046940697535, '2077-11-24T00:03:55.635Z'), +(3.103913378282215, 31.10013151725634, '2077-11-24T00:10:47.635Z'), +(11.707585922397504, 20.954093802564508, '2077-11-24T00:15:41.635Z'), +(15.781210102602536, 13.604668288749385, '2077-11-24T00:18:43.635Z'), +(9.74415272827682, 41.910413289853885, '2077-11-24T00:29:10.635Z'), +(14.23180976076985, 23.717688335683597, '2077-11-24T00:35:57.635Z'), +(13.740518583494808, 25.700778673139308, '2077-11-24T00:36:41.635Z'), +(22.912604453327663, 42.23455579791666, '2077-11-24T00:43:24.635Z'), +(22.32165578297696, 26.51796545401222, '2077-11-24T00:48:46.635Z'), +(11.916664939408658, 19.43606905080585, '2077-11-24T00:53:21.635Z'), +(12.800486946047187, 1.821871531901344, '2077-11-24T00:59:44.635Z'), +(6.525660384425535, 12.812786132554075, '2077-11-24T01:04:22.635Z'), +(8.764821462747156, 27.930148150289202, '2077-11-24T01:09:58.635Z'), +(15.597217043929296, 38.151533167638846, '2077-11-24T01:14:27.635Z'), +(22.983494695001212, 20.988172084178455, '2077-11-24T01:21:02.635Z'), +(7.399687621695717, 38.99733803778153, '2077-11-24T01:29:39.635Z'), +(4.702866654669221, 46.9416848355913, '2077-11-24T01:32:44.635Z'), +(15.609805013425316, 44.18195623418712, '2077-11-24T01:36:53.635Z'), +(2.58261665402881, 7.9403063770057525, '2077-11-24T01:50:57.635Z'), +(5.509261880460764, 38.48845256407645, '2077-11-24T02:02:17.635Z'), +(11.41026994142664, 47.91069072764231, '2077-11-24T02:06:22.635Z'), +(16.227175974620103, 45.15025286025393, '2077-11-24T02:08:24.635Z'), +(10.566796116583548, 7.609050602728628, '2077-11-24T02:22:04.635Z'), +(22.789591149124156, 40.35023924033714, '2077-11-24T02:34:30.635Z'), +(10.603802225537903, 13.78870952411062, '2077-11-24T02:44:55.635Z'), +(14.396081697935486, 5.122352370320897, '2077-11-24T02:48:21.635Z'), +(6.975646897267631, 6.876129530789395, '2077-11-24T02:51:10.635Z'), +(5.49381828279247, 16.697568144035028, '2077-11-24T02:54:49.635Z'), +(15.769605145337028, 20.36709470681698, '2077-11-24T02:58:51.635Z'), +(19.088932167739245, 23.69522420345236, '2077-11-24T03:00:33.635Z'), +(14.596648766239047, 22.544051810526465, '2077-11-24T03:02:15.635Z'), +(10.209420523547559, 14.176364003399208, '2077-11-24T03:05:41.635Z'), +(15.270437133777621, 8.943456336816245, '2077-11-24T03:08:20.635Z'), +(12.363781275518651, 45.074002138850865, '2077-11-24T03:21:22.635Z'), +(20.582627674898024, 35.03395375032169, '2077-11-24T03:26:03.635Z'), +(14.050388002553174, 10.901392023777616, '2077-11-24T03:34:54.635Z'), +(9.560312813200733, 6.502081432306652, '2077-11-24T03:37:12.635Z'), +(22.843579861459173, 19.14567252607335, '2077-11-24T03:43:51.635Z'), +(18.9329590757633, 10.703307427019285, '2077-11-24T03:47:06.635Z'), +(5.370350165754612, 21.584590251778724, '2077-11-24T03:53:28.635Z'), +(20.181636252491348, 3.668130433712427, '2077-11-24T04:01:56.635Z'), +(12.653696549314878, 23.815478583907094, '2077-11-24T04:09:36.635Z'), +(17.615730852445733, 25.991585865758047, '2077-11-24T04:11:35.635Z'), +(20.367236019477318, 44.85823295120836, '2077-11-24T04:18:16.635Z'), +(18.664568169214157, 17.56892569373457, '2077-11-24T04:27:48.635Z'), +(15.288593693606764, 43.94978655644265, '2077-11-24T04:37:13.635Z'), +(2.1444237088037874, 49.96906774268914, '2077-11-24T04:42:33.635Z'), +(18.151968098699264, 43.71350796390343, '2077-11-24T04:48:54.635Z'), +(7.663391414340375, 49.89702114632354, '2077-11-24T04:53:22.635Z'), +(8.224910911447598, 0.945490622361716, '2077-11-24T05:11:19.635Z'), +(15.286798380574655, 31.919667861914522, '2077-11-24T05:22:50.635Z'), +(6.2237741587527475, 15.463171631688532, '2077-11-24T05:29:41.635Z'), +(1.1747269107692933, 37.2424009308568, '2077-11-24T05:37:57.635Z'), +(21.401909170922984, 20.310610956708135, '2077-11-24T05:47:37.635Z'), +(5.533852719742652, 49.46017379827026, '2077-11-24T05:59:37.635Z'), +(18.702680750085186, 11.552937014527291, '2077-11-24T06:14:09.635Z'), +(7.403195155447574, 23.108358680829593, '2077-11-24T06:20:03.635Z'), +(5.026701701560778, 39.61430972588538, '2077-11-24T06:26:11.635Z'), +(11.962727003566114, 43.60508009618572, '2077-11-24T06:29:08.635Z'), +(5.629647692023889, 18.7827018814206, '2077-11-24T06:38:31.635Z'), +(18.10447650025012, 37.01960891561686, '2077-11-24T06:46:34.635Z'), +(16.77453719462923, 45.676037497754706, '2077-11-24T06:49:40.635Z'), +(12.318265017411594, 41.57580839371383, '2077-11-24T06:51:52.635Z'), +(7.062595471929911, 43.424964284857424, '2077-11-24T06:53:55.635Z'), +(13.932556191495634, 21.370014454088864, '2077-11-24T07:02:20.635Z'), +(16.352025576339994, 12.818484398336565, '2077-11-24T07:05:31.635Z'), +(22.187187431615133, 46.704821077602226, '2077-11-24T07:17:32.635Z'), +(16.33135263435668, 33.48762238336887, '2077-11-24T07:22:38.635Z'), +(1.2865194957986565, 47.29396867136977, '2077-11-24T07:30:09.635Z'), +(18.196506550652778, 26.52224456864797, '2077-11-24T07:39:58.635Z'), +(19.726355771179094, 44.538193601918024, '2077-11-24T07:46:18.635Z'), +(21.33411723461464, 35.0898421281412, '2077-11-24T07:49:37.635Z'), +(14.914530696147445, 29.070464218783147, '2077-11-24T07:52:48.635Z'), +(0.7169894141754319, 31.951210357592775, '2077-11-24T07:58:10.635Z'), +(19.86217226134602, 25.294136339015154, '2077-11-24T08:05:39.635Z'), +(16.488102523657542, 16.565696875450705, '2077-11-24T08:08:58.635Z'), +(19.8033741042247, 46.59799778049545, '2077-11-24T08:19:36.635Z'), +(9.791608557561009, 22.053484716031523, '2077-11-24T08:29:07.635Z'), +(14.550097701658524, 43.29030754704901, '2077-11-24T08:37:00.635Z'), +(5.940059996703349, 28.197334734177993, '2077-11-24T08:43:21.635Z'), +(19.446691006956588, 41.862564699327955, '2077-11-24T08:50:22.635Z'), +(9.206676126737026, 33.06641668898277, '2077-11-24T08:55:18.635Z'), +(12.832613821452401, 8.042258580799635, '2077-11-24T09:04:29.635Z'), +(20.09091358836975, 8.21224165018067, '2077-11-24T09:07:10.635Z'), +(16.72972775781437, 47.63546786909446, '2077-11-24T09:21:03.635Z'), +(11.4924029920382, 7.877666907644279, '2077-11-24T09:35:26.635Z'), +(7.522948094556073, 6.427770529084387, '2077-11-24T09:36:59.635Z'), +(1.2788897295428177, 46.09106572022067, '2077-11-24T09:51:48.635Z'), +(23.012149257627858, 42.57416426509491, '2077-11-24T09:59:57.635Z'), +(20.009969194018662, 2.3274563922450326, '2077-11-24T10:13:49.635Z'), +(11.443161589911206, 7.188102537509449, '2077-11-24T10:17:26.635Z'), +(18.06513393513675, 47.56959876056915, '2077-11-24T10:32:05.635Z'), +(7.343970392627547, 29.13926353295327, '2077-11-24T10:39:49.635Z'), +(21.596806699699655, 35.52034198176643, '2077-11-24T10:45:34.635Z'), +(10.169330079558895, 4.940288240241728, '2077-11-24T10:57:13.635Z'), +(5.7092524190067895, 10.537634751555164, '2077-11-24T10:59:51.635Z'), +(12.171923599258184, 8.95864400924317, '2077-11-24T11:02:18.635Z'), +(15.653286074964049, 9.49910032148942, '2077-11-24T11:03:36.635Z'), +(2.495099260406702, 29.891959631582992, '2077-11-24T11:12:30.635Z'), +(8.864957678182137, 37.02468055349768, '2077-11-24T11:16:02.635Z'), +(2.5284349572541602, 45.95547039499138, '2077-11-24T11:20:04.635Z'), +(13.28431376359326, 32.68396590244808, '2077-11-24T11:26:21.635Z'), +(15.328411804807773, 44.19138512251543, '2077-11-24T11:30:33.635Z'), +(20.74509483845561, 5.953726533621955, '2077-11-24T11:44:08.635Z'), +(15.848752242105059, 23.748866968352296, '2077-11-24T11:50:38.635Z'), +(0.34193462996603347, 43.97252142558516, '2077-11-24T12:00:00.635Z'), +(2.0304500974262085, 29.751726383429702, '2077-11-24T12:05:18.635Z'), +(4.319213181672795, 29.19809138290436, '2077-11-24T12:06:10.635Z'), +(22.09047228644731, 28.49642362623288, '2077-11-24T12:12:45.635Z'), +(18.87812551394545, 40.51095470919888, '2077-11-24T12:17:05.635Z'), +(12.134117263559762, 4.819803662585157, '2077-11-24T12:30:02.635Z'), +(4.212380839192945, 6.573137033643207, '2077-11-24T12:33:02.635Z'), +(1.7220250000691608, 41.4180970357684, '2077-11-24T12:45:57.635Z'), +(8.083248353786223, 27.03112506409298, '2077-11-24T12:51:45.635Z'), +(5.449340559060508, 9.378743746047515, '2077-11-24T12:58:19.635Z'), +(9.418807650374045, 39.66001907302947, '2077-11-24T13:09:32.635Z'), +(7.208991609989139, 19.325185658395597, '2077-11-24T13:17:02.635Z'), +(16.083841381017344, 45.88824028759021, '2077-11-24T13:27:12.635Z'), +(22.753776394846675, 41.84843990048645, '2077-11-24T13:30:02.635Z'), +(16.416297692673417, 44.40138188868936, '2077-11-24T13:32:32.635Z'), +(23.267337607232964, 44.72554645927981, '2077-11-24T13:35:04.635Z'), +(13.178032329741955, 45.93255388930436, '2077-11-24T13:38:49.635Z'), +(2.393142470309974, 28.408235602433383, '2077-11-24T13:46:23.635Z'), +(13.539937846480012, 4.982849328670532, '2077-11-24T13:55:54.635Z'), +(12.676243091159742, 37.884401350270835, '2077-11-24T14:07:46.635Z'), +(9.123724356281741, 19.00781619447783, '2077-11-24T14:14:45.635Z'), +(21.283908598093987, 11.43009483608403, '2077-11-24T14:20:00.635Z'), +(21.51380785028473, 12.631973258605893, '2077-11-24T14:20:25.635Z'), +(9.988846296446274, 24.619382171661137, '2077-11-24T14:26:27.635Z'), +(10.669370847460211, 31.18252937368761, '2077-11-24T14:28:51.635Z'), +(10.313000909082522, 33.21417427474926, '2077-11-24T14:29:36.635Z'), +(9.507011661425038, 50.044590156434474, '2077-11-24T14:35:45.635Z'), +(19.0136296878491, 11.954343651953078, '2077-11-24T14:49:50.635Z'), +(7.029739802322114, 14.096892132081436, '2077-11-24T14:54:20.635Z'), +(11.678328212203127, 13.160306349908444, '2077-11-24T14:56:05.635Z'), +(23.277945770372625, 26.947886262229677, '2077-11-24T15:02:34.635Z'), +(22.489287144936778, 38.537708329598715, '2077-11-24T15:06:32.635Z'), +(17.40017369339508, 13.660817887173105, '2077-11-24T15:15:23.635Z'), +(8.895428077977202, 40.275297608187074, '2077-11-24T15:25:28.635Z'), +(4.232394132566103, 5.443533017705449, '2077-11-24T15:38:24.635Z'), +(18.99128364883042, 8.623238654539156, '2077-11-24T15:43:59.635Z'), +(4.860130255544895, 2.0153988745530107, '2077-11-24T15:49:44.635Z'), +(18.475461504113262, 43.49350083078101, '2077-11-24T16:05:33.635Z'), +(11.718822071880622, 38.988993083368456, '2077-11-24T16:08:31.635Z'), +(18.47193529354893, 18.163521480407567, '2077-11-24T16:16:22.635Z'), +(0.4793712835691613, 41.74543136727937, '2077-11-24T16:27:14.635Z'), +(7.6211680126129355, 44.65132256228839, '2077-11-24T16:30:05.635Z'), +(21.284656926443283, 36.8361500291621, '2077-11-24T16:35:52.635Z'), +(8.934744254832315, 7.377287973529514, '2077-11-24T16:47:19.635Z'), +(22.61636707141043, 27.227299446690584, '2077-11-24T16:56:00.635Z'), +(10.765923484618547, 40.23439653510987, '2077-11-24T17:02:21.635Z'), +(21.726009770860742, 47.893411028008465, '2077-11-24T17:07:14.635Z'), +(19.766224008889715, 9.685121345446014, '2077-11-24T17:20:27.635Z'), +(10.647198271792968, 43.91761214501088, '2077-11-24T17:33:07.635Z'), +(1.3736794034371773, 16.9704707880157, '2077-11-24T17:43:36.635Z'), +(2.5065154245196655, 5.6978152457564795, '2077-11-24T17:47:47.635Z'), +(14.161428288761991, 12.934214553025143, '2077-11-24T17:52:51.635Z'), +(9.039926606188189, 46.59045075876346, '2077-11-24T18:05:12.635Z'), +(17.688461601932364, 17.91429500028144, '2077-11-24T18:16:00.635Z'), +(15.36281869477154, 4.335262802473801, '2077-11-24T18:20:54.635Z'), +(18.757760846453422, 11.780127857451289, '2077-11-24T18:23:49.635Z'), +(16.18038494290714, 21.563741438221165, '2077-11-24T18:27:24.635Z'), +(1.597143882677946, 38.03506491033626, '2077-11-24T18:35:29.635Z'), +(21.922325819366755, 19.550807495717798, '2077-11-24T18:45:32.635Z'), +(2.8679793593132787, 7.022907432074761, '2077-11-24T18:53:54.635Z'), +(5.786832793884989, 45.49360778693934, '2077-11-24T19:08:09.635Z'), +(22.080010137410962, 20.99809213923101, '2077-11-24T19:18:48.635Z'), +(11.271797521133466, 48.301017077638114, '2077-11-24T19:29:15.635Z'), +(10.497842440230059, 49.40511381062922, '2077-11-24T19:29:44.635Z'), +(19.050503222867476, 36.943992816297715, '2077-11-24T19:35:12.635Z'), +(19.23102233661471, 37.29154213884154, '2077-11-24T19:35:20.635Z'), +(9.642363075567411, 43.194584837794245, '2077-11-24T19:39:28.635Z'), +(21.97776173798827, 1.7302325113967592, '2077-11-24T19:54:53.635Z'), +(8.473794551384, 31.26024118083905, '2077-11-24T20:06:32.635Z'), +(13.03320765887124, 44.528167398972755, '2077-11-24T20:11:39.635Z'), +(7.939027207816323, 18.841091487966136, '2077-11-24T20:21:11.635Z'), +(4.725522228615297, 21.09590624145204, '2077-11-24T20:22:38.635Z'), +(4.403978045527275, 41.54116972863888, '2077-11-24T20:30:11.635Z'), +(23.119545958839577, 49.75458387518755, '2077-11-24T20:37:43.635Z'), +(10.256584573597733, 11.00230129090514, '2077-11-24T20:52:13.635Z'), +(2.050372744776094, 27.88421836321806, '2077-11-24T20:59:08.635Z'), +(17.05468182655977, 20.612365998258458, '2077-11-24T21:05:17.635Z'), +(19.40212713540769, 47.839428843305846, '2077-11-24T21:14:53.635Z'), +(7.4625200603040325, 15.73801880279019, '2077-11-24T21:27:14.635Z'), +(23.375024680335986, 45.58991964419782, '2077-11-24T21:39:22.635Z'), +(14.672253692879734, 2.4501312420818997, '2077-11-24T21:54:45.635Z'), +(20.80280194834512, 17.731998174088744, '2077-11-24T22:00:35.635Z'), +(16.74616851227787, 15.66863937282761, '2077-11-24T22:02:15.635Z'), +(16.98572052791074, 40.683265189701025, '2077-11-24T22:11:07.635Z'), +(9.535348235154625, 33.07030478504185, '2077-11-24T22:15:00.635Z'), +(15.816672935794898, 43.51514489629657, '2077-11-24T22:19:26.635Z'), +(13.187355131519947, 23.33016160794269, '2077-11-24T22:26:44.635Z'), +(7.944527684876182, 4.132370873624971, '2077-11-24T22:33:59.635Z'), +(4.799848488392728, 9.954718896227877, '2077-11-24T22:36:25.635Z'), +(16.03362173882576, 1.3259416011017022, '2077-11-24T22:41:37.635Z'), +(3.079860660440507, 27.180061569761115, '2077-11-24T22:52:11.635Z'), +(9.002522240548792, 26.597093318320386, '2077-11-24T22:54:23.635Z'), +(17.04266742843173, 13.778426827689856, '2077-11-24T22:59:53.635Z'), +(6.632478611281854, 23.195441302710247, '2077-11-24T23:05:01.635Z'), +(2.225731034059661, 39.64790991102998, '2077-11-24T23:11:18.635Z'), +(23.39232884215458, 13.425904229870547, '2077-11-24T23:23:33.635Z'), +(18.18542190256579, 9.241867439436477, '2077-11-24T23:25:57.635Z'), +(6.887864532586031, 46.446671240814396, '2077-11-24T23:40:00.635Z'), +(4.599401558315957, 5.192774221477168, '2077-11-24T23:55:13.635Z'), +(1.8568002588798491, 14.912607808203559, '2077-11-24T23:58:57.635Z'), +(18.332012722722666, 32.85342980198254, '2077-11-25T00:07:53.635Z'), +(3.6678904180356064, 10.596280294028533, '2077-11-25T00:17:36.635Z'), +(17.744937793028313, 19.435812190529504, '2077-11-25T00:23:43.635Z'), +(18.96292116441182, 41.11686272016797, '2077-11-25T00:31:21.635Z'), +(6.388154397954579, 19.208058606187603, '2077-11-25T00:40:31.635Z'), +(0.06484187539876196, 34.457661763866795, '2077-11-25T00:46:37.635Z'), +(14.36181584127902, 20.06292067201116, '2077-11-25T00:54:05.635Z'), +(7.89295951577998, 33.734630542619485, '2077-11-25T00:59:36.635Z'), +(17.796524000697282, 28.53221973313524, '2077-11-25T01:03:43.635Z'), +(15.40601373952173, 4.812811580979772, '2077-11-25T01:12:10.635Z'), +(1.3648269609001629, 33.21102056004898, '2077-11-25T01:23:46.635Z'), +(17.71588474463183, 20.297263922128163, '2077-11-25T01:31:26.635Z'), +(16.520769542609834, 45.98180236327466, '2077-11-25T01:40:32.635Z'), +(10.704601530491699, 38.505102661918464, '2077-11-25T01:43:58.635Z'), +(2.140733794561414, 47.06986084687188, '2077-11-25T01:48:26.635Z'), +(15.852939835101884, 23.04873932724741, '2077-11-25T01:58:34.635Z'), +(14.370766951957288, 15.48079037535965, '2077-11-25T02:01:19.635Z'), +(15.133033288241904, 3.48881672850582, '2077-11-25T02:05:37.635Z'), +(14.870824030179344, 12.670399800351271, '2077-11-25T02:08:54.635Z'), +(22.07419595479287, 19.290907409942275, '2077-11-25T02:12:26.635Z'), +(19.4185558949612, 48.82812120156686, '2077-11-25T02:22:42.635Z'), +(23.32964338556528, 21.068712127920243, '2077-11-25T02:32:22.635Z'), +(11.837795023317474, 25.28039082402201, '2077-11-25T02:36:52.635Z'), +(7.5732644871408095, 24.385001855940725, '2077-11-25T02:38:28.635Z'), +(13.189157259435376, 17.150867385792488, '2077-11-25T02:41:49.635Z'), +(0.4150761935347158, 36.91776616475747, '2077-11-25T02:50:28.635Z'), +(8.877313569711392, 7.808393422453078, '2077-11-25T03:01:39.635Z'), +(10.98388865383956, 11.299349170431219, '2077-11-25T03:03:08.635Z'), +(14.356338100195812, 19.1829912553877, '2077-11-25T03:06:14.635Z'), +(9.557324026827223, 49.81887942398596, '2077-11-25T03:17:28.635Z'), +(4.590035196739969, 49.533689521458406, '2077-11-25T03:19:18.635Z'), +(2.9357172111461014, 4.348273104327356, '2077-11-25T03:36:01.635Z'), +(12.60501068071962, 43.12045582458134, '2077-11-25T03:50:40.635Z'), +(20.618082973894236, 35.71079419032346, '2077-11-25T03:54:37.635Z'), +(12.803706860761165, 18.528964441365886, '2077-11-25T04:01:21.635Z'), +(1.7285989188804938, 4.067920987188037, '2077-11-25T04:08:03.635Z'), +(11.972885674691126, 21.396321772620336, '2077-11-25T04:15:27.635Z'), +(2.0568006175738103, 9.072325191094299, '2077-11-25T04:21:16.635Z'), +(21.90785773489577, 16.37849083938393, '2077-11-25T04:29:04.635Z'), +(11.90632736816337, 7.499467974002633, '2077-11-25T04:33:55.635Z'), +(8.443386886348119, 30.424915269892466, '2077-11-25T04:42:22.635Z'), +(7.7494152935452725, 0.17951894765716814, '2077-11-25T04:53:27.635Z'), +(19.469969612852076, 49.08168223794614, '2077-11-25T05:11:31.635Z'), +(3.327901047562878, 31.555602394929284, '2077-11-25T05:20:14.635Z'), +(6.64137920599034, 27.428435025679438, '2077-11-25T05:22:11.635Z'), +(20.548279898488335, 29.526907410913413, '2077-11-25T05:27:23.635Z'), +(1.2305957312401004, 25.964814607216006, '2077-11-25T05:34:39.635Z'), +(7.288993451476312, 30.295284247340877, '2077-11-25T05:37:24.635Z'), +(17.504719588260826, 12.204987565689853, '2077-11-25T05:44:57.635Z'), +(21.926836914950844, 27.296995014770694, '2077-11-25T05:50:27.635Z'), +(17.18464700895924, 5.16132159247888, '2077-11-25T05:58:22.635Z'), +(4.567791027761247, 46.68775071134517, '2077-11-25T06:14:08.635Z'), +(10.740819395217828, 22.93440665452784, '2077-11-25T06:23:08.635Z'), +(1.570241262234987, 0.6932494126227595, '2077-11-25T06:31:59.635Z'), +(8.940325484990641, 19.699984613394726, '2077-11-25T06:39:30.635Z'), +(15.189974704700056, 42.040965582254366, '2077-11-25T06:47:54.635Z'), +(6.344292526296139, 45.52465985918016, '2077-11-25T06:51:24.635Z'), +(18.072219373851944, 43.678798775579324, '2077-11-25T06:55:47.635Z'), +(6.984529046309871, 10.067868287099621, '2077-11-25T07:08:35.635Z'), +(18.929570191004895, 7.129043922194152, '2077-11-25T07:13:08.635Z'), +(17.87884861689918, 47.419592012174824, '2077-11-25T07:27:16.635Z'), +(6.854130342663041, 50.10612482774249, '2077-11-25T07:31:28.635Z'), +(1.7990936887466578, 30.49803475787712, '2077-11-25T07:38:56.635Z'), +(5.425861810235571, 48.798141784532106, '2077-11-25T07:45:50.635Z'), +(16.613666903007136, 39.66596017048952, '2077-11-25T07:51:08.635Z'), +(7.914190830574492, 25.662928504157815, '2077-11-25T07:57:08.635Z'), +(18.499062367202608, 19.558691977752346, '2077-11-25T08:01:37.635Z'), +(21.886946357976377, 30.924013125067226, '2077-11-25T08:05:45.635Z'), +(15.989993977010075, 7.155803715654432, '2077-11-25T08:14:21.635Z'), +(9.3918355072493, 14.001451131491326, '2077-11-25T08:17:49.635Z'), +(3.4247573105478155, 3.4525015188755326, '2077-11-25T08:22:17.635Z'), +(22.27144389580102, 34.57307594754764, '2077-11-25T08:35:27.635Z'), +(20.731055056703042, 21.834773434140534, '2077-11-25T08:39:52.635Z'), +(14.252632309714974, 35.697398128249944, '2077-11-25T08:45:19.635Z'), +(5.655543512070135, 28.264287549337137, '2077-11-25T08:49:30.635Z'), +(13.676796837714857, 49.09139015007508, '2077-11-25T08:57:39.635Z'), +(16.612345156474007, 10.678468576488862, '2077-11-25T09:11:24.635Z'), +(3.977859416184528, 29.006427859334977, '2077-11-25T09:19:32.635Z'), +(15.503370321616393, 17.091912307259125, '2077-11-25T09:25:37.635Z'), +(10.662415032550411, 17.956068085521007, '2077-11-25T09:27:26.635Z'), +(11.457063028724123, 8.46003590470217, '2077-11-25T09:30:54.635Z'), +(10.04520771569301, 15.559081611559188, '2077-11-25T09:33:32.635Z'), +(17.17398559193528, 5.91844546193011, '2077-11-25T09:37:53.635Z'), +(22.110087456479146, 36.49434289741825, '2077-11-25T09:48:41.635Z'), +(9.815239361085736, 5.33616802247242, '2077-11-25T10:00:39.635Z'), +(5.174522999106251, 15.604247466031419, '2077-11-25T10:04:47.635Z'), +(19.39173158909426, 10.631109857812106, '2077-11-25T10:10:21.635Z'), +(7.335202568007846, 26.320324770235445, '2077-11-25T10:17:32.635Z'), +(4.79888424422583, 29.448068631338877, '2077-11-25T10:19:01.635Z'), +(15.284526382813954, 8.586003093158482, '2077-11-25T10:27:33.635Z'), +(13.89268032445613, 31.933044800793986, '2077-11-25T10:35:56.635Z'), +(8.79343994348913, 40.52156822444259, '2077-11-25T10:39:34.635Z'), +(0.8124313579775528, 3.027981103767327, '2077-11-25T10:53:42.635Z'), +(16.197853086807573, 2.972303276461327, '2077-11-25T10:59:24.635Z'), +(14.34743860752785, 35.01173577311714, '2077-11-25T11:10:51.635Z'), +(14.509786809527847, 27.26583359195371, '2077-11-25T11:13:37.635Z'), +(2.9568611996030483, 13.59725356221348, '2077-11-25T11:20:11.635Z'), +(14.594494089161412, 47.57478420842422, '2077-11-25T11:33:19.635Z'), +(11.812947160990262, 15.659881613047462, '2077-11-25T11:44:52.635Z'), +(6.90945089252365, 1.0726480064014603, '2077-11-25T11:50:30.635Z'), +(8.016113699194001, 3.717858348867155, '2077-11-25T11:51:33.635Z'), +(21.872382170464817, 3.137464183925399, '2077-11-25T11:56:41.635Z'), +(2.4829197983818805, 41.07605764159998, '2077-11-25T12:12:07.635Z'), +(15.537739702817458, 12.082094185600267, '2077-11-25T12:23:45.635Z'), +(5.176217662976883, 17.15727451756963, '2077-11-25T12:28:00.635Z'), +(2.3250008537487834, 13.209955996528628, '2077-11-25T12:29:48.635Z'), +(16.779385111463995, 15.53601797967491, '2077-11-25T12:35:13.635Z'), +(9.60677439719029, 44.51354194469241, '2077-11-25T12:45:59.635Z'), +(15.374190416261245, 23.304573718144177, '2077-11-25T12:53:56.635Z'), +(7.834560429017565, 30.658934998510862, '2077-11-25T12:57:47.635Z'), +(22.31259357797248, 46.63134580111179, '2077-11-25T13:05:36.635Z'), +(22.2456363947589, 46.81367062440514, '2077-11-25T13:05:40.635Z'), +(4.5490258868285265, 8.643101723829455, '2077-11-25T13:20:50.635Z'), +(22.267988074289665, 18.579975580032478, '2077-11-25T13:28:18.635Z'), +(12.876059220841066, 9.993445451014242, '2077-11-25T13:32:54.635Z'), +(19.27090900487982, 8.466755439158062, '2077-11-25T13:35:19.635Z'), +(4.749118602890806, 38.787302466504556, '2077-11-25T13:47:31.635Z'), +(11.86013263510627, 7.266547881418357, '2077-11-25T13:59:21.635Z'), +(19.70297965451957, 39.559752831548984, '2077-11-25T14:11:12.635Z'), +(5.441499715188817, 20.51828984360375, '2077-11-25T14:19:51.635Z'), +(14.975333381719828, 5.696648159006028, '2077-11-25T14:26:18.635Z'), +(21.41810898357123, 12.914458925025304, '2077-11-25T14:29:47.635Z'), +(19.80229927757395, 16.410927405952734, '2077-11-25T14:31:08.635Z'), +(6.992568558437815, 16.813525368300265, '2077-11-25T14:35:53.635Z'), +(0.2904655292850756, 4.2898253139271105, '2077-11-25T14:41:08.635Z'), +(14.089146752497125, 23.333059099389423, '2077-11-25T14:49:47.635Z'), +(13.600896155182278, 11.863361362459766, '2077-11-25T14:53:54.635Z'), +(3.170218046019533, 44.43446819830667, '2077-11-25T15:06:26.635Z'), +(0.03860595606824169, 8.152033227247948, '2077-11-25T15:19:55.635Z'), +(2.0320157530552563, 28.900781049234457, '2077-11-25T15:27:38.635Z'), +(12.002003555311562, 41.1444028812958, '2077-11-25T15:33:27.635Z'), +(10.475966884575511, 7.53993612255121, '2077-11-25T15:45:40.635Z'), +(13.768234379690435, 2.3422649252245784, '2077-11-25T15:47:54.635Z'), +(2.374976755676857, 34.899988148590815, '2077-11-25T16:00:32.635Z'), +(8.086802333203828, 11.461228731071532, '2077-11-25T16:09:26.635Z'), +(6.592567272675392, 23.540537895821487, '2077-11-25T16:13:54.635Z'), +(13.907275191865354, 48.52001856116479, '2077-11-25T16:23:23.635Z'), +(9.364174115450433, 22.80902155918812, '2077-11-25T16:32:51.635Z'), +(4.490528882382114, 7.632068640378655, '2077-11-25T16:38:43.635Z'), +(7.279058336936814, 16.9906984514552, '2077-11-25T16:42:19.635Z'), +(22.22046871564623, 48.011435614741806, '2077-11-25T16:54:41.635Z'), +(17.72214890505993, 7.4004162173564785, '2077-11-25T17:08:53.635Z'), +(2.1998523030065527, 23.782541555199934, '2077-11-25T17:17:10.635Z'), +(13.65689483415569, 20.094541171000195, '2077-11-25T17:21:37.635Z'), +(6.356848276499916, 7.4204232909228525, '2077-11-25T17:26:58.635Z'), +(15.583827473779547, 12.708832234092194, '2077-11-25T17:30:53.635Z'), +(2.211123088233375, 21.908430175036017, '2077-11-25T17:36:52.635Z'), +(22.91522111089401, 16.123269690998832, '2077-11-25T17:44:49.635Z'), +(23.504556950480463, 23.721988778711435, '2077-11-25T17:47:24.635Z'), +(21.855923269169963, 11.355388033480805, '2077-11-25T17:51:40.635Z'), +(4.1646611456019285, 5.8338201183422616, '2077-11-25T17:58:31.635Z'), +(3.7025448565492556, 2.9156151238321075, '2077-11-25T17:59:36.635Z'), +(19.898873397857248, 45.54288926277742, '2077-11-25T18:16:07.635Z'), +(22.808526936720476, 10.005820896479403, '2077-11-25T18:28:24.635Z'), +(2.651273624952202, 9.785434267541229, '2077-11-25T18:35:52.635Z'), +(0.886918994894461, 27.79486374331354, '2077-11-25T18:42:34.635Z'), +(4.8787788223284085, 49.77582402508817, '2077-11-25T18:50:50.635Z'), +(20.211094023834345, 16.693068257092484, '2077-11-25T19:04:02.635Z'), +(12.836123796558162, 46.32897774352714, '2077-11-25T19:14:53.635Z'), +(22.72143821775151, 4.7714457617020525, '2077-11-25T19:29:56.635Z'), +(1.7503968266879013, 46.91716949836523, '2077-11-25T19:46:57.635Z'), +(1.0681190494510375, 41.399483964050006, '2077-11-25T19:49:00.635Z'), +(8.128359372097783, 47.523549611434795, '2077-11-25T19:52:27.635Z'), +(0.642740553278263, 37.80794807543682, '2077-11-25T19:56:59.635Z'), +(23.203458189379397, 18.390653520641802, '2077-11-25T20:07:52.635Z'), +(17.45112838238831, 2.50828370490027, '2077-11-25T20:13:46.635Z'), +(4.561772081200726, 12.412939510285016, '2077-11-25T20:19:44.635Z'), +(11.608757052462604, 45.27141898205703, '2077-11-25T20:32:03.635Z'), +(22.250926282693353, 13.303015104093872, '2077-11-25T20:44:01.635Z'), +(13.825943163143213, 15.680161136147037, '2077-11-25T20:47:14.635Z'), +(6.894843674636477, 42.8159688522075, '2077-11-25T20:57:26.635Z'), +(19.54736469652267, 18.92548653718339, '2077-11-25T21:07:13.635Z'), +(8.918251182970284, 1.6431268136006423, '2077-11-25T21:14:33.635Z'), +(7.520884362131635, 33.13582328148022, '2077-11-25T21:26:06.635Z'), +(22.96175474941504, 29.958217147689894, '2077-11-25T21:31:56.635Z'), +(2.8032443998011307, 20.932912557206222, '2077-11-25T21:40:04.635Z'), +(20.26536847595994, 24.666047150401948, '2077-11-25T21:46:40.635Z'), +(2.604921922053242, 48.95747386122852, '2077-11-25T21:57:37.635Z'), +(10.38768913489584, 34.00106604081106, '2077-11-25T22:03:49.635Z'), +(9.528238797046422, 14.7024483481634, '2077-11-25T22:10:52.635Z'), +(17.149062317141432, 19.704026614483574, '2077-11-25T22:14:13.635Z'), +(14.281555506924219, 16.361694633735823, '2077-11-25T22:15:48.635Z'), +(4.273543611689737, 19.19962812382832, '2077-11-25T22:19:39.635Z'), +(19.006934511501544, 16.757792177537947, '2077-11-25T22:25:10.635Z'), +(2.324630262239779, 31.69001530968473, '2077-11-25T22:33:23.635Z'), +(1.5782614017271117, 40.10152421942412, '2077-11-25T22:36:30.635Z'), +(21.17677101104573, 15.278657165978027, '2077-11-25T22:48:02.635Z'), +(7.444086123314204, 25.682068703348786, '2077-11-25T22:54:20.635Z'), +(17.941344638163898, 27.637002106881628, '2077-11-25T22:58:17.635Z'), +(1.8777581040409537, 0.7569092179120726, '2077-11-25T23:09:43.635Z'), +(20.767016597828206, 44.93126076708095, '2077-11-25T23:27:08.635Z'), +(16.114531072955035, 29.741845687494898, '2077-11-25T23:32:44.635Z'), +(7.492860971775847, 7.550289936625107, '2077-11-25T23:41:23.635Z'), +(23.047412091687992, 44.05334637739335, '2077-11-25T23:55:35.635Z'), +(15.195684874061177, 31.215852226057528, '2077-11-26T00:00:56.635Z'), +(17.748822157592247, 7.939097863117064, '2077-11-26T00:09:15.635Z'), +(20.85825605057469, 4.734016372327454, '2077-11-26T00:10:51.635Z'), +(10.37432022396968, 0.7400933076740236, '2077-11-26T00:14:59.635Z'), +(6.914533565838776, 2.489820691262117, '2077-11-26T00:16:25.635Z'), +(17.168653217075878, 33.20713418150831, '2077-11-26T00:28:09.635Z'), +(4.725288834646573, 26.96286989417475, '2077-11-26T00:33:17.635Z'), +(0.7908983256227565, 27.58838956256732, '2077-11-26T00:34:45.635Z'), +(22.789585002136718, 22.76428505472989, '2077-11-26T00:43:05.635Z'), +(19.322153982756166, 29.844452811267132, '2077-11-26T00:45:50.635Z'), +(23.49635420194338, 17.990362031207834, '2077-11-26T00:50:12.635Z'), +(15.490695192782773, 50.27050276338393, '2077-11-26T01:01:50.635Z'), +(5.4831796996500435, 49.647030347284094, '2077-11-26T01:05:32.635Z'), +(2.4214792057600434, 31.85208031882281, '2077-11-26T01:12:12.635Z'), +(16.181656078967016, 10.507712630975368, '2077-11-26T01:21:30.635Z'), +(13.000852313742893, 5.7611277157542755, '2077-11-26T01:23:34.635Z'), +(19.4282700124721, 42.78855768469259, '2077-11-26T01:36:55.635Z'), +(18.796607018778257, 46.27563964979381, '2077-11-26T01:38:09.635Z'), +(16.195715247260942, 33.65744178057865, '2077-11-26T01:42:42.635Z'), +(11.35246669971089, 40.70049940886354, '2077-11-26T01:45:48.635Z'), +(7.487464255531402, 16.372353168688715, '2077-11-26T01:54:48.635Z'), +(13.325555347451484, 20.616424524532434, '2077-11-26T01:57:27.635Z'), +(11.936317963412332, 48.10342362333183, '2077-11-26T02:07:23.635Z'), +(10.447524159249575, 45.57899241116962, '2077-11-26T02:08:27.635Z'), +(19.63318615139152, 48.08384632066553, '2077-11-26T02:11:58.635Z'), +(8.945096689545169, 23.006370308698703, '2077-11-26T02:21:47.635Z'), +(15.342331461528213, 7.609892312516337, '2077-11-26T02:27:50.635Z'), +(2.9790023180216822, 27.104244270971936, '2077-11-26T02:36:17.635Z'), +(11.2306402433023, 25.249281865836398, '2077-11-26T02:39:25.635Z'), +(20.979050044306707, 5.191002106991584, '2077-11-26T02:47:24.635Z'), +(1.6774973641449946, 40.8759184730523, '2077-11-26T03:02:08.635Z'), +(6.275472421333661, 44.858099111519635, '2077-11-26T03:04:23.635Z'), +(15.370331022755122, 29.16043910800434, '2077-11-26T03:11:00.635Z'), +(19.112698220520226, 24.626058664657304, '2077-11-26T03:13:07.635Z'), +(0.8604330211402982, 1.5220232374298732, '2077-11-26T03:23:53.635Z'), +(16.67303242733479, 22.142730288299468, '2077-11-26T03:33:25.635Z'), +(0.4937797684047717, 49.44999568330704, '2077-11-26T03:45:03.635Z'), +(7.734179709148481, 21.537835950662128, '2077-11-26T03:55:42.635Z'), +(16.837044053696527, 31.437945533606307, '2077-11-26T04:00:37.635Z'), +(8.601044515723402, 30.421779397624935, '2077-11-26T04:03:41.635Z'), +(1.2719393631095688, 9.778050204946005, '2077-11-26T04:11:46.635Z'), +(4.795089976453815, 7.367381104932829, '2077-11-26T04:13:20.635Z'), +(12.594096844917464, 10.431408271215194, '2077-11-26T04:16:26.635Z'), +(4.214540207861604, 18.12752718570196, '2077-11-26T04:20:37.635Z'), +(22.677582225218682, 8.795272403247912, '2077-11-26T04:28:14.635Z'), +(23.260300633478447, 40.9868002035935, '2077-11-26T04:39:11.635Z'), +(8.290098765302037, 47.84003560822232, '2077-11-26T04:45:14.635Z'), +(10.466970224590227, 25.777702869531414, '2077-11-26T04:53:20.635Z'), +(19.64882115903674, 14.274557020658014, '2077-11-26T04:58:40.635Z'), +(2.7136313413110003, 30.795392040139316, '2077-11-26T05:07:20.635Z'), +(14.060837864606382, 13.591068449275511, '2077-11-26T05:14:54.635Z'), +(11.653784618786762, 4.230781020372843, '2077-11-26T05:18:23.635Z'), +(21.90459328313616, 28.11708570984217, '2077-11-26T05:27:39.635Z'), +(15.676992594074378, 26.462186190844896, '2077-11-26T05:30:01.635Z'), +(22.3935018656423, 8.798823926339816, '2077-11-26T05:36:40.635Z'), +(1.904095315438739, 12.921604699498243, '2077-11-26T05:44:24.635Z'), +(6.387047007922401, 45.1364099446142, '2077-11-26T05:56:25.635Z'), +(9.082496205360874, 34.72513461458845, '2077-11-26T06:00:22.635Z'), +(17.42395075526086, 15.86171383522825, '2077-11-26T06:07:50.635Z'), +(21.19401509712161, 43.33264589908291, '2077-11-26T06:17:31.635Z'), +(9.04246167302198, 11.58328091980243, '2077-11-26T06:29:42.635Z'), +(22.22945264447962, 37.11152204817098, '2077-11-26T06:40:00.635Z'), +(4.625085679160302, 36.42389045990586, '2077-11-26T06:46:31.635Z'), +(2.1620901153481182, 13.114515406458567, '2077-11-26T06:55:11.635Z'), +(22.776135274655182, 37.34966294267886, '2077-11-26T07:06:46.635Z'), +(18.206340307250372, 8.639803409365955, '2077-11-26T07:16:51.635Z'), +(8.418207264235242, 19.825495758788886, '2077-11-26T07:22:16.635Z'), +(3.8221759029802316, 39.02136336634509, '2077-11-26T07:29:32.635Z'), +(19.364391816421207, 6.4955749363590565, '2077-11-26T07:42:37.635Z'), +(17.91934827637738, 9.543250288041525, '2077-11-26T07:43:48.635Z'), +(0.4299218813932685, 26.76430692574526, '2077-11-26T07:52:49.635Z'), +(3.698982312636378, 1.5202841604780033, '2077-11-26T08:02:14.635Z'), +(15.402788290210422, 44.42896081435645, '2077-11-26T08:18:28.635Z'), +(4.6941157274306216, 44.35373838084194, '2077-11-26T08:22:26.635Z'), +(3.089703046571889, 19.591244256255198, '2077-11-26T08:31:36.635Z'), +(10.104402468898433, 24.303411642318526, '2077-11-26T08:34:43.635Z'), +(3.7624265674291775, 42.876153457640264, '2077-11-26T08:41:56.635Z'), +(14.351882514016593, 44.98781188051955, '2077-11-26T08:45:56.635Z'), +(5.221423299606483, 46.45648080813282, '2077-11-26T08:49:21.635Z'), +(14.72058294153521, 13.191473761367966, '2077-11-26T09:01:58.635Z'), +(10.083580209312084, 1.8185966578417319, '2077-11-26T09:06:25.635Z'), +(2.870832616933982, 5.118729539773658, '2077-11-26T09:09:21.635Z'), +(23.033263763002964, 33.99915865816247, '2077-11-26T09:22:07.635Z'), +(23.303736642822162, 21.751342287887244, '2077-11-26T09:26:17.635Z'), +(19.187069955051804, 25.43891210918596, '2077-11-26T09:28:16.635Z'), +(6.584484467100066, 39.304283284077144, '2077-11-26T09:35:06.635Z'), +(22.620612977235766, 35.28337895859954, '2077-11-26T09:41:12.635Z'), +(17.963963343354283, 18.486716250962186, '2077-11-26T09:47:17.635Z'), +(16.813698115779673, 0.2975408310848492, '2077-11-26T09:53:43.635Z'), +(15.257581074939559, 27.23796219634103, '2077-11-26T10:03:19.635Z'), +(22.771307927541006, 12.605824906853542, '2077-11-26T10:09:08.635Z'), +(21.43407018612559, 9.128783726872072, '2077-11-26T10:10:25.635Z'), +(22.552917268436993, 38.51917936062787, '2077-11-26T10:20:30.635Z'), +(6.23315247522678, 0.5432251885464962, '2077-11-26T10:35:20.635Z'), +(18.446203424508255, 48.15262654903097, '2077-11-26T10:53:05.635Z'), +(19.26742503257413, 12.615499441737603, '2077-11-26T11:05:31.635Z'), +(11.47308198554654, 18.23572577662312, '2077-11-26T11:09:02.635Z'), +(6.53546407781771, 35.85529889326498, '2077-11-26T11:15:44.635Z'), +(22.51882352710487, 23.982668391905545, '2077-11-26T11:23:01.635Z'), +(17.368694256554555, 33.37268547637487, '2077-11-26T11:26:48.635Z'), +(11.50413207732495, 2.183821564172893, '2077-11-26T11:38:11.635Z'), +(10.136598729063941, 30.887532422698214, '2077-11-26T11:48:38.635Z'), +(10.550965195270088, 50.10699975033914, '2077-11-26T11:55:38.635Z'), +(2.795074473866394, 17.669677951856986, '2077-11-26T12:07:54.635Z'), +(21.966910249307084, 12.326942416216818, '2077-11-26T12:15:15.635Z'), +(16.220767256990257, 35.22505970202803, '2077-11-26T12:23:32.635Z'), +(20.358897288043988, 40.264224126482475, '2077-11-26T12:25:52.635Z'), +(18.840052301728246, 26.798385731114067, '2077-11-26T12:30:36.635Z'), +(23.04155676222317, 16.114582441028507, '2077-11-26T12:34:36.635Z'), +(4.044158083737283, 24.120209843091327, '2077-11-26T12:42:12.635Z'), +(5.401408153899475, 15.677289413543958, '2077-11-26T12:45:21.635Z'), +(10.558886836568838, 46.871615508007686, '2077-11-26T12:56:57.635Z'), +(2.503673899223728, 23.679061940697842, '2077-11-26T13:05:59.635Z'), +(3.922411554751119, 17.39896894173136, '2077-11-26T13:08:21.635Z'), +(6.223265561302236, 13.109633136010538, '2077-11-26T13:10:08.635Z'), +(4.07925588351075, 12.035670823883255, '2077-11-26T13:11:01.635Z'), +(2.2299183013172987, 8.822051912769902, '2077-11-26T13:12:23.635Z'), +(6.990699974832166, 28.22053957373107, '2077-11-26T13:19:45.635Z'), +(20.813821960882073, 42.523617433536685, '2077-11-26T13:27:00.635Z'), +(13.402426205783842, 8.442617051394718, '2077-11-26T13:39:21.635Z'), +(3.5389948022168056, 50.2719544112447, '2077-11-26T13:55:05.635Z'), +(15.358289187699011, 3.8668093053466595, '2077-11-26T14:12:33.635Z'), +(8.010215094439602, 49.87863579061334, '2077-11-26T14:29:26.635Z'), +(22.264485902653586, 37.851602813812164, '2077-11-26T14:36:14.635Z'), +(16.544211077087052, 44.42882469491429, '2077-11-26T14:39:21.635Z'), +(3.518121051870097, 33.64864125730365, '2077-11-26T14:45:34.635Z'), +(9.326154188198151, 6.021325903676278, '2077-11-26T14:55:57.635Z'), +(23.23407807497682, 13.248929940041341, '2077-11-26T15:01:42.635Z'), +(2.756243356741922, 45.65088030198924, '2077-11-26T15:15:34.635Z'), +(22.009056911366397, 25.92923708053453, '2077-11-26T15:25:37.635Z'), +(13.571340193693034, 22.29167874852762, '2077-11-26T15:28:59.635Z'), +(18.42222561210706, 3.7462035352747614, '2077-11-26T15:35:49.635Z'), +(9.566244389740413, 16.233684260764385, '2077-11-26T15:41:22.635Z'), +(7.9975667103137535, 4.419841727475312, '2077-11-26T15:45:43.635Z'), +(3.5345004937140287, 14.681168655077414, '2077-11-26T15:49:50.635Z'), +(4.210700024094546, 44.0673424665791, '2077-11-26T16:00:42.635Z'), +(5.688420268951151, 44.3571827926726, '2077-11-26T16:01:15.635Z'), +(0.17252170399675448, 43.73240717930375, '2077-11-26T16:03:18.635Z'), +(0.46910394683846923, 1.0898400431158124, '2077-11-26T16:19:06.635Z'), +(22.782513803074078, 45.55726286611794, '2077-11-26T16:37:07.635Z'), +(17.844959414704274, 25.999179378896088, '2077-11-26T16:44:09.635Z'), +(16.21007667005493, 27.466075439481823, '2077-11-26T16:44:56.635Z'), +(8.675218711923211, 23.370749308456794, '2077-11-26T16:48:05.635Z'), +(13.091075926124335, 17.242434302993118, '2077-11-26T16:50:50.635Z'), +(12.163115370896472, 24.326491994270224, '2077-11-26T16:53:25.635Z'), +(0.37343595893746995, 13.93723569615297, '2077-11-26T16:59:13.635Z'), +(20.18976439624164, 45.57831484638803, '2077-11-26T17:12:50.635Z'), +(8.610270459786587, 22.076431475106038, '2077-11-26T17:22:16.635Z'), +(16.333096711794433, 39.13644734450335, '2077-11-26T17:29:03.635Z'), +(3.4935063801324207, 5.731214872375618, '2077-11-26T17:42:06.635Z'), +(10.983037996195716, 47.180388914796474, '2077-11-26T17:57:34.635Z'), +(18.34157247440327, 6.501448894378143, '2077-11-26T18:12:22.635Z'), +(8.148452563633791, 29.559379869795812, '2077-11-26T18:21:29.635Z'), +(5.262961189831629, 43.98984507777497, '2077-11-26T18:26:54.635Z'), +(21.22714487339407, 9.714814000510538, '2077-11-26T18:40:33.635Z'), +(19.82908043202609, 20.682704861923423, '2077-11-26T18:44:23.635Z'), +(10.039438272313005, 2.4887751178857545, '2077-11-26T18:51:49.635Z'), +(19.291139928117342, 45.43966033826918, '2077-11-26T19:07:33.635Z'), +(11.505684904262978, 21.61394782099445, '2077-11-26T19:16:31.635Z'), +(15.864180878763785, 38.449543280072575, '2077-11-26T19:22:47.635Z'), +(6.768819095282176, 12.16473658219868, '2077-11-26T19:32:54.635Z'), +(21.28306793869951, 43.08752076335105, '2077-11-26T19:45:12.635Z'), +(7.966279310168566, 34.636512052389456, '2077-11-26T19:50:59.635Z'), +(9.11488959528957, 49.45063538919042, '2077-11-26T19:56:25.635Z'), +(0.21490229918472756, 26.64543776170876, '2077-11-26T20:05:27.635Z'), +(19.495951160857025, 0.2913923416940484, '2077-11-26T20:17:23.635Z'), +(10.732730686120716, 6.5004004834145706, '2077-11-26T20:21:19.635Z'), +(3.7205517142859494, 16.543516950450368, '2077-11-26T20:25:49.635Z'), +(15.38105085778376, 18.455922153418605, '2077-11-26T20:30:11.635Z'), +(12.65007966939831, 43.447622669200214, '2077-11-26T20:39:13.635Z'), +(10.083332117113791, 41.41841157857108, '2077-11-26T20:40:25.635Z'), +(15.32503178664089, 20.81520419100338, '2077-11-26T20:48:06.635Z'), +(2.8430371358339706, 42.90724287379406, '2077-11-26T20:57:23.635Z'), +(3.5054331432072816, 40.50043266744473, '2077-11-26T20:58:18.635Z'), +(17.445952824962607, 2.529944671081287, '2077-11-26T21:13:01.635Z'), +(19.191465697034513, 2.0937944228142444, '2077-11-26T21:13:40.635Z'), +(0.026801779251814865, 29.6988710941399, '2077-11-26T21:25:57.635Z'), +(12.465524579937323, 16.082045741952335, '2077-11-26T21:32:45.635Z'), +(4.545188600689777, 21.454369854013656, '2077-11-26T21:36:17.635Z'), +(17.00208784757866, 22.11031824933092, '2077-11-26T21:40:54.635Z'), +(12.17236942354581, 13.725997476712788, '2077-11-26T21:44:23.635Z'), +(8.871667669021628, 17.82637458383268, '2077-11-26T21:46:18.635Z'), +(0.5130479511262561, 48.0834256318515, '2077-11-26T21:57:53.635Z'), +(8.637171781421369, 9.231136734540673, '2077-11-26T22:12:32.635Z'), +(10.725510919429828, 7.835556956014812, '2077-11-26T22:13:27.635Z'), +(6.398242042341718, 13.946200699231143, '2077-11-26T22:16:12.635Z'), +(2.2894293086946416, 38.837715281038264, '2077-11-26T22:25:31.635Z'), +(3.387990195710659, 26.121496244045304, '2077-11-26T22:30:14.635Z'), +(12.69403861246261, 50.22097593291288, '2077-11-26T22:39:42.635Z'), +(6.462336721670395, 2.141435502173804, '2077-11-26T22:57:23.635Z'), +(11.58510819082432, 49.06936452750553, '2077-11-26T23:14:38.635Z'), +(1.406474833956578, 40.850752969569825, '2077-11-26T23:19:28.635Z'), +(5.920440702264555, 15.75824172325975, '2077-11-26T23:28:53.635Z'), +(17.902714878694816, 19.62513970033763, '2077-11-26T23:33:32.635Z'), +(9.574661813071788, 45.53988114247096, '2077-11-26T23:43:20.635Z'), +(7.840285239894381, 49.76276009742401, '2077-11-26T23:45:00.635Z'), +(10.185787142844795, 25.056508720897593, '2077-11-26T23:54:05.635Z'), +(0.27982092971200667, 13.10231730040183, '2077-11-26T23:59:49.635Z'), +(13.31242315285744, 6.084798343629718, '2077-11-27T00:05:17.635Z'), +(7.097024790411661, 27.262894328446357, '2077-11-27T00:13:20.635Z'), +(16.645810964151714, 48.520184776756956, '2077-11-27T00:21:48.635Z'), +(5.160980604910539, 23.078897466843152, '2077-11-27T00:31:58.635Z'), +(14.962426217293576, 22.73759372213146, '2077-11-27T00:35:36.635Z'), +(8.797757107101852, 6.671205155763303, '2077-11-27T00:41:51.635Z'), +(12.2627090224181, 8.05388551945956, '2077-11-27T00:43:13.635Z'), +(5.907264087438499, 49.32131041116722, '2077-11-27T00:58:29.635Z'), +(15.054147932739975, 11.944414109546333, '2077-11-27T01:12:29.635Z'), +(22.392969782841, 12.424088945658601, '2077-11-27T01:15:12.635Z'), +(13.728562166783044, 17.46109669279865, '2077-11-27T01:18:52.635Z'), +(8.402863706007679, 38.652411556851426, '2077-11-27T01:26:49.635Z'), +(6.9618203775817795, 34.66598898490347, '2077-11-27T01:28:22.635Z'), +(12.14278722462423, 3.132089064672658, '2077-11-27T01:40:02.635Z'), +(13.258125875452425, 17.940449146319764, '2077-11-27T01:45:24.635Z'), +(1.0713483196058184, 23.006239859845845, '2077-11-27T01:50:17.635Z'), +(13.706648494261627, 7.364918553240125, '2077-11-27T01:57:41.635Z'), +(6.099269290340046, 22.948065812056257, '2077-11-27T02:04:01.635Z'), +(17.48958733655093, 5.764351434360964, '2077-11-27T02:11:32.635Z'), +(4.715923472458121, 16.89280561089155, '2077-11-27T02:17:45.635Z'), +(16.2818521590856, 37.80042840958591, '2077-11-27T02:26:28.635Z'), +(9.998978803007466, 37.159485581471564, '2077-11-27T02:28:48.635Z'), +(15.833589220407399, 48.2720082754753, '2077-11-27T02:33:21.635Z'), +(22.567330615033985, 39.48564900890391, '2077-11-27T02:37:18.635Z'), +(19.520075598302522, 47.579187506486875, '2077-11-27T02:40:19.635Z'), +(3.6075418977333613, 16.23197017614143, '2077-11-27T02:53:05.635Z'), +(11.32333777331613, 12.505181275173515, '2077-11-27T02:56:15.635Z'), +(18.861759561503472, 28.59952929879048, '2077-11-27T03:02:38.635Z'), +(19.1133963838499, 1.8238546521251353, '2077-11-27T03:12:00.635Z'), +(15.335797813131467, 24.42181883270707, '2077-11-27T03:20:06.635Z'), +(11.804323220018093, 42.50907961035733, '2077-11-27T03:26:44.635Z'), +(15.573421350800261, 43.72829915312234, '2077-11-27T03:28:11.635Z'), +(15.74912531497589, 47.09899790684453, '2077-11-27T03:29:23.635Z'), +(1.6139826916599853, 22.544843752525548, '2077-11-27T03:39:46.635Z'), +(17.936889029688718, 48.089988309172526, '2077-11-27T03:50:51.635Z'), +(22.281514623518017, 2.1781743675944667, '2077-11-27T04:06:51.635Z'), +(14.692250381613713, 34.06939987398211, '2077-11-27T04:18:22.635Z'), +(10.992213488092409, 43.50631237597084, '2077-11-27T04:22:02.635Z'), +(16.991685407443512, 48.95101324081498, '2077-11-27T04:24:59.635Z'), +(17.238690527776072, 11.228825869266837, '2077-11-27T04:38:19.635Z'), +(0.3434334705830648, 41.566999934609996, '2077-11-27T04:51:01.635Z'), +(18.573568075177146, 11.4460117907669, '2077-11-27T05:03:53.635Z'), +(22.910978715471586, 47.85684917839507, '2077-11-27T05:16:34.635Z'), +(2.675054461077691, 16.778686167552348, '2077-11-27T05:30:00.635Z'), +(4.916393432472066, 39.14888518034468, '2077-11-27T05:38:18.635Z'), +(1.533004722088884, 20.205038414331597, '2077-11-27T05:45:25.635Z'), +(5.568000981079852, 14.616415412666504, '2077-11-27T05:47:58.635Z'), +(20.729602592096853, 6.301234715920446, '2077-11-27T05:54:19.635Z'), +(15.012520093232276, 40.48966756490346, '2077-11-27T06:06:32.635Z'), +(6.745005237740391, 14.346056969306664, '2077-11-27T06:16:31.635Z'), +(9.984571726513973, 42.07794288619163, '2077-11-27T06:26:45.635Z'), +(11.427759636799776, 46.49203121078122, '2077-11-27T06:28:26.635Z'), +(5.382164510001058, 0.9985526175908017, '2077-11-27T06:45:14.635Z'), +(7.71611430741249, 11.390102357613674, '2077-11-27T06:49:09.635Z'), +(17.371872561490388, 23.223294718989777, '2077-11-27T06:54:43.635Z'), +(5.071425146279815, 35.08402855931731, '2077-11-27T07:00:59.635Z'), +(20.35228725068438, 49.79393683441639, '2077-11-27T07:08:44.635Z'), +(4.359317813424071, 11.813169533005372, '2077-11-27T07:23:38.635Z'), +(16.568365191939847, 49.41867584303207, '2077-11-27T07:38:01.635Z'), +(16.07734339118731, 27.365445472046307, '2077-11-27T07:45:51.635Z'), +(6.4117689242933, 24.541753945692445, '2077-11-27T07:49:34.635Z'), +(15.514558276084905, 44.025026546095056, '2077-11-27T07:57:24.635Z'), +(22.58499762656708, 28.13151923089507, '2077-11-27T08:03:32.635Z'), +(13.971005247992645, 11.485216345269261, '2077-11-27T08:10:11.635Z'), +(20.40264518689552, 43.50339110603765, '2077-11-27T08:21:44.635Z'), +(14.21047994305205, 42.54419431129342, '2077-11-27T08:24:03.635Z'), +(0.9356312364461632, 45.59363377984596, '2077-11-27T08:29:05.635Z'), +(21.19196370844479, 33.34741119928553, '2077-11-27T08:37:48.635Z'), +(9.37175767264841, 10.515934558949679, '2077-11-27T08:47:02.635Z'), +(0.3390543936126157, 5.14395849788248, '2077-11-27T08:50:55.635Z'), +(19.063814624937205, 13.110852798999087, '2077-11-27T08:58:26.635Z'), +(20.77429490061382, 39.38004813018743, '2077-11-27T09:07:35.635Z'), +(19.889273560303753, 25.37999024559413, '2077-11-27T09:12:27.635Z'), +(1.1839511797317726, 23.39575752002425, '2077-11-27T09:19:25.635Z'), +(17.39708773747987, 44.1812632091945, '2077-11-27T09:29:05.635Z'), +(21.265596254319583, 42.26852175187664, '2077-11-27T09:30:39.635Z'), +(14.872513344108441, 7.734109060323791, '2077-11-27T09:43:01.635Z'), +(23.133696832181997, 28.186636449483405, '2077-11-27T09:50:47.635Z'), +(7.9568810383864985, 34.401742463198495, '2077-11-27T09:56:49.635Z'), +(15.718827745179444, 23.811377522008055, '2077-11-27T10:01:36.635Z'), +(20.450423517435436, 2.7602159170159037, '2077-11-27T10:09:12.635Z'), +(21.810553111055384, 5.286672935954883, '2077-11-27T10:10:12.635Z'), +(6.368141494976821, 15.193447207547415, '2077-11-27T10:16:56.635Z'), +(7.370890171005809, 18.73795439743628, '2077-11-27T10:18:17.635Z'), +(13.079027230167041, 38.88223351176978, '2077-11-27T10:25:55.635Z'), +(22.315392287496344, 23.16796138687012, '2077-11-27T10:32:25.635Z'), +(7.630190037000773, 29.800606413860844, '2077-11-27T10:38:21.635Z'), +(17.36123267237717, 20.992150390276, '2077-11-27T10:43:09.635Z'), +(13.659482302370362, 1.1739386608563886, '2077-11-27T10:50:21.635Z'), +(3.367748072034173, 13.675263252236412, '2077-11-27T10:56:18.635Z'), +(10.337040738197583, 24.70227809334845, '2077-11-27T11:01:06.635Z'), +(22.707904827650037, 11.666239702213696, '2077-11-27T11:07:36.635Z'), +(8.231201023756155, 27.17289174204259, '2077-11-27T11:15:17.635Z'), +(23.03347486280766, 17.396707257982325, '2077-11-27T11:21:46.635Z'), +(9.94954428805473, 16.298154459071917, '2077-11-27T11:26:37.635Z'), +(3.975026751426065, 18.585330447069826, '2077-11-27T11:28:59.635Z'), +(7.434307142168227, 20.473527198591125, '2077-11-27T11:30:26.635Z'), +(22.05538354773574, 26.791991471230517, '2077-11-27T11:36:18.635Z'), +(15.10647066756705, 8.960506690042212, '2077-11-27T11:43:03.635Z'), +(11.70154971683478, 11.554695668880214, '2077-11-27T11:44:37.635Z'), +(13.682747266493125, 13.709880158321157, '2077-11-27T11:45:41.635Z'), +(21.708189109040074, 34.43785968181898, '2077-11-27T11:53:34.635Z'), +(14.918249059334427, 36.09386277371567, '2077-11-27T11:56:08.635Z'), +(14.272116703361915, 24.298321418075016, '2077-11-27T12:00:22.635Z'), +(0.36454095037105844, 30.442882147052103, '2077-11-27T12:05:59.635Z'), +(4.374904409972915, 39.39955778174993, '2077-11-27T12:09:37.635Z'), +(5.898242187457019, 22.446393990927387, '2077-11-27T12:15:54.635Z'), +(5.769265292967925, 43.46800526767303, '2077-11-27T12:23:39.635Z'), +(8.479476351147849, 7.518945397515704, '2077-11-27T12:36:54.635Z'), +(14.849006426396082, 49.29266118218476, '2077-11-27T12:52:13.635Z'), +(16.155121348025016, 17.473765431464802, '2077-11-27T13:03:34.635Z'), +(1.5249245179690107, 14.925640425767112, '2077-11-27T13:09:04.635Z'), +(5.462651721402314, 12.74577380925163, '2077-11-27T13:10:44.635Z'), +(17.113068148798625, 49.27713974643944, '2077-11-27T13:24:39.635Z'), +(8.83118627480394, 50.08000901490855, '2077-11-27T13:27:43.635Z'), +(9.00989182217073, 35.26658617585307, '2077-11-27T13:33:08.635Z'), +(19.480708114952886, 13.258378555695321, '2077-11-27T13:41:55.635Z'), +(3.7244759321136147, 34.160678315994424, '2077-11-27T13:51:28.635Z'), +(23.282764491720265, 10.719172869510313, '2077-11-27T14:02:33.635Z'), +(8.422473096190355, 36.96071325635591, '2077-11-27T14:13:22.635Z'), +(18.480245054828252, 13.697297822146508, '2077-11-27T14:22:31.635Z'), +(6.014840407006126, 49.42080348566376, '2077-11-27T14:36:13.635Z'), +(3.0207460464882994, 8.836081809453157, '2077-11-27T14:51:14.635Z'), +(11.831623076018326, 8.315180731063464, '2077-11-27T14:54:30.635Z'), +(15.279558073691279, 35.5892300021732, '2077-11-27T15:04:24.635Z'), +(20.176002927707753, 37.95536533888361, '2077-11-27T15:06:23.635Z'), +(16.924250512165568, 20.578926996392234, '2077-11-27T15:12:36.635Z'), +(7.474313577513808, 19.188419648180897, '2077-11-27T15:16:08.635Z'), +(6.092709858815659, 45.01094051619065, '2077-11-27T15:25:38.635Z'), +(8.980693990877334, 19.398493872594802, '2077-11-27T15:35:06.635Z'), +(16.536128517942913, 47.47205893366613, '2077-11-27T15:45:36.635Z'), +(6.884715828449726, 35.437951368073676, '2077-11-27T15:51:14.635Z'), +(6.502430559129541, 11.565351521727163, '2077-11-27T16:00:01.635Z'), +(3.507692546958139, 47.85391914521817, '2077-11-27T16:13:27.635Z'), +(22.057620260978858, 6.240033372454322, '2077-11-27T16:29:54.635Z'), +(5.874069256916163, 16.310210742366863, '2077-11-27T16:36:53.635Z'), +(13.041064823564962, 13.36605125897814, '2077-11-27T16:39:44.635Z'), +(9.593408641802707, 47.6535813909203, '2077-11-27T16:52:15.635Z'), +(20.151044462543762, 20.390532883229856, '2077-11-27T17:02:44.635Z'), +(8.835939766318289, 27.459466698863288, '2077-11-27T17:07:37.635Z'), +(20.447710872512584, 19.070487271412798, '2077-11-27T17:12:51.635Z'), +(15.765134795604927, 18.187143019293792, '2077-11-27T17:14:36.635Z'), +(19.556598883845915, 25.320121112117, '2077-11-27T17:17:29.635Z'), +(16.194755974365748, 37.0328916486134, '2077-11-27T17:21:47.635Z'), +(1.7425665708373097, 33.50142239580902, '2077-11-27T17:27:17.635Z'), +(11.855742157649832, 23.455391724529132, '2077-11-27T17:32:32.635Z'), +(18.108317366195685, 25.52925078382042, '2077-11-27T17:34:58.635Z'), +(10.098514688317774, 36.326578996355025, '2077-11-27T17:39:51.635Z'), +(6.007301588531624, 28.31904294720562, '2077-11-27T17:43:09.635Z'), +(13.781660784263858, 22.0771376226959, '2077-11-27T17:46:49.635Z'), +(2.1599284646947927, 4.886451717435557, '2077-11-27T17:54:26.635Z'), +(6.290039624216448, 0.5795963756130957, '2077-11-27T17:56:38.635Z'), +(16.10347440481715, 15.913518167736406, '2077-11-27T18:03:17.635Z'), +(4.288389477030128, 16.318148417233065, '2077-11-27T18:07:39.635Z'), +(14.360340430057773, 25.85918615950895, '2077-11-27T18:12:45.635Z'), +(2.3970001396320746, 45.07731578154764, '2077-11-27T18:21:03.635Z'), +(15.124301139117106, 22.312867094615033, '2077-11-27T18:30:36.635Z'), +(15.777676213970096, 15.47145238045662, '2077-11-27T18:33:03.635Z'), +(1.2664405110478028, 30.54254643697879, '2077-11-27T18:40:44.635Z'), +(16.876834683876748, 1.0568723184163666, '2077-11-27T18:52:56.635Z'), +(4.490066482202239, 25.187059084219978, '2077-11-27T19:02:49.635Z'), +(15.471540875301708, 18.104580484778257, '2077-11-27T19:07:38.635Z'), +(7.90599646931817, 19.806559635817298, '2077-11-27T19:10:30.635Z'), +(15.85691756912199, 3.4837810923774075, '2077-11-27T19:17:06.635Z'), +(5.854720163452162, 48.08714734934153, '2077-11-27T19:33:42.635Z'), +(8.370371297228813, 4.480503697208881, '2077-11-27T19:49:45.635Z'), +(0.29800708684330585, 22.357071651975, '2077-11-27T19:56:59.635Z'), +(22.294327378767132, 0.1374018723987443, '2077-11-27T20:08:25.635Z'), +(20.984801964053556, 44.12382077580422, '2077-11-27T20:23:31.635Z'), +(4.234988296167096, 15.537084818327491, '2077-11-27T20:35:32.635Z'), +(19.178530293137687, 21.45381112376156, '2077-11-27T20:41:28.635Z'), +(12.606484351826927, 38.96647583679351, '2077-11-27T20:48:09.635Z'), +(5.51173453635529, 49.32774622074549, '2077-11-27T20:52:45.635Z'), +(4.325524726409741, 15.567246421229465, '2077-11-27T21:05:13.635Z'), +(21.059028086393297, 31.494971664590302, '2077-11-27T21:13:39.635Z'), +(20.163327388625312, 21.339451022702207, '2077-11-27T21:17:11.635Z'), +(18.287855936596063, 5.928585843102322, '2077-11-27T21:22:37.635Z'), +(9.633408415211106, 18.52978526379188, '2077-11-27T21:28:09.635Z'), +(8.532102414113064, 30.231057326606038, '2077-11-27T21:32:27.635Z'), +(10.214442699597036, 21.21917018243929, '2077-11-27T21:35:48.635Z'), +(8.953140825817028, 1.0969763576624276, '2077-11-27T21:43:10.635Z'), +(16.112161001732854, 46.59488829288788, '2077-11-27T21:59:48.635Z'), +(3.4807472474708296, 26.96928002179254, '2077-11-27T22:08:20.635Z'), +(19.122821432722624, 46.81221065615303, '2077-11-27T22:17:33.635Z'), +(16.659489070264133, 11.814318551737736, '2077-11-27T22:29:54.635Z'), +(6.009959068233615, 39.939168651043154, '2077-11-27T22:40:50.635Z'), +(0.6776956535048329, 32.94861308988857, '2077-11-27T22:44:05.635Z'), +(9.443706547081218, 23.317292915539216, '2077-11-27T22:48:53.635Z'), +(5.545577015347168, 39.421527559240005, '2077-11-27T22:54:58.635Z'), +(8.580253242792079, 19.380329233059108, '2077-11-27T23:02:25.635Z'), +(4.484608157393058, 6.886325175531492, '2077-11-27T23:07:15.635Z'), +(2.0749637840986885, 14.63206863062875, '2077-11-27T23:10:15.635Z'), +(1.0076908923563386, 17.91687326588757, '2077-11-27T23:11:31.635Z'), +(11.600701361546227, 35.08953531597952, '2077-11-27T23:18:57.635Z'), +(8.724580102679761, 33.04437651631811, '2077-11-27T23:20:15.635Z'), +(10.701397877960938, 2.9344798014366904, '2077-11-27T23:31:16.635Z'), +(8.25754136416077, 2.559162712575433, '2077-11-27T23:32:10.635Z'), +(5.874862981740504, 18.94651338515549, '2077-11-27T23:38:15.635Z'), +(7.735787279509343, 7.2902379412931735, '2077-11-27T23:42:35.635Z'), +(4.5912332894752605, 25.57442263747146, '2077-11-27T23:49:25.635Z'), +(4.528939910155623, 40.781010965261764, '2077-11-27T23:55:02.635Z'), +(6.647574671400205, 33.52104059521932, '2077-11-27T23:57:49.635Z'), +(9.614863004630807, 11.90821367802263, '2077-11-28T00:05:49.635Z'), +(10.85807012574335, 19.244863903167325, '2077-11-28T00:08:31.635Z'), +(18.905720200165796, 26.177478129270696, '2077-11-28T00:12:23.635Z'), +(2.080834681604293, 49.09077522675288, '2077-11-28T00:22:46.635Z'), +(23.09540644710141, 23.41801805023519, '2077-11-28T00:34:50.635Z'), +(7.630720964467048, 49.9635807017289, '2077-11-28T00:45:52.635Z'), +(7.11143590139718, 29.421994365681975, '2077-11-28T00:53:25.635Z'), +(23.342687112060574, 15.066419011059063, '2077-11-28T01:01:18.635Z'), +(0.3237431154406981, 4.677382114749006, '2077-11-28T01:10:36.635Z'), +(14.39009907753819, 49.950058059505885, '2077-11-28T01:27:59.635Z'), +(15.547775865906667, 28.705731285051737, '2077-11-28T01:35:35.635Z'), +(13.208750085916396, 38.576787460988925, '2077-11-28T01:39:13.635Z'), +(1.2750020698116202, 40.03517436490568, '2077-11-28T01:43:40.635Z'), +(11.928436567086239, 35.62859518485377, '2077-11-28T01:47:56.635Z'), +(12.570687784536515, 39.38332792436056, '2077-11-28T01:49:18.635Z'), +(4.4234863014935835, 19.353700622257747, '2077-11-28T01:57:13.635Z'), +(2.3948747863551114, 44.187362787198836, '2077-11-28T02:06:26.635Z'), +(17.203643131668766, 0.057029572972851106, '2077-11-28T02:23:24.635Z'), +(2.4818543809479814, 10.62149928073723, '2077-11-28T02:30:04.635Z'), +(17.29874510024536, 39.45845024823815, '2077-11-28T02:41:54.635Z'), +(7.0685977995373035, 28.71789716365202, '2077-11-28T02:47:19.635Z'), +(21.516237290712667, 19.702007544185758, '2077-11-28T02:53:34.635Z'), +(11.22370623840237, 32.307774589561724, '2077-11-28T02:59:26.635Z'), +(1.2330096589686619, 8.32024731049025, '2077-11-28T03:09:00.635Z'), +(13.224286946915672, 33.560514444729186, '2077-11-28T03:19:16.635Z'), +(19.54696774786567, 26.16317668035194, '2077-11-28T03:22:47.635Z'), +(2.6374174065626685, 13.685599764234443, '2077-11-28T03:30:30.635Z'), +(14.595554473879389, 28.935676387248673, '2077-11-28T03:37:37.635Z'), +(8.551840778383168, 38.8672247756309, '2077-11-28T03:41:51.635Z'), +(7.622483212621463, 11.015041637245897, '2077-11-28T03:52:04.635Z'), +(14.761463090711752, 46.7338724614288, '2077-11-28T04:05:18.635Z'), +(3.117329476634728, 37.618240010664955, '2077-11-28T04:10:45.635Z'), +(15.850257280146687, 21.022012649093586, '2077-11-28T04:18:25.635Z'), +(22.63903085546093, 19.17458525731076, '2077-11-28T04:21:00.635Z'), +(10.644230529719877, 2.8432543944853217, '2077-11-28T04:28:17.635Z'), +(15.780772227561519, 2.6123873697925966, '2077-11-28T04:30:11.635Z'), +(8.402524996840986, 30.38782849345372, '2077-11-28T04:40:36.635Z'), +(19.973699627189283, 0.4460375443175073, '2077-11-28T04:52:09.635Z'), +(0.09899328436199997, 11.340646929585587, '2077-11-28T05:00:30.635Z'), +(12.06277739910279, 16.89066597074484, '2077-11-28T05:05:22.635Z'), +(0.1410993471978228, 31.16783186718201, '2077-11-28T05:12:13.635Z'), +(12.051440277012764, 48.819977158991676, '2077-11-28T05:20:04.635Z'), +(1.7707236377562001, 9.826557462929697, '2077-11-28T05:34:53.635Z'), +(10.074367024270252, 50.06489415564355, '2077-11-28T05:50:01.635Z'), +(2.948874992830946, 47.462637732023865, '2077-11-28T05:52:49.635Z'), +(1.283454707471628, 49.50583177581258, '2077-11-28T05:53:47.635Z'), +(3.182961307787143, 18.32491942355129, '2077-11-28T06:05:21.635Z'), +(0.9991054359784902, 49.46741727079476, '2077-11-28T06:16:54.635Z'), +(2.345414797208426, 32.312068611507215, '2077-11-28T06:23:16.635Z'), +(12.251261955645598, 21.309177250219697, '2077-11-28T06:28:43.635Z'), +(21.46093312276045, 33.30216025754896, '2077-11-28T06:34:09.635Z'), +(10.187751478135137, 10.420710616189098, '2077-11-28T06:43:17.635Z'), +(2.3665615339375075, 4.528040621921456, '2077-11-28T06:46:54.635Z'), +(8.37451607215756, 34.37817306872762, '2077-11-28T06:58:07.635Z'), +(11.467267766538367, 1.2839424560874084, '2077-11-28T07:10:14.635Z'), +(15.05991322984152, 29.938404566799857, '2077-11-28T07:20:38.635Z'), +(9.27683417942739, 33.49643148399078, '2077-11-28T07:23:08.635Z'), +(4.660590192606466, 18.716119909566963, '2077-11-28T07:28:49.635Z'), +(18.549668662031486, 24.85605736866466, '2077-11-28T07:34:25.635Z'), +(0.2573372924264297, 34.54192785924774, '2077-11-28T07:42:03.635Z'), +(21.477574648901232, 3.8613426422491277, '2077-11-28T07:55:38.635Z'), +(0.7590666844275237, 19.83336557197323, '2077-11-28T08:05:14.635Z'), +(7.214932448563374, 33.842732064159094, '2077-11-28T08:10:56.635Z'), +(6.473510483223823, 50.287953879262446, '2077-11-28T08:16:59.635Z'), +(13.85423120986309, 3.8408921260546522, '2077-11-28T08:34:07.635Z'), +(19.002962601929035, 18.76718675664675, '2077-11-28T08:39:45.635Z'), +(13.397155448819337, 37.0081367776599, '2077-11-28T08:46:33.635Z'), +(11.272101817776663, 14.585891261885104, '2077-11-28T08:54:42.635Z'), +(0.9710949154355795, 41.298921415287076, '2077-11-28T09:05:14.635Z'), +(18.790319483263062, 18.811682615614103, '2077-11-28T09:15:44.635Z'), +(3.364588451992838, 36.34463859729876, '2077-11-28T09:24:16.635Z'), +(10.463883835974254, 40.62759878509919, '2077-11-28T09:27:19.635Z'), +(23.46912658521688, 0.870289655997588, '2077-11-28T09:42:09.635Z'), +(13.393676795761108, 10.295107870812233, '2077-11-28T09:47:08.635Z'), +(18.996699842645103, 47.56060914580191, '2077-11-28T10:00:32.635Z'), +(10.186732341933357, 30.87060388100691, '2077-11-28T10:07:20.635Z'), +(2.898203385944423, 18.83025932455407, '2077-11-28T10:12:31.635Z'), +(2.422244511662577, 28.50970309789296, '2077-11-28T10:16:06.635Z'), +(14.597617490377841, 10.404545609367267, '2077-11-28T10:24:06.635Z'), +(9.699348248505359, 2.3487017043593084, '2077-11-28T10:27:32.635Z'), +(13.915814109499978, 39.25138040812436, '2077-11-28T10:40:59.635Z'), +(15.530304248520626, 32.882790339691624, '2077-11-28T10:43:20.635Z'), +(18.648682384845245, 43.5494815195361, '2077-11-28T10:47:17.635Z'), +(20.469419942728855, 44.485277909369586, '2077-11-28T10:48:01.635Z'), +(19.048918272547787, 40.81860961719345, '2077-11-28T10:49:23.635Z'), +(5.401545246821957, 48.656294708110764, '2077-11-28T10:55:10.635Z'), +(2.429903920638132, 14.240886373858842, '2077-11-28T11:07:56.635Z'), +(3.17674585904173, 5.586240772417513, '2077-11-28T11:11:08.635Z'), +(8.173338336930113, 15.780854719932771, '2077-11-28T11:15:19.635Z'), +(14.65449249285501, 42.65700385316249, '2077-11-28T11:25:21.635Z'), +(4.674331047277497, 32.00776417395183, '2077-11-28T11:30:42.635Z'), +(8.420148229994826, 26.642251235199414, '2077-11-28T11:33:06.635Z'), +(16.740052455266706, 3.9140361697616317, '2077-11-28T11:41:52.635Z'), +(7.847472642593914, 49.07821713702146, '2077-11-28T11:58:30.635Z'), +(20.14470329741274, 31.98215926027211, '2077-11-28T12:06:08.635Z'), +(23.47016934487126, 15.74520863675875, '2077-11-28T12:11:51.635Z'), +(8.160212674168365, 33.91371254787586, '2077-11-28T12:20:26.635Z'), +(8.574675431476306, 36.43468063291601, '2077-11-28T12:21:22.635Z'), +(17.245724285066974, 23.793368479473955, '2077-11-28T12:26:56.635Z'), +(19.56414257047938, 21.720374216026922, '2077-11-28T12:28:03.635Z'), +(5.324661402376223, 19.861562455500277, '2077-11-28T12:33:22.635Z'), +(15.217527766455465, 2.650872618698638, '2077-11-28T12:40:37.635Z'), +(21.89832385839576, 36.699150935567545, '2077-11-28T12:52:48.635Z'), +(22.649126067627073, 43.2259192387681, '2077-11-28T12:55:03.635Z'), +(1.8576989375252775, 29.268406110673254, '2077-11-28T13:04:14.635Z'), +(10.704513835473007, 16.845711148596063, '2077-11-28T13:09:51.635Z'), +(21.65053634372209, 26.96854170733265, '2077-11-28T13:15:16.635Z'), +(3.784227078773752, 50.22947589620184, '2077-11-28T13:25:56.635Z'), +(12.921651340282313, 0.3890292381953379, '2077-11-28T13:44:29.635Z'), +(3.9704644136492835, 18.793764856577315, '2077-11-28T13:51:59.635Z'), +(20.523332939552535, 19.82898721302669, '2077-11-28T13:58:07.635Z'), +(16.087345273754483, 48.972116248764024, '2077-11-28T14:08:29.635Z'), +(9.7326704822362, 46.876876395529756, '2077-11-28T14:10:57.635Z'), +(11.435702869956545, 14.74190693872187, '2077-11-28T14:22:40.635Z'), +(0.11928623539877829, 42.63737749884945, '2077-11-28T14:33:45.635Z'), +(9.910591912145941, 49.86251462908089, '2077-11-28T14:38:15.635Z'), +(3.238522918534147, 31.0681041438978, '2077-11-28T14:45:35.635Z'), +(10.64709940103677, 32.8509943208995, '2077-11-28T14:48:24.635Z'), +(21.05537882572243, 30.033308024363123, '2077-11-28T14:52:23.635Z'), +(19.497752438615148, 8.444903396229343, '2077-11-28T14:59:54.635Z'), +(13.980277757004371, 49.14547343030699, '2077-11-28T15:14:27.635Z'), +(1.0760825730053134, 29.862216873185456, '2077-11-28T15:22:59.635Z'), +(16.523185211128286, 46.62915704908414, '2077-11-28T15:31:21.635Z'), +(10.28403492903979, 3.8630063221810653, '2077-11-28T15:46:54.635Z'), +(15.321643955397104, 34.73060033948402, '2077-11-28T15:58:12.635Z'), +(0.8668601255572869, 11.83504671104886, '2077-11-28T16:08:08.635Z'), +(20.606697630542754, 28.309057342445765, '2077-11-28T16:17:34.635Z'), +(2.6060512713042705, 19.846960640782978, '2077-11-28T16:24:54.635Z'), +(15.62827800686851, 10.781652707700715, '2077-11-28T16:30:45.635Z'), +(14.520847823333296, 20.683720224836033, '2077-11-28T16:34:19.635Z'), +(8.765874530700353, 30.61334518731166, '2077-11-28T16:38:30.635Z'), +(12.291882413991708, 21.08819152487244, '2077-11-28T16:42:12.635Z'), +(3.373797964980805, 30.71582507824185, '2077-11-28T16:47:02.635Z'), +(15.214365713786865, 31.122715543389585, '2077-11-28T16:51:25.635Z'), +(1.5991698202183724, 27.379440668396153, '2077-11-28T16:56:38.635Z'), +(7.641320272841061, 5.281606848319297, '2077-11-28T17:05:05.635Z'), +(13.992451189932435, 11.795987433581791, '2077-11-28T17:08:25.635Z'), +(21.522183245031425, 11.58324725247869, '2077-11-28T17:11:12.635Z'), +(19.446878872051744, 16.148713661665546, '2077-11-28T17:12:57.635Z'), +(20.865598639807494, 41.97306021268863, '2077-11-28T17:21:56.635Z'), +(23.060082256697207, 14.064601930082393, '2077-11-28T17:31:32.635Z'), +(17.658428718598145, 28.73727634910849, '2077-11-28T17:37:00.635Z'), +(4.30740405744795, 15.832090271616869, '2077-11-28T17:43:48.635Z'), +(10.323121429089843, 45.19673129847663, '2077-11-28T17:54:48.635Z'), +(18.38540007181824, 42.16841396642168, '2077-11-28T17:57:58.635Z'), +(6.276182240330301, 6.139459924804692, '2077-11-28T18:11:43.635Z'), +(3.6999479205827983, 44.460409500699924, '2077-11-28T18:25:53.635Z'), +(20.881570333635295, 34.46563637431809, '2077-11-28T18:33:12.635Z'), +(12.958088064338808, 3.9543033681377278, '2077-11-28T18:44:23.635Z'), +(23.50017198009226, 30.407621664929408, '2077-11-28T18:54:27.635Z'), +(19.592668106642105, 8.276725557651568, '2077-11-28T19:02:12.635Z'), +(0.6105523267887392, 36.02239018458853, '2077-11-28T19:14:29.635Z'), +(11.535619197949, 32.9241707233935, '2077-11-28T19:18:41.635Z'), +(14.995424570455635, 35.85723735236223, '2077-11-28T19:20:20.635Z'), +(22.569307189072905, 41.60840472355371, '2077-11-28T19:23:47.635Z'), +(12.556167326769899, 37.75852023912568, '2077-11-28T19:27:44.635Z'), +(23.24872526811593, 17.673132559654164, '2077-11-28T19:35:50.635Z'), +(16.78590984799468, 39.382578966403365, '2077-11-28T19:43:45.635Z'), +(23.04284806398908, 30.49471739910911, '2077-11-28T19:47:37.635Z'), +(8.45980085287358, 10.108292794967673, '2077-11-28T19:56:39.635Z'), +(13.3891116291102, 40.15193826245212, '2077-11-28T20:07:43.635Z'), +(20.126613487628536, 40.59893092684886, '2077-11-28T20:10:13.635Z'), +(18.493565266880804, 37.626018956657866, '2077-11-28T20:11:25.635Z'), +(5.372106005516539, 1.1684688852985474, '2077-11-28T20:25:27.635Z'), +(9.319813691049232, 14.705722848804369, '2077-11-28T20:30:38.635Z'), +(18.464707321657045, 21.664283898011234, '2077-11-28T20:34:50.635Z'), +(18.306527131923747, 29.306283706838368, '2077-11-28T20:37:31.635Z'), +(2.353774181726634, 34.058285460309115, '2077-11-28T20:43:40.635Z'), +(1.6520790261418512, 14.031635911046806, '2077-11-28T20:51:05.635Z'), +(4.10899106413679, 25.12183048271551, '2077-11-28T20:55:17.635Z'), +(14.108577085182201, 1.145985461567322, '2077-11-28T21:04:47.635Z'), +(7.129247684312848, 11.447081891240616, '2077-11-28T21:09:20.635Z'), +(21.117311694089995, 24.91973827490994, '2077-11-28T21:16:25.635Z'), +(20.44570011531194, 35.73893000642962, '2077-11-28T21:20:10.635Z'), +(22.676807305291884, 39.26971441261406, '2077-11-28T21:21:38.635Z'), +(20.484359142607598, 27.284148228618538, '2077-11-28T21:25:50.635Z'), +(8.70946823702133, 4.758890344783723, '2077-11-28T21:34:59.635Z'), +(11.282799358997009, 3.6596798141794165, '2077-11-28T21:36:01.635Z'), +(3.0127322927319926, 1.9831623474592135, '2077-11-28T21:39:08.635Z'), +(5.725841910921703, 20.170519145949395, '2077-11-28T21:45:55.635Z'), +(3.1793260246577355, 13.05553221884417, '2077-11-28T21:48:42.635Z'), +(19.929985972520033, 41.4777433349926, '2077-11-28T22:00:42.635Z'), +(2.860524041023076, 26.219671856325096, '2077-11-28T22:09:05.635Z'), +(14.901715933126699, 49.53318937527683, '2077-11-28T22:18:42.635Z'), +(9.76472454843022, 14.670345125428838, '2077-11-28T22:31:27.635Z'), +(1.6071097324113384, 5.66227110522739, '2077-11-28T22:35:56.635Z'), +(7.823230171976351, 18.50965753118455, '2077-11-28T22:41:12.635Z'), +(11.349472597695735, 11.268610257275613, '2077-11-28T22:44:09.635Z'), +(15.446496289724982, 19.568736616506083, '2077-11-28T22:47:30.635Z'), +(8.35567699413397, 24.25621794140822, '2077-11-28T22:50:37.635Z'), +(13.058511094014754, 44.245551415678314, '2077-11-28T22:58:05.635Z'), +(10.145776903990171, 3.1778009633133353, '2077-11-28T23:13:01.635Z'), +(0.1366636474729336, 31.814048465374476, '2077-11-28T23:24:12.635Z'), +(4.28050228217685, 38.68486205501287, '2077-11-28T23:27:10.635Z'), +(8.803127521862637, 7.102998948152424, '2077-11-28T23:38:54.635Z'), +(9.281557494206034, 0.1451655958410126, '2077-11-28T23:41:27.635Z'), +(9.326938051523518, 24.032121958396328, '2077-11-28T23:50:11.635Z'), +(2.6565850902346204, 40.327810890785884, '2077-11-28T23:56:40.635Z'), +(10.450053580941134, 31.24306240093482, '2077-11-29T00:01:05.635Z'), +(10.433994150008257, 47.84583086586538, '2077-11-29T00:07:08.635Z'), +(1.6503712236568577, 42.25829237623338, '2077-11-29T00:10:59.635Z'), +(23.258876921415073, 8.541253122813494, '2077-11-29T00:25:30.635Z'), +(5.623047915576707, 19.856685143081084, '2077-11-29T00:33:11.635Z'), +(19.797390079475615, 46.30931333351038, '2077-11-29T00:44:04.635Z'), +(13.89143488935053, 12.271695591792476, '2077-11-29T00:56:18.635Z'), +(1.3947381303048083, 33.13132046762624, '2077-11-29T01:05:14.635Z'), +(2.7632060503117875, 41.76408745415231, '2077-11-29T01:08:28.635Z'), +(20.792892547555233, 23.954620143835317, '2077-11-29T01:17:44.635Z'), +(22.649639474936777, 16.538515086718313, '2077-11-29T01:20:22.635Z'), +(11.012883341812776, 7.365364159437207, '2077-11-29T01:25:45.635Z'), +(12.695464502660494, 23.780078373958254, '2077-11-29T01:31:44.635Z'), +(15.683305222122419, 22.674742917480838, '2077-11-29T01:32:54.635Z'), +(20.39350211047861, 34.79158904322386, '2077-11-29T01:37:30.635Z'), +(14.294443170476011, 36.747400234211625, '2077-11-29T01:39:51.635Z'), +(20.953715775517455, 8.133956146084667, '2077-11-29T01:50:14.635Z'), +(18.057653155252172, 36.683278248990575, '2077-11-29T02:00:15.635Z'), +(21.80795612146453, 43.82578441745125, '2077-11-29T02:03:05.635Z'), +(9.760107697469504, 24.888239993242216, '2077-11-29T02:11:09.635Z'), +(1.2223801966984984, 40.525658133453845, '2077-11-29T02:17:43.635Z'), +(8.87034484662902, 27.319731523828064, '2077-11-29T02:23:21.635Z'), +(0.06961591846281671, 7.039550263433802, '2077-11-29T02:31:30.635Z'), +(11.766533921291392, 32.738347547316835, '2077-11-29T02:41:54.635Z'), +(12.075886742468626, 6.421125479331567, '2077-11-29T02:51:26.635Z'), +(20.82732025409812, 4.71865387460437, '2077-11-29T02:54:43.635Z'), +(16.188785995697113, 37.52766444060682, '2077-11-29T03:06:21.635Z'), +(14.767315873658525, 16.87800602928017, '2077-11-29T03:13:44.635Z'), +(9.039052761900642, 49.77902568031345, '2077-11-29T03:25:50.635Z'), +(13.920072108021603, 20.273259889116954, '2077-11-29T03:36:41.635Z'), +(7.193002029250921, 32.87951842868736, '2077-11-29T03:41:54.635Z'), +(21.135827137164007, 21.762851749589224, '2077-11-29T03:48:25.635Z'), +(11.888986703886175, 41.7924712479658, '2077-11-29T03:56:18.635Z'), +(12.099457632919396, 35.4490747566798, '2077-11-29T03:58:36.635Z'), +(8.69619877416043, 7.78383024989686, '2077-11-29T04:08:45.635Z'), +(8.771535148297652, 18.91153223141923, '2077-11-29T04:12:49.635Z'), +(15.05733710392308, 9.413785399503118, '2077-11-29T04:16:58.635Z'), +(14.390622964325535, 27.041123801001984, '2077-11-29T04:23:17.635Z'), +(10.74873597319973, 44.07461918893223, '2077-11-29T04:29:35.635Z'), +(11.895044917247843, 11.735351161525626, '2077-11-29T04:41:20.635Z'), +(3.9887985338863157, 14.053955768132317, '2077-11-29T04:44:23.635Z'), +(0.1192503103705488, 5.969924553679562, '2077-11-29T04:47:42.635Z'), +(15.687075130160936, 40.83741430385697, '2077-11-29T05:01:41.635Z'), +(1.4151473452634746, 10.83405330580502, '2077-11-29T05:13:51.635Z'), +(16.44877973113522, 33.8225130928279, '2077-11-29T05:23:55.635Z'), +(12.37043629454178, 34.104777549633276, '2077-11-29T05:25:25.635Z'), +(3.3947450522633913, 0.5116541493506563, '2077-11-29T05:38:10.635Z'), +(13.778853428724224, 9.806368906092356, '2077-11-29T05:43:18.635Z'), +(14.05784712575042, 46.72202534143077, '2077-11-29T05:56:34.635Z'), +(0.745528083677272, 32.02975778780741, '2077-11-29T06:03:52.635Z'), +(14.935530567209439, 34.00496986342521, '2077-11-29T06:09:10.635Z'), +(2.310597465684669, 4.724455919689323, '2077-11-29T06:20:50.635Z'), +(17.95602417663656, 48.09914532976918, '2077-11-29T06:37:37.635Z'), +(2.0165879591169156, 23.51826549481156, '2077-11-29T06:48:19.635Z'), +(16.276268681095868, 23.203105858281678, '2077-11-29T06:53:36.635Z'), +(2.232178718476037, 40.886965434509946, '2077-11-29T07:01:53.635Z'), +(0.49561957845717225, 14.765902874929184, '2077-11-29T07:11:34.635Z'), +(14.974810932828111, 45.08157386714115, '2077-11-29T07:23:53.635Z'), +(17.324952979664754, 3.9386952812195264, '2077-11-29T07:38:31.635Z'), +(20.964676326805836, 50.25084940227396, '2077-11-29T07:54:44.635Z'), +(3.4214774851757337, 36.40320005309641, '2077-11-29T08:02:55.635Z'), +(19.818004247512267, 34.25344755757636, '2077-11-29T08:09:02.635Z'), +(2.7991014914121735, 41.05688208453076, '2077-11-29T08:15:48.635Z'), +(15.604022023170453, 34.16490335221312, '2077-11-29T08:21:10.635Z'), +(22.935202484812244, 45.83582514713102, '2077-11-29T08:26:04.635Z'), +(14.776564490256957, 35.1273079224933, '2077-11-29T08:30:53.635Z'), +(10.080307677637792, 6.7323429070028755, '2077-11-29T08:41:17.635Z'), +(2.4452297921321855, 43.844449710509025, '2077-11-29T08:55:14.635Z'), +(2.388764971691321, 44.91724913213791, '2077-11-29T08:55:37.635Z'), +(2.8191869440241644, 14.473595543336291, '2077-11-29T09:06:53.635Z'), +(12.952342014653672, 34.02704593008958, '2077-11-29T09:14:58.635Z'), +(4.003497107073811, 26.909130878016946, '2077-11-29T09:19:11.635Z'), +(7.997571122191661, 6.416552549510489, '2077-11-29T09:26:52.635Z'), +(1.5042407796999437, 22.052142230917887, '2077-11-29T09:33:07.635Z'), +(20.08036249461949, 25.742531950485834, '2077-11-29T09:40:07.635Z'), +(18.577779439229033, 1.641789972643236, '2077-11-29T09:48:33.635Z'), +(3.0819253479223305, 8.77263817812151, '2077-11-29T09:54:50.635Z'), +(11.261258275474288, 5.9377648550705615, '2077-11-29T09:58:02.635Z'), +(8.676687115722354, 20.470303212252688, '2077-11-29T10:03:25.635Z'), +(5.274751823634281, 1.8358506546387565, '2077-11-29T10:10:23.635Z'), +(15.45988951049355, 7.79423436725028, '2077-11-29T10:14:44.635Z'), +(4.613978341441002, 40.36866671924925, '2077-11-29T10:27:15.635Z'), +(10.819709018430897, 13.891152670834343, '2077-11-29T10:37:14.635Z'), +(13.736716294255341, 47.569275102205566, '2077-11-29T10:49:28.635Z'), +(6.324767121310379, 16.019921241202553, '2077-11-29T11:01:17.635Z'), +(1.6798512524868268, 45.12024787835498, '2077-11-29T11:12:10.635Z'), +(14.09132302502838, 14.368167101687696, '2077-11-29T11:24:20.635Z'), +(1.9962669322492732, 23.755044095782782, '2077-11-29T11:29:58.635Z'), +(10.524712403401201, 48.17065204204611, '2077-11-29T11:39:29.635Z'), +(20.65603434865655, 41.547039827017166, '2077-11-29T11:43:55.635Z'), +(19.96473698427132, 21.32258410074452, '2077-11-29T11:50:56.635Z'), +(14.676007772261569, 32.72648571308075, '2077-11-29T11:55:25.635Z'), +(18.471880526732427, 14.74660748333195, '2077-11-29T12:01:57.635Z'), +(11.88182477310001, 1.1402660154662105, '2077-11-29T12:07:23.635Z'), +(15.462739034328001, 39.18078505140366, '2077-11-29T12:21:07.635Z'), +(19.980031874574365, 14.868374849075598, '2077-11-29T12:29:51.635Z'), +(8.992414639120748, 21.639639868515644, '2077-11-29T12:34:35.635Z'), +(19.881597449004595, 0.7398250068743185, '2077-11-29T12:43:05.635Z'), +(18.716102953863807, 1.811597104234005, '2077-11-29T12:43:39.635Z'), +(16.48860399524485, 33.359109132248264, '2077-11-29T12:54:48.635Z'), +(19.927405001911588, 7.045710911052654, '2077-11-29T13:04:08.635Z'), +(4.167983296412372, 9.926590365816049, '2077-11-29T13:10:03.635Z'), +(2.1613807349880276, 13.319452262052057, '2077-11-29T13:11:30.635Z'), +(1.8943817521110833, 34.89115625157891, '2077-11-29T13:19:29.635Z'), +(14.84631346101909, 11.003750584777057, '2077-11-29T13:29:27.635Z'), +(21.42702382070644, 13.462373206886268, '2077-11-29T13:32:02.635Z'), +(5.823095847319154, 13.28672175128955, '2077-11-29T13:37:49.635Z'), +(0.8004383555176606, 18.703135545319057, '2077-11-29T13:40:33.635Z'), +(12.19786485583799, 3.9587678615295596, '2077-11-29T13:47:25.635Z'), +(8.184368671346062, 24.292367685979467, '2077-11-29T13:54:58.635Z'), +(6.434077472485966, 2.0824787491621612, '2077-11-29T14:03:09.635Z'), +(13.409630749708208, 22.304992152761823, '2077-11-29T14:10:58.635Z'), +(6.586971163250798, 43.36824679916809, '2077-11-29T14:19:03.635Z'), +(16.46467418965764, 9.864630821382391, '2077-11-29T14:31:44.635Z'), +(7.288120091092258, 26.711079561432747, '2077-11-29T14:38:43.635Z'), +(0.361639428881446, 38.30252650400252, '2077-11-29T14:43:42.635Z'), +(9.40673136902558, 1.0791088222358025, '2077-11-29T14:57:50.635Z'), +(4.395697904105088, 46.13213636929632, '2077-11-29T15:14:30.635Z'), +(10.968659198750425, 40.676676695939456, '2077-11-29T15:17:39.635Z'), +(8.818558342585199, 13.836584699496045, '2077-11-29T15:27:28.635Z'), +(18.923574227862726, 0.2579560453239193, '2077-11-29T15:33:37.635Z'), +(20.573441789384997, 6.8366701912116135, '2077-11-29T15:35:59.635Z'), +(6.93084150699071, 35.50775233711783, '2077-11-29T15:47:26.635Z'), +(4.024614160941863, 28.491413432032374, '2077-11-29T15:50:14.635Z'), +(0.9702733095113237, 23.420955378192144, '2077-11-29T15:52:25.635Z'), +(3.231626928065755, 4.652429479308121, '2077-11-29T15:59:25.635Z'), +(17.513069819447068, 14.578272045339117, '2077-11-29T16:05:49.635Z'), +(10.191162267875823, 11.329280341316746, '2077-11-29T16:08:46.635Z'), +(2.657439686283533, 15.6779996677916, '2077-11-29T16:11:59.635Z'), +(13.844416898356679, 23.84764236865104, '2077-11-29T16:17:05.635Z'), +(6.237888335629792, 35.21881444210011, '2077-11-29T16:22:05.635Z'), +(8.7004151968664, 2.780278617490565, '2077-11-29T16:34:02.635Z'), +(6.193393276908935, 36.30603536034737, '2077-11-29T16:46:23.635Z'), +(0.15407251754330797, 16.676712435978033, '2077-11-29T16:53:58.635Z'), +(23.278807745740732, 31.88347008078097, '2077-11-29T17:04:08.635Z'), +(12.06007592904944, 2.822767442775743, '2077-11-29T17:15:10.635Z'), +(10.623660802671377, 36.59771266017312, '2077-11-29T17:27:26.635Z'), +(20.505687873947036, 35.17690528379118, '2077-11-29T17:31:07.635Z'), +(7.881757637823372, 12.713341227954912, '2077-11-29T17:40:25.635Z'), +(6.772226486278446, 38.865807091078445, '2077-11-29T17:50:02.635Z'), +(0.20506189858403986, 6.910415795925435, '2077-11-29T18:02:05.635Z'), +(13.283769764394467, 9.011926903382538, '2077-11-29T18:06:59.635Z'), +(21.39813440595541, 11.610288245486922, '2077-11-29T18:10:07.635Z'), +(17.616259191176628, 6.892453463378614, '2077-11-29T18:12:16.635Z'), +(3.1081323018254676, 36.4296965119971, '2077-11-29T18:24:16.635Z'), +(22.216394904183595, 12.394087117611054, '2077-11-29T18:35:26.635Z'), +(17.261764284925505, 6.497977972768377, '2077-11-29T18:38:11.635Z'), +(4.858523369157601, 4.3059964189669575, '2077-11-29T18:42:50.635Z'), +(18.19700836150553, 43.36918976067966, '2077-11-29T18:57:48.635Z'), +(0.6330803071509792, 23.986955553041454, '2077-11-29T19:07:24.635Z'), +(15.222521065205516, 24.720739239740084, '2077-11-29T19:12:48.635Z'), +(2.3073722829885415, 36.390102742730065, '2077-11-29T19:19:12.635Z'), +(20.873771218040865, 12.531443469321324, '2077-11-29T19:30:13.635Z'), +(14.369772674200815, 19.70733435817235, '2077-11-29T19:33:42.635Z'), +(3.573130891702562, 25.776183119658874, '2077-11-29T19:38:16.635Z'), +(21.216992625439484, 2.881686618753122, '2077-11-29T19:48:47.635Z'), +(22.667192167776058, 23.323598999338046, '2077-11-29T19:55:49.635Z'), +(18.277306474288952, 3.6476910044884043, '2077-11-29T20:02:50.635Z'), +(15.391163377562652, 4.968948460904703, '2077-11-29T20:04:00.635Z'), +(8.36335639457529, 23.379562193455836, '2077-11-29T20:11:09.635Z'), +(5.534328380437728, 2.1854681384081087, '2077-11-29T20:19:00.635Z'), +(9.167600315700817, 44.508439729513164, '2077-11-29T20:34:36.635Z'), +(17.683928425778742, 44.81270349387522, '2077-11-29T20:37:45.635Z'), +(0.02718735580834724, 16.650810855312724, '2077-11-29T20:49:55.635Z'), +(17.035538027591276, 4.116052745803836, '2077-11-29T20:57:42.635Z'), +(8.41436304740439, 9.195543928553807, '2077-11-29T21:01:23.635Z'), +(22.421682083324082, 34.972448890390666, '2077-11-29T21:11:55.635Z'), +(22.145046770515712, 24.67378507840268, '2077-11-29T21:15:26.635Z'), +(3.721071735751577, 23.556915187296536, '2077-11-29T21:22:16.635Z'), +(0.6969225500484401, 20.366407584986575, '2077-11-29T21:23:53.635Z'), +(10.166063338637281, 7.062974816682083, '2077-11-29T21:29:54.635Z'), +(5.811394977334487, 37.29903013146635, '2077-11-29T21:41:06.635Z'), +(15.804835291968965, 45.09529571329851, '2077-11-29T21:45:45.635Z'), +(15.355568834602648, 1.9432561537482906, '2077-11-29T22:01:07.635Z'), +(20.683178930127703, 32.072664974382796, '2077-11-29T22:11:54.635Z'), +(3.043441491663917, 23.260050841753372, '2077-11-29T22:19:10.635Z'), +(14.736663901233367, 50.17210511215582, '2077-11-29T22:29:54.635Z'), +(14.798123948829874, 1.369789352481975, '2077-11-29T22:47:21.635Z'), +(20.51199418106143, 36.68885342251111, '2077-11-29T22:59:58.635Z'), +(3.2356906757295856, 42.1501610816334, '2077-11-29T23:06:40.635Z'), +(18.455855658460642, 35.862740005408796, '2077-11-29T23:12:45.635Z'), +(6.1663191149222, 3.139198703264814, '2077-11-29T23:25:24.635Z'), +(7.928741882808134, 7.195658780812064, '2077-11-29T23:27:01.635Z'), +(20.569553606414747, 32.04360851944762, '2077-11-29T23:37:04.635Z'), +(22.07931181581886, 15.617009103845332, '2077-11-29T23:42:45.635Z'), +(15.331224470085672, 15.912142350137641, '2077-11-29T23:45:15.635Z'), +(19.230683930648915, 30.66719470378761, '2077-11-29T23:50:39.635Z'), +(6.930348013323168, 42.713496897116066, '2077-11-29T23:56:56.635Z'), +(4.6962018754713, 20.41989122678896, '2077-11-30T00:05:11.635Z'), +(0.20375153511615748, 31.5654997154959, '2077-11-30T00:09:37.635Z'), +(5.261187968293643, 22.109419692405886, '2077-11-30T00:13:35.635Z'), +(4.490029867454785, 27.56943688986173, '2077-11-30T00:15:37.635Z'), +(11.546320602148345, 49.63593949689246, '2077-11-30T00:24:07.635Z'), +(16.87784037754343, 19.443568900399303, '2077-11-30T00:35:07.635Z'), +(8.398897917227115, 20.26048567237139, '2077-11-30T00:38:16.635Z'), +(10.737394698530846, 43.14172642722985, '2077-11-30T00:46:40.635Z'), +(12.363315347265809, 37.50288550378312, '2077-11-30T00:48:48.635Z'), +(19.969494574723104, 28.92423462244365, '2077-11-30T00:52:57.635Z'), +(10.892633141075475, 20.570618146769377, '2077-11-30T00:57:26.635Z'), +(21.600299894463124, 4.61372497227837, '2077-11-30T01:04:21.635Z'), +(17.14462671080051, 39.99100937996409, '2077-11-30T01:16:48.635Z'), +(2.6894465155255585, 29.86085980976506, '2077-11-30T01:23:18.635Z'), +(3.675584202825824, 37.802710542627814, '2077-11-30T01:26:15.635Z'), +(19.185613483345225, 12.491456688779188, '2077-11-30T01:37:03.635Z'), +(2.037629326749638, 3.635158518433615, '2077-11-30T01:44:10.635Z'), +(19.995350245107467, 42.274392518170615, '2077-11-30T01:59:39.635Z'), +(0.34948465180514676, 47.97856711956839, '2077-11-30T02:07:13.635Z'), +(0.08522310816289812, 7.015402830488765, '2077-11-30T02:22:23.635Z'), +(3.1855484976205486, 44.11943321804183, '2077-11-30T02:36:10.635Z'), +(20.442419531354997, 14.142264709366678, '2077-11-30T02:48:44.635Z'), +(17.988307562992766, 37.50634410756284, '2077-11-30T02:56:57.635Z'), +(22.556698540581603, 44.715426772082466, '2077-11-30T02:59:58.635Z'), +(19.611277897916718, 27.324001792862475, '2077-11-30T03:06:04.635Z'), +(23.295566413324778, 8.702730032114026, '2077-11-30T03:12:37.635Z'), +(1.3264595706292721, 4.63356202167844, '2077-11-30T03:20:53.635Z'), +(17.739601577634005, 0.969621834586377, '2077-11-30T03:27:06.635Z'), +(2.9412585870389396, 43.66192864797635, '2077-11-30T03:43:32.635Z'), +(7.061599693443086, 1.9960427432921954, '2077-11-30T03:58:59.635Z'), +(18.191058740042752, 39.112125383696856, '2077-11-30T04:12:59.635Z'), +(0.023606071608909502, 26.172959990672524, '2077-11-30T04:21:12.635Z'), +(3.7498568683005087, 34.80815175442626, '2077-11-30T04:24:41.635Z'), +(22.03122035260858, 16.95356899265832, '2077-11-30T04:34:00.635Z'), +(7.9053010443673095, 35.18453168320115, '2077-11-30T04:42:21.635Z'), +(0.9571747888507167, 20.24120146645394, '2077-11-30T04:48:26.635Z'), +(9.238386705049498, 49.16753129826867, '2077-11-30T04:59:32.635Z'), +(13.965447395423675, 24.914478051741636, '2077-11-30T05:08:30.635Z'), +(8.615781790994388, 35.313432306965495, '2077-11-30T05:12:46.635Z'), +(2.731186173356136, 25.197743683699947, '2077-11-30T05:17:05.635Z'), +(15.954460856106039, 7.6039878685889395, '2077-11-30T05:25:09.635Z'), +(7.416558970416367, 45.451028263102664, '2077-11-30T05:39:13.635Z'), +(10.868747265800103, 12.54299713161208, '2077-11-30T05:51:19.635Z'), +(15.574491236136373, 12.295557926337203, '2077-11-30T05:53:03.635Z'), +(11.356015124010458, 19.134313468044176, '2077-11-30T05:55:58.635Z'), +(19.143010569335683, 46.38256153687437, '2077-11-30T06:06:06.635Z'), +(17.272736779548683, 0.20528265905151113, '2077-11-30T06:22:19.635Z'), +(4.638173721474813, 36.74205316793176, '2077-11-30T06:36:22.635Z'), +(5.511294272838051, 23.49447978301515, '2077-11-30T06:41:16.635Z'), +(7.060438205858466, 35.98788411474261, '2077-11-30T06:45:54.635Z'), +(14.39687861420457, 3.26304878346426, '2077-11-30T06:58:06.635Z'), +(23.490567781465973, 2.1879083559200483, '2077-11-30T07:01:29.635Z'), +(13.863222008550972, 49.537837312023235, '2077-11-30T07:18:24.635Z'), +(4.983211771721038, 49.28124563690424, '2077-11-30T07:21:41.635Z'), +(21.014626379910105, 40.50218273996742, '2077-11-30T07:28:24.635Z'), +(15.63211362622923, 24.84869531273775, '2077-11-30T07:34:15.635Z'), +(15.1406360464787, 8.005687920188045, '2077-11-30T07:40:16.635Z'), +(9.521076388999763, 3.058899498666762, '2077-11-30T07:43:00.635Z'), +(15.593218442870597, 32.35134952666967, '2077-11-30T07:53:49.635Z'), +(9.067025687156603, 27.914347099799876, '2077-11-30T07:56:43.635Z'), +(7.689377593121843, 35.63232433795845, '2077-11-30T07:59:35.635Z'), +(21.304925451687467, 34.85295384745277, '2077-11-30T08:04:38.635Z'), +(21.79481526026073, 47.702002437780415, '2077-11-30T08:09:03.635Z'), +(16.754022971069478, 37.945780755489004, '2077-11-30T08:12:56.635Z'), +(18.15965664069787, 12.789545544926513, '2077-11-30T08:21:50.635Z'), +(16.89124846565731, 41.966613598036865, '2077-11-30T08:32:08.635Z'), +(2.3788018918878078, 11.852050042508662, '2077-11-30T08:44:20.635Z'), +(20.856775199879387, 39.7642238419724, '2077-11-30T08:56:31.635Z'), +(8.014053327460282, 30.05133000952684, '2077-11-30T09:02:24.635Z'), +(8.503461063770196, 0.26120397483263375, '2077-11-30T09:13:19.635Z'), +(9.373173355754737, 5.089525351964, '2077-11-30T09:15:06.635Z'), +(16.74779392816576, 33.74878350263906, '2077-11-30T09:25:47.635Z'), +(2.781675991505854, 32.88302611864166, '2077-11-30T09:30:58.635Z'), +(3.205561254169562, 49.502936081999614, '2077-11-30T09:37:07.635Z'), +(4.532833700946033, 38.41218126057149, '2077-11-30T09:41:14.635Z'), +(21.421765082920743, 12.671344854297747, '2077-11-30T09:52:24.635Z'), +(14.029699498255473, 45.44092066367878, '2077-11-30T10:04:15.635Z'), +(5.6809700711949, 7.854792187965163, '2077-11-30T10:18:17.635Z'), +(19.180212898621523, 42.266105228697135, '2077-11-30T10:31:40.635Z'), +(11.539472543003441, 22.65942854463209, '2077-11-30T10:39:13.635Z'), +(16.367979543825847, 39.636420417969674, '2077-11-30T10:45:34.635Z'), +(12.309527923357692, 39.59279603006876, '2077-11-30T10:47:04.635Z'), +(17.700665521394125, 29.954885275473885, '2077-11-30T10:51:03.635Z'), +(9.699987004550794, 11.983158970040567, '2077-11-30T10:58:09.635Z'), +(18.685187763368138, 2.7249259608268397, '2077-11-30T11:02:51.635Z'), +(0.7887472613830098, 25.510229564150908, '2077-11-30T11:13:27.635Z'), +(17.573517777981664, 37.92976098712115, '2077-11-30T11:21:08.635Z'), +(14.976883481609267, 31.01639198286851, '2077-11-30T11:23:46.635Z'), +(17.82538136029019, 25.91715320636671, '2077-11-30T11:25:51.635Z'), +(16.61146357546095, 26.50963041801161, '2077-11-30T11:26:20.635Z'), +(16.681713150690385, 23.670472987369337, '2077-11-30T11:27:20.635Z'), +(15.808059075537516, 26.707199014999766, '2077-11-30T11:28:27.635Z'), +(0.9353022621651058, 21.97642545054606, '2077-11-30T11:34:13.635Z'), +(18.144515428347926, 20.79779317310518, '2077-11-30T11:40:36.635Z'), +(5.989456913236739, 4.161421882013993, '2077-11-30T11:48:06.635Z'), +(11.916658972035771, 5.901664398087939, '2077-11-30T11:50:23.635Z'), +(6.253922988994473, 19.088550443024566, '2077-11-30T11:55:38.635Z'), +(9.79716942776164, 19.839036143966815, '2077-11-30T11:56:58.635Z'), +(17.35165492671031, 29.211752919213993, '2077-11-30T12:01:21.635Z'), +(22.532478347127263, 3.136867060562049, '2077-11-30T12:10:37.635Z'), +(22.56208403272439, 5.512694030963864, '2077-11-30T12:11:25.635Z'), +(10.533119818531064, 13.137644738023157, '2077-11-30T12:16:37.635Z'), +(23.19700850470463, 44.59607717271034, '2077-11-30T12:28:41.635Z'), +(19.988325777313072, 46.61266062815267, '2077-11-30T12:30:03.635Z'), +(1.2541679503333005, 24.666550171487824, '2077-11-30T12:40:36.635Z'), +(6.375655852783733, 43.894798080415015, '2077-11-30T12:47:57.635Z'), +(16.808069754740075, 22.07777156900544, '2077-11-30T12:56:45.635Z'), +(8.152440378853345, 32.09664649167107, '2077-11-30T13:01:35.635Z'), +(0.0228918721031945, 38.4067479964014, '2077-11-30T13:05:23.635Z'), +(17.101175872818228, 40.580873084862006, '2077-11-30T13:11:45.635Z'), +(16.333824595217635, 49.310028253869476, '2077-11-30T13:14:51.635Z'), +(8.946295704390945, 34.43303608752552, '2077-11-30T13:20:52.635Z'), +(7.9517314118467315, 31.42498418273095, '2077-11-30T13:22:01.635Z'), +(11.91679505142427, 12.038550170584887, '2077-11-30T13:29:14.635Z'), +(5.99554606426675, 25.78163945489843, '2077-11-30T13:34:43.635Z'), +(16.590549557756265, 30.15214467609883, '2077-11-30T13:38:57.635Z'), +(5.330142523109689, 15.757041918602745, '2077-11-30T13:45:38.635Z'), +(2.448962714070897, 4.844449676107424, '2077-11-30T13:49:48.635Z'), +(1.3643898236519163, 36.958551926522176, '2077-11-30T14:01:42.635Z'), +(2.0976615864618653, 37.028579887735106, '2077-11-30T14:01:58.635Z'), +(9.722297081695352, 0.9463919213448465, '2077-11-30T14:15:33.635Z'), +(6.992566703388675, 49.651473968540415, '2077-11-30T14:33:25.635Z'), +(20.79244926360718, 47.93249015148092, '2077-11-30T14:38:34.635Z'), +(23.387575998765033, 18.810590827537272, '2077-11-30T14:48:35.635Z'), +(3.6833804057812416, 30.025009107574252, '2077-11-30T14:56:55.635Z'), +(9.093118396998282, 18.93645739566324, '2077-11-30T15:01:27.635Z'), +(6.71185043934182, 48.451371875701575, '2077-11-30T15:12:19.635Z'), +(3.452639650138501, 45.813222339501785, '2077-11-30T15:13:52.635Z'), +(10.968614347772673, 19.592914612900472, '2077-11-30T15:23:53.635Z'), +(1.693891291199342, 2.858877305120343, '2077-11-30T15:30:56.635Z'), +(5.113677788125118, 3.516914458176675, '2077-11-30T15:32:13.635Z'), +(6.409743984781038, 17.426585577247533, '2077-11-30T15:37:22.635Z'), +(14.37324476724037, 34.402876333459574, '2077-11-30T15:44:13.635Z'), +(20.723713677512592, 30.593248756476285, '2077-11-30T15:46:55.635Z'), +(19.582428028420594, 39.962367331783675, '2077-11-30T15:50:12.635Z'), +(23.170431256783992, 44.405980378889325, '2077-11-30T15:52:13.635Z'), +(4.47015555298169, 27.254622016095674, '2077-11-30T16:01:28.635Z'), +(23.22102312026555, 41.330355058437625, '2077-11-30T16:10:03.635Z'), +(0.90808160872273, 49.055127633513486, '2077-11-30T16:18:46.635Z'), +(16.801585042864783, 40.70411431853484, '2077-11-30T16:25:23.635Z'), +(17.131001547095064, 6.414732788638432, '2077-11-30T16:37:31.635Z'), +(3.201160537624619, 6.286049624162467, '2077-11-30T16:42:40.635Z'), +(19.666994734084103, 27.280719716644516, '2077-11-30T16:52:24.635Z'), +(18.56018099594569, 40.45982010935798, '2077-11-30T16:57:01.635Z'), +(17.996765369809555, 7.54294640335599, '2077-11-30T17:08:35.635Z'), +(7.444411148619711, 17.29194771964817, '2077-11-30T17:13:50.635Z'), +(3.8814735118466928, 16.59586242558631, '2077-11-30T17:15:10.635Z'), +(1.4773796973420588, 21.67247671265376, '2077-11-30T17:17:14.635Z'), +(23.306084163009288, 40.41134293434921, '2077-11-30T17:27:45.635Z'), +(0.7561100247945043, 13.815987328339657, '2077-11-30T17:40:27.635Z'), +(20.535583636244095, 38.14742518504137, '2077-11-30T17:51:54.635Z'), +(6.567251334069755, 3.7779243078757636, '2077-11-30T18:05:16.635Z'), +(11.434863594873706, 49.180035041824176, '2077-11-30T18:21:58.635Z'), +(6.088677645147562, 42.53192680987347, '2077-11-30T18:25:06.635Z'), +(7.7415132860096945, 4.70289391583849, '2077-11-30T18:39:01.635Z'), +(2.294670799359104, 21.13399073355659, '2077-11-30T18:45:24.635Z'), +(16.63771758413822, 3.5698771032246124, '2077-11-30T18:53:43.635Z'), +(8.669684632141303, 21.328319379114564, '2077-11-30T19:00:46.635Z'), +(0.7348884327657541, 22.79442843611491, '2077-11-30T19:03:45.635Z'), +(10.653510398964848, 48.15044046735682, '2077-11-30T19:13:47.635Z'), +(6.607030256612527, 30.576940022236734, '2077-11-30T19:20:23.635Z'), +(11.761498928636485, 23.5990990414497, '2077-11-30T19:23:34.635Z'), +(0.23488926461476747, 0.3111125024955013, '2077-11-30T19:33:08.635Z'), +(7.350064490463191, 41.60544053339736, '2077-11-30T19:48:37.635Z'), +(22.74370410024921, 13.178926969731647, '2077-11-30T20:00:14.635Z'), +(15.469552444846304, 48.065377351259656, '2077-11-30T20:12:42.635Z'), +(22.16662495242311, 15.88992430606214, '2077-11-30T20:24:14.635Z'), +(14.297227222444898, 16.602946374184295, '2077-11-30T20:27:09.635Z'), +(22.25824494738745, 45.58001182032619, '2077-11-30T20:37:44.635Z'), +(4.423263604384616, 37.55071657205478, '2077-11-30T20:44:56.635Z'), +(18.18351149837785, 48.98809875658154, '2077-11-30T20:51:30.635Z'), +(20.58030259925986, 20.393761090011292, '2077-11-30T21:01:31.635Z'), +(14.524580350737866, 33.41605518607184, '2077-11-30T21:06:38.635Z'), +(9.413170493694242, 35.32908241923798, '2077-11-30T21:08:39.635Z'), +(14.115369639522934, 44.336764766495655, '2077-11-30T21:12:21.635Z'), +(15.169405398423702, 49.79283354533716, '2077-11-30T21:14:20.635Z'), +(14.239273855563757, 41.93236326194634, '2077-11-30T21:17:10.635Z'), +(10.639324881139645, 0.17726130657549774, '2077-11-30T21:32:19.635Z'), +(1.9024343581413696, 29.88337109076939, '2077-11-30T21:43:43.635Z'), +(17.605760218256652, 12.68053230585458, '2077-11-30T21:52:15.635Z'), +(7.54316042963279, 17.443659825751432, '2077-11-30T21:56:21.635Z'), +(3.281040357073862, 24.63553347470871, '2077-11-30T21:59:26.635Z'), +(23.314583257259283, 36.12349861921849, '2077-11-30T22:07:55.635Z'), +(9.669665525868329, 43.47358886793049, '2077-11-30T22:13:36.635Z'), +(0.8258567181193482, 23.816215444435905, '2077-11-30T22:21:33.635Z'), +(15.578729278692585, 1.567405105045197, '2077-11-30T22:31:21.635Z'), +(19.512623240382656, 12.229752633717785, '2077-11-30T22:35:23.635Z'), +(20.453656600676037, 45.54392045132157, '2077-11-30T22:46:58.635Z'), +(5.463279818938581, 42.65458499672763, '2077-11-30T22:52:37.635Z'), +(15.917126857626744, 24.361120171953143, '2077-11-30T23:00:18.635Z'), +(1.2623314238795, 14.698720118817125, '2077-11-30T23:06:46.635Z'), +(13.22720821260787, 33.66330172214991, '2077-11-30T23:15:01.635Z'), +(19.526990029926147, 28.97707223361438, '2077-11-30T23:17:53.635Z'), +(10.39047702742658, 31.47889630673959, '2077-11-30T23:21:23.635Z'), +(12.570234510343422, 24.764262685529697, '2077-11-30T23:23:57.635Z'), +(9.973947378399465, 11.598635368904693, '2077-11-30T23:28:49.635Z'), +(20.436752739728814, 3.4894106843772743, '2077-11-30T23:33:39.635Z'), +(8.51366178807065, 49.702056329289, '2077-11-30T23:50:44.635Z'), +(18.877327173351603, 46.742666326009484, '2077-11-30T23:54:43.635Z'), +(23.517682902176592, 46.41546283088183, '2077-11-30T23:56:26.635Z'), +(12.695480643965, 21.97332987550297, '2077-12-01T00:05:54.635Z'), +(19.597536781984058, 10.344003563336548, '2077-12-01T00:10:45.635Z'), +(2.8617146336379466, 17.872893981864095, '2077-12-01T00:17:31.635Z'), +(20.12798558153271, 13.299716337028197, '2077-12-01T00:24:07.635Z'), +(7.827854345246383, 17.489687582209545, '2077-12-01T00:28:55.635Z'), +(21.068569899794383, 24.827845788081667, '2077-12-01T00:34:28.635Z'), +(8.404361149447887, 43.24724320439617, '2077-12-01T00:42:33.635Z'), +(1.4910718565241186, 7.971757937057481, '2077-12-01T00:55:48.635Z'), +(1.883183765905624, 20.3767488850047, '2077-12-01T01:00:23.635Z'), +(6.974707194033665, 0.542965176033202, '2077-12-01T01:07:56.635Z'), +(1.5594346810332858, 47.21156625611668, '2077-12-01T01:25:17.635Z'), +(9.632427785854198, 0.8407011614881132, '2077-12-01T01:42:37.635Z'), +(22.950715895110854, 49.2377492937225, '2077-12-01T02:00:26.635Z'), +(19.086440359227833, 7.187038825939854, '2077-12-01T02:15:00.635Z'), +(5.242927249034801, 19.716183965127684, '2077-12-01T02:21:50.635Z'), +(11.635990911183349, 46.25176136370574, '2077-12-01T02:31:50.635Z'), +(22.57729896047336, 0.02088417949376795, '2077-12-01T02:48:38.635Z'), +(3.3792073590970624, 6.5499968598095775, '2077-12-01T02:56:07.635Z'), +(13.333924913670351, 5.686427506691323, '2077-12-01T02:59:49.635Z'), +(3.2836256986683363, 49.542370274275086, '2077-12-01T03:16:17.635Z'), +(14.526726894112866, 49.71680023638386, '2077-12-01T03:20:27.635Z'), +(9.18755712292624, 49.3501081550729, '2077-12-01T03:22:26.635Z'), +(13.488611063583907, 48.87305401309991, '2077-12-01T03:24:02.635Z'), +(15.765094551283722, 28.028123383385747, '2077-12-01T03:31:33.635Z'), +(12.429011957784814, 20.26439269245915, '2077-12-01T03:34:36.635Z'), +(10.442518022941794, 34.47227369769493, '2077-12-01T03:39:48.635Z'), +(4.15039634410652, 14.951191415934728, '2077-12-01T03:47:20.635Z'), +(2.1539195707073753, 38.78172005611108, '2077-12-01T03:56:10.635Z'), +(21.130755330631715, 49.85463865635884, '2077-12-01T04:04:15.635Z'), +(11.629141547149763, 35.090409076655696, '2077-12-01T04:10:33.635Z'), +(2.7078606151072613, 48.915677747585704, '2077-12-01T04:16:36.635Z'), +(18.929332719109965, 22.993482425287958, '2077-12-01T04:27:45.635Z'), +(2.7738628609922564, 36.60019961749545, '2077-12-01T04:35:30.635Z'), +(19.699850904509013, 35.95160992864268, '2077-12-01T04:41:46.635Z'), +(17.198838399277943, 37.528700517577995, '2077-12-01T04:42:50.635Z'), +(13.033859885765818, 10.91843960938291, '2077-12-01T04:52:28.635Z'), +(7.502066088213096, 45.397474997213344, '2077-12-01T05:05:11.635Z'), +(16.41971699220856, 4.059531025888967, '2077-12-01T05:20:30.635Z'), +(12.314162476336065, 8.083855530274313, '2077-12-01T05:22:35.635Z'), +(11.320525791842746, 46.99911213983538, '2077-12-01T05:36:41.635Z'), +(12.847217954265373, 43.63813442770494, '2077-12-01T05:38:01.635Z'), +(15.59314609510114, 13.958659089252023, '2077-12-01T05:48:43.635Z'), +(4.837206807796465, 40.11507002715925, '2077-12-01T05:59:02.635Z'), +(15.74616638817999, 31.411293331868496, '2077-12-01T06:04:10.635Z'), +(8.6112226536358, 38.40337760578219, '2077-12-01T06:07:49.635Z'), +(17.96536157636823, 48.812386369483384, '2077-12-01T06:12:55.635Z'), +(18.188787960812267, 2.1217373178320664, '2077-12-01T06:29:19.635Z'), +(4.316444477878034, 3.3343344439610925, '2077-12-01T06:34:28.635Z'), +(6.348508967361746, 8.182708551077154, '2077-12-01T06:36:24.635Z'), +(0.35733006617507024, 9.080322633768072, '2077-12-01T06:38:38.635Z'), +(11.796724138578004, 34.122105342469006, '2077-12-01T06:48:46.635Z'), +(7.0405882908775705, 8.31892097161548, '2077-12-01T06:58:21.635Z'), +(1.6201057507907006, 16.79087239881504, '2077-12-01T07:02:04.635Z'), +(15.192143644260037, 30.622711195514235, '2077-12-01T07:09:12.635Z'), +(15.600537113198637, 39.07458266592142, '2077-12-01T07:12:13.635Z'), +(21.225711200431334, 17.56173054233617, '2077-12-01T07:20:03.635Z'), +(1.735968315506033, 21.29848860478078, '2077-12-01T07:27:23.635Z'), +(21.467647267794206, 10.467330783756163, '2077-12-01T07:35:40.635Z'), +(21.074359235968974, 27.312363579471807, '2077-12-01T07:41:29.635Z'), +(5.219412529152114, 38.19099897157006, '2077-12-01T07:48:32.635Z'), +(7.498391779384182, 46.90503904725794, '2077-12-01T07:51:51.635Z'), +(4.529420306602125, 27.20755606763243, '2077-12-01T07:59:11.635Z'), +(10.884722543115899, 41.26971820611237, '2077-12-01T08:04:51.635Z'), +(21.970922643005448, 47.9428890879495, '2077-12-01T08:09:35.635Z'), +(3.6907126614369217, 2.7407017338153943, '2077-12-01T08:27:10.635Z'), +(22.301254269261257, 11.277195683484905, '2077-12-01T08:34:42.635Z'), +(13.855160166186705, 36.06292376663456, '2077-12-01T08:43:57.635Z'), +(14.51227810071727, 11.2600646366727, '2077-12-01T08:52:51.635Z'), +(19.457549940228365, 13.558971691736813, '2077-12-01T08:54:51.635Z'), +(3.4117443075799763, 40.453873814322655, '2077-12-01T09:06:15.635Z'), +(20.17116211200461, 38.29411641829318, '2077-12-01T09:12:30.635Z'), +(3.5221535867229754, 0.593749947267738, '2077-12-01T09:27:26.635Z'), +(12.562582091207611, 36.5139112653798, '2077-12-01T09:41:01.635Z'), +(3.448551700893058, 26.955662774858865, '2077-12-01T09:45:53.635Z'), +(16.9755473720174, 30.630693993138166, '2077-12-01T09:51:04.635Z'), +(9.665413774877733, 46.680473582896674, '2077-12-01T09:57:27.635Z'), +(8.057792127390071, 21.190558666449384, '2077-12-01T10:06:48.635Z'), +(13.18917430812522, 5.979974028663333, '2077-12-01T10:12:39.635Z'), +(9.717579270320188, 22.366100946878685, '2077-12-01T10:18:44.635Z'), +(7.825673501363519, 21.256812459285236, '2077-12-01T10:19:32.635Z'), +(4.693762374713575, 29.16297124687311, '2077-12-01T10:22:40.635Z'), +(15.252547940272823, 33.852358204632566, '2077-12-01T10:26:56.635Z'), +(17.956923012388526, 17.244264351960272, '2077-12-01T10:32:54.635Z'), +(23.55921196900309, 41.02877999266621, '2077-12-01T10:41:23.635Z'), +(19.71984098513397, 33.73161853792297, '2077-12-01T10:44:16.635Z'), +(4.2544802340021555, 33.85076521604265, '2077-12-01T10:49:59.635Z'), +(22.64555306926497, 11.572130224573867, '2077-12-01T11:00:29.635Z'), +(15.509128807856563, 37.64299847691065, '2077-12-01T11:09:58.635Z'), +(7.137834982729134, 7.694841674881946, '2077-12-01T11:21:16.635Z'), +(0.42663716409976976, 45.971423942998086, '2077-12-01T11:35:37.635Z'), +(5.06395676871813, 4.543682581051038, '2077-12-01T11:51:02.635Z'), +(17.152977502066573, 41.26758370054591, '2077-12-01T12:05:05.635Z'), +(19.662264634947412, 21.701583036525857, '2077-12-01T12:12:01.635Z'), +(5.617665598357574, 25.37535900192317, '2077-12-01T12:17:23.635Z'), +(2.5362873721621804, 12.251246488547421, '2077-12-01T12:22:22.635Z'), +(4.566590399025232, 14.49862314285483, '2077-12-01T12:23:29.635Z'), +(8.366317310684442, 29.524949665582138, '2077-12-01T12:29:11.635Z'), +(13.30752934185465, 33.31091879609227, '2077-12-01T12:31:28.635Z'), +(5.175419997121033, 13.754803128841322, '2077-12-01T12:39:13.635Z'), +(21.23876001218122, 25.929546789152166, '2077-12-01T12:46:36.635Z'), +(16.68736198054031, 27.752418852648876, '2077-12-01T12:48:24.635Z'), +(7.233012144784733, 33.39484709289179, '2077-12-01T12:52:27.635Z'), +(18.976940819766007, 14.4605762679848, '2077-12-01T13:00:32.635Z'), +(5.5031776025900365, 1.6467600790361119, '2077-12-01T13:07:20.635Z'), +(9.564976579515658, 41.446612922507, '2077-12-01T13:22:01.635Z'), +(17.088656863269396, 35.315126281796346, '2077-12-01T13:25:34.635Z'), +(23.002810301390333, 49.30909910141845, '2077-12-01T13:30:54.635Z'), +(10.790718724886164, 10.554501479834244, '2077-12-01T13:45:18.635Z'), +(5.949850648277766, 4.351258249249054, '2077-12-01T13:48:11.635Z'), +(19.963348525512405, 15.712199866894595, '2077-12-01T13:54:47.635Z'), +(12.214604088495205, 10.850424130124573, '2077-12-01T13:58:08.635Z'), +(2.9989121304502557, 27.821165486889576, '2077-12-01T14:05:14.635Z'), +(18.771769766226694, 13.903862819976887, '2077-12-01T14:12:57.635Z'), +(6.837282580961571, 24.319253647854104, '2077-12-01T14:18:45.635Z'), +(5.4569634273275796, 31.431960165421856, '2077-12-01T14:21:25.635Z'), +(9.39344712984123, 22.75932528568036, '2077-12-01T14:24:55.635Z'), +(10.276348670702124, 48.872149824529565, '2077-12-01T14:34:27.635Z'), +(3.872675839989567, 30.911406434711694, '2077-12-01T14:41:27.635Z'), +(4.722666720236257, 18.78673461097819, '2077-12-01T14:45:56.635Z'), +(11.233924200138112, 39.15744999681918, '2077-12-01T14:53:47.635Z'), +(20.581584705368584, 5.134271897714831, '2077-12-01T15:06:22.635Z'), +(19.670598563412614, 20.774244583477035, '2077-12-01T15:11:49.635Z'), +(23.30821514779878, 16.47771251515034, '2077-12-01T15:13:49.635Z'), +(6.050894414835287, 49.225830586686044, '2077-12-01T15:27:07.635Z'), +(13.048146169890419, 49.167450779191476, '2077-12-01T15:29:42.635Z'), +(10.512989152472764, 48.43865350665182, '2077-12-01T15:30:40.635Z'), +(19.481057328784505, 43.53729517802494, '2077-12-01T15:34:25.635Z'), +(11.021807963729385, 32.2705464100101, '2077-12-01T15:39:31.635Z'), +(18.74138017819174, 36.93138633179665, '2077-12-01T15:42:49.635Z'), +(7.669668164643704, 10.325660307643068, '2077-12-01T15:53:14.635Z'), +(4.078794235769057, 27.203592549527215, '2077-12-01T15:59:35.635Z'), +(18.558486999695457, 24.812600153215055, '2077-12-01T16:05:01.635Z'), +(2.8031072478506633, 1.8222948040470002, '2077-12-01T16:15:11.635Z'), +(15.557639430516982, 43.684814789620525, '2077-12-01T16:31:10.635Z'), +(10.201179026172909, 8.960324313375825, '2077-12-01T16:43:51.635Z'), +(20.431064390649112, 44.97366194731676, '2077-12-01T16:57:14.635Z'), +(13.39958673399386, 4.826639366403144, '2077-12-01T17:11:40.635Z'), +(15.106393184767098, 10.969517239662387, '2077-12-01T17:13:57.635Z'), +(18.777757571377624, 44.38136601225183, '2077-12-01T17:25:51.635Z'), +(13.957453032978712, 45.29859333890149, '2077-12-01T17:27:39.635Z'), +(5.745286451059184, 20.830906261983042, '2077-12-01T17:37:04.635Z'), +(18.831199707393687, 28.968541491445297, '2077-12-01T17:42:44.635Z'), +(17.762732326430424, 47.819849662472734, '2077-12-01T17:49:22.635Z'), +(17.828015677781853, 25.317880715092496, '2077-12-01T17:57:18.635Z'), +(2.282467543803878, 22.254373727245802, '2077-12-01T18:03:10.635Z'), +(14.249916055624913, 13.607765785502496, '2077-12-01T18:08:36.635Z'), +(0.5157880101831045, 17.78944210809114, '2077-12-01T18:13:54.635Z'), +(14.352405906807128, 44.61472693938307, '2077-12-01T18:24:59.635Z'), +(4.23192742047047, 38.65241916283426, '2077-12-01T18:29:19.635Z'), +(18.004947821777066, 21.38426842314678, '2077-12-01T18:37:23.635Z'), +(20.374025876112142, 41.67449259136032, '2077-12-01T18:44:32.635Z'), +(17.00126723392889, 3.5579991570625324, '2077-12-01T18:57:56.635Z'), +(9.497883958619473, 14.644531184678165, '2077-12-01T19:02:48.635Z'), +(9.68311893742072, 8.818283422591504, '2077-12-01T19:04:55.635Z'), +(14.154654695893187, 42.88917842318034, '2077-12-01T19:17:22.635Z'), +(8.736189180690157, 13.61680973172021, '2077-12-01T19:28:10.635Z'), +(16.73281270678667, 47.92439530113921, '2077-12-01T19:40:53.635Z'), +(6.757486255699933, 23.059226663863, '2077-12-01T19:50:37.635Z'), +(9.466999656158938, 20.795361063467734, '2077-12-01T19:51:55.635Z'), +(5.196957661955133, 33.61590916572925, '2077-12-01T19:56:53.635Z'), +(21.221739246419222, 27.475058345136652, '2077-12-01T20:03:13.635Z'), +(12.46973421153695, 7.771062324845905, '2077-12-01T20:10:54.635Z'), +(20.229940668967686, 33.16130584337858, '2077-12-01T20:20:21.635Z'), +(10.597310813749862, 44.18098753363836, '2077-12-01T20:25:39.635Z'), +(19.792665247189543, 29.386627403806237, '2077-12-01T20:31:56.635Z'), +(10.33105884232514, 23.349649440733618, '2077-12-01T20:36:03.635Z'), +(11.71928845839799, 34.97860767705333, '2077-12-01T20:40:18.635Z'), +(9.354376843441685, 7.864082456294217, '2077-12-01T20:50:12.635Z'), +(22.960835588319288, 22.588543745943277, '2077-12-01T20:57:27.635Z'), +(15.507695721844446, 0.1554129077849525, '2077-12-01T21:05:45.635Z'), +(15.216300636177635, 3.8855469323914305, '2077-12-01T21:07:05.635Z'), +(4.2609575541502975, 2.641225355995585, '2077-12-01T21:11:10.635Z'), +(14.378393557933355, 1.4735840045806705, '2077-12-01T21:14:56.635Z'), +(8.15454440905919, 14.68117227900018, '2077-12-01T21:20:15.635Z'), +(0.6540883001451127, 27.56252948635366, '2077-12-01T21:25:45.635Z'), +(3.2678077512411163, 41.1141923001946, '2077-12-01T21:30:51.635Z'), +(1.1700702605460733, 49.079965794008494, '2077-12-01T21:33:54.635Z'), +(20.132044297055984, 31.097901949031773, '2077-12-01T21:43:29.635Z'), +(8.289674178328637, 28.2706802194554, '2077-12-01T21:47:59.635Z'), +(3.6787867317729135, 49.694276848342604, '2077-12-01T21:56:03.635Z'), +(13.538298155877532, 41.137129602847935, '2077-12-01T22:00:51.635Z'), +(15.961650078382073, 9.551426494507846, '2077-12-01T22:12:11.635Z'), +(10.176157045809875, 30.55954081515338, '2077-12-01T22:20:03.635Z'), +(22.825699301761883, 11.0714310168463, '2077-12-01T22:28:23.635Z'), +(22.537930746987517, 13.3874863468175, '2077-12-01T22:29:10.635Z'), +(0.7367266774752144, 32.13642342445061, '2077-12-01T22:39:42.635Z'), +(8.247556366735648, 30.95901289135665, '2077-12-01T22:42:31.635Z'), +(19.685691834548404, 33.59587125557414, '2077-12-01T22:46:51.635Z'), +(22.41170049564175, 27.273533968222136, '2077-12-01T22:49:15.635Z'), +(12.48087041823967, 34.815974790475686, '2077-12-01T22:53:47.635Z'), +(15.503722951862176, 40.096359394557766, '2077-12-01T22:55:59.635Z'), +(14.716928128590581, 24.74127784995063, '2077-12-01T23:01:29.635Z'), +(16.185226886616213, 5.532318268645908, '2077-12-01T23:08:21.635Z'), +(5.023124832963016, 40.13467622282206, '2077-12-01T23:21:35.635Z'), +(16.005669951787993, 37.29999767478011, '2077-12-01T23:25:46.635Z'), +(4.752807243127753, 49.65441293735419, '2077-12-01T23:31:53.635Z'), +(9.381737938256853, 13.912815543244387, '2077-12-01T23:45:08.635Z'), +(17.14696433971083, 50.25640620138061, '2077-12-01T23:58:32.635Z'), +(9.891677553659767, 34.77081973841446, '2077-12-02T00:04:43.635Z'), +(13.88652448572534, 44.5501720104661, '2077-12-02T00:08:33.635Z'), +(8.51971028482237, 48.561828689298125, '2077-12-02T00:11:00.635Z'), +(20.828988614698027, 1.927310453041162, '2077-12-02T00:28:15.635Z'), +(11.799444917182914, 1.8397642532844551, '2077-12-02T00:31:35.635Z'), +(5.067337980444818, 16.137225893675886, '2077-12-02T00:37:23.635Z'), +(16.29483615839898, 19.858467939013345, '2077-12-02T00:41:45.635Z'), +(18.01187353248497, 14.678086844404561, '2077-12-02T00:43:41.635Z'), +(14.278594712649134, 15.453995728803699, '2077-12-02T00:45:05.635Z'), +(10.963100863911531, 48.7687158415682, '2077-12-02T00:57:11.635Z'), +(9.497387133616215, 22.43323949728096, '2077-12-02T01:06:48.635Z'), +(5.028690346294655, 40.221784461502196, '2077-12-02T01:13:32.635Z'), +(9.45640925920732, 25.578770766147965, '2077-12-02T01:19:09.635Z'), +(15.308545923411025, 7.612437062473662, '2077-12-02T01:26:00.635Z'), +(8.341014099857329, 36.211986594062694, '2077-12-02T01:36:40.635Z'), +(22.187218523230204, 0.003902363455946936, '2077-12-02T01:50:32.635Z'), +(11.051758738820666, 19.529574825902266, '2077-12-02T01:58:35.635Z'), +(7.488625304592392, 20.611261781330548, '2077-12-02T01:59:57.635Z'), +(6.137338145115125, 15.152666430471376, '2077-12-02T02:02:01.635Z'), +(14.22529790039449, 8.623310621570127, '2077-12-02T02:05:50.635Z'), +(20.39421662985167, 5.870305474823008, '2077-12-02T02:08:19.635Z'), +(6.75518456717506, 32.488321857175904, '2077-12-02T02:19:07.635Z'), +(14.23593081844789, 18.803690004702485, '2077-12-02T02:24:49.635Z'), +(6.582631520002271, 25.438848197554282, '2077-12-02T02:28:32.635Z'), +(16.651605032879644, 42.594736528251275, '2077-12-02T02:35:47.635Z'), +(9.091619281229269, 40.09723326983176, '2077-12-02T02:38:43.635Z'), +(13.271861735238536, 16.27859495385341, '2077-12-02T02:47:30.635Z'), +(11.090180530835621, 20.55847045781597, '2077-12-02T02:49:14.635Z'), +(13.91054682728832, 38.68598984706495, '2077-12-02T02:55:52.635Z'), +(12.820422696294264, 8.107334228167034, '2077-12-02T03:06:53.635Z'), +(4.369660351449869, 16.09168385297851, '2077-12-02T03:11:10.635Z'), +(19.552777905932604, 13.068924972540303, '2077-12-02T03:16:53.635Z'), +(13.509147257931618, 34.35555294564975, '2077-12-02T03:24:45.635Z'), +(23.314339234532262, 15.259212397838128, '2077-12-02T03:32:22.635Z'), +(6.032807240819988, 44.872492316963445, '2077-12-02T03:44:43.635Z'), +(3.2085605835385285, 47.63101978656091, '2077-12-02T03:46:10.635Z'), +(5.143827044888595, 9.858891518908612, '2077-12-02T04:00:08.635Z'), +(23.352710536431157, 5.979402974428507, '2077-12-02T04:07:01.635Z'), +(8.183031648608942, 26.112730963794306, '2077-12-02T04:16:06.635Z'), +(7.00892216870683, 47.15186996953027, '2077-12-02T04:23:50.635Z'), +(6.189320286888957, 20.553708697972468, '2077-12-02T04:33:37.635Z'), +(7.777209352678181, 12.73190129580257, '2077-12-02T04:36:33.635Z'), +(12.160947707049974, 9.897621916345653, '2077-12-02T04:38:28.635Z'), +(12.026927321360741, 22.36139454965203, '2077-12-02T04:42:59.635Z'), +(6.727318463068251, 27.737296201652907, '2077-12-02T04:45:45.635Z'), +(4.6730124420026975, 10.902017977802505, '2077-12-02T04:52:00.635Z'), +(5.016498512321147, 38.56904569611214, '2077-12-02T05:02:13.635Z'), +(10.19710241272418, 45.284168974469246, '2077-12-02T05:05:20.635Z'), +(20.706759964854257, 0.8439860972004934, '2077-12-02T05:21:37.635Z'), +(6.8106177423751095, 22.780687027959715, '2077-12-02T05:31:01.635Z'), +(2.5221279093514033, 0.4234687569036354, '2077-12-02T05:39:25.635Z'), +(6.908790323223621, 40.672147174004216, '2077-12-02T05:54:22.635Z'), +(0.23074524036745164, 41.92996527212502, '2077-12-02T05:56:53.635Z'), +(0.40395064553349036, 25.98143863050237, '2077-12-02T06:02:47.635Z'), +(21.867826026885453, 25.791240569101205, '2077-12-02T06:10:44.635Z'), +(18.57829365343239, 43.453086896606955, '2077-12-02T06:16:59.635Z'), +(1.799839007064164, 32.108197665633675, '2077-12-02T06:24:26.635Z'), +(1.452514099226161, 47.347543820705134, '2077-12-02T06:30:04.635Z'), +(13.349028979299037, 43.17327332156729, '2077-12-02T06:34:44.635Z'), +(23.05760758421516, 4.554492913960203, '2077-12-02T06:48:45.635Z'), +(4.434081424456337, 37.62107935144476, '2077-12-02T07:02:26.635Z'), +(12.477710888481553, 12.07723788952991, '2077-12-02T07:12:15.635Z'), +(0.24681922946636098, 47.34736233798347, '2077-12-02T07:25:59.635Z'), +(22.621398170381685, 40.18672217031537, '2077-12-02T07:34:40.635Z'), +(12.813721743015419, 3.508202084010808, '2077-12-02T07:48:04.635Z'), +(0.13909898575605606, 6.019929123798768, '2077-12-02T07:52:51.635Z'), +(8.694926054305324, 18.6649274359358, '2077-12-02T07:58:29.635Z'), +(2.593521714884337, 0.3302603740049437, '2077-12-02T08:05:36.635Z'), +(5.010889716629855, 46.82091324604182, '2077-12-02T08:22:48.635Z'), +(19.990646286755887, 29.98551505974192, '2077-12-02T08:31:01.635Z'), +(12.950830854607474, 48.789150246845864, '2077-12-02T08:38:11.635Z'), +(19.971541469226786, 26.27647343819369, '2077-12-02T08:46:35.635Z'), +(13.756005947227868, 12.007957334823368, '2077-12-02T08:52:08.635Z'), +(21.061088959926913, 3.3450616912583615, '2077-12-02T08:56:13.635Z'), +(14.513173366739611, 39.76793071590454, '2077-12-02T09:09:16.635Z'), +(1.9233100657055993, 47.068012299400344, '2077-12-02T09:14:38.635Z'), +(23.41501601901987, 17.000486251611218, '2077-12-02T09:28:02.635Z'), +(19.61191186241547, 19.77273396453091, '2077-12-02T09:29:44.635Z'), +(3.382352292880387, 5.193695808115755, '2077-12-02T09:37:44.635Z'), +(13.745386412662254, 4.125010039052571, '2077-12-02T09:41:35.635Z'), +(10.22038075036653, 11.068507983796918, '2077-12-02T09:44:25.635Z'), +(4.769356052546267, 5.777597110109397, '2077-12-02T09:47:13.635Z'), +(20.59000074659978, 28.658476734123646, '2077-12-02T09:57:19.635Z'), +(15.816326093005415, 19.522015021624817, '2077-12-02T10:00:59.635Z'), +(3.886412970888994, 39.83979698394056, '2077-12-02T10:09:36.635Z'), +(17.40464444481592, 42.846494826324296, '2077-12-02T10:14:43.635Z'), +(15.941251017162738, 7.724783592331196, '2077-12-02T10:27:10.635Z'), +(14.123994130067036, 38.717556578444885, '2077-12-02T10:38:16.635Z'), +(4.57348356586874, 33.657760867756146, '2077-12-02T10:42:15.635Z'), +(13.507248703202508, 10.414968273349091, '2077-12-02T10:51:22.635Z'), +(17.762521073538533, 17.25464255231816, '2077-12-02T10:54:16.635Z'), +(14.847597540177562, 28.470351961129705, '2077-12-02T10:58:23.635Z'), +(20.524389696168935, 45.444787783108026, '2077-12-02T11:04:43.635Z'), +(2.033981565695186, 0.8542114742498162, '2077-12-02T11:22:13.635Z'), +(21.738478882069074, 6.331013086009235, '2077-12-02T11:29:46.635Z'), +(6.958603720662173, 2.5198805035897776, '2077-12-02T11:35:24.635Z'), +(7.837716008775839, 27.502735953745, '2077-12-02T11:44:35.635Z'), +(18.024576774343736, 27.207564611148744, '2077-12-02T11:48:21.635Z'), +(8.221372388439802, 4.110674695323218, '2077-12-02T11:57:25.635Z'), +(1.131896909884272, 9.350926721682413, '2077-12-02T12:00:40.635Z'), +(17.470694311662825, 27.43987720470687, '2077-12-02T12:09:37.635Z'), +(2.6266517712880226, 9.275575243793742, '2077-12-02T12:18:12.635Z'), +(20.783485666363656, 10.301362991364158, '2077-12-02T12:24:56.635Z'), +(22.281819835996025, 20.965274438348285, '2077-12-02T12:28:39.635Z'), +(2.01721263581406, 29.66895190369546, '2077-12-02T12:36:47.635Z'), +(17.028101766364482, 29.105457342506774, '2077-12-02T12:42:21.635Z'), +(9.871978495808156, 47.101785135969116, '2077-12-02T12:49:21.635Z'), +(4.140211644002526, 26.557473803265452, '2077-12-02T12:57:11.635Z'), +(16.797169522232377, 10.468376937688907, '2077-12-02T13:04:40.635Z'), +(2.698838933177439, 15.790092578450366, '2077-12-02T13:10:14.635Z'), +(1.757989451056314, 46.9020696807858, '2077-12-02T13:21:45.635Z'), +(21.430367674398614, 15.816586178966183, '2077-12-02T13:35:07.635Z'), +(18.184719729072935, 33.81610994483369, '2077-12-02T13:41:30.635Z'), +(18.382376202217817, 0.5658964821407093, '2077-12-02T13:53:11.635Z'), +(7.582845277480461, 4.097883488537609, '2077-12-02T13:57:23.635Z'), +(14.394871747703267, 34.633685464180815, '2077-12-02T14:08:45.635Z'), +(2.732560248250779, 9.398810428961118, '2077-12-02T14:18:56.635Z'), +(5.358699170076389, 33.89128355346617, '2077-12-02T14:28:02.635Z'), +(0.9062208438331784, 47.97860424361966, '2077-12-02T14:33:30.635Z'), +(23.29066375878776, 6.53927266723515, '2077-12-02T14:50:32.635Z'), +(5.352616197029669, 17.591494186051406, '2077-12-02T14:58:15.635Z'), +(3.3246156452120124, 8.638051182657875, '2077-12-02T15:01:38.635Z'), +(8.028137885494795, 47.729324196370996, '2077-12-02T15:16:08.635Z'), +(20.6381799006562, 49.72355930665499, '2077-12-02T15:20:51.635Z'), +(16.90368331850434, 13.814316267285518, '2077-12-02T15:33:30.635Z'), +(9.741049438415384, 6.395375422533727, '2077-12-02T15:37:16.635Z'), +(6.616939749222779, 38.942084734567985, '2077-12-02T15:49:15.635Z'), +(1.8644714087233338, 8.480324831695011, '2077-12-02T16:00:38.635Z'), +(20.410504824927823, 34.99442365343314, '2077-12-02T16:12:26.635Z'), +(0.4558237744971994, 17.300749718740825, '2077-12-02T16:22:13.635Z'), +(13.203372089006484, 31.661963942525947, '2077-12-02T16:29:17.635Z'), +(2.5843632025901275, 48.12055149304579, '2077-12-02T16:36:29.635Z'), +(14.747213783712189, 22.49623330282596, '2077-12-02T16:46:52.635Z'), +(7.406067978959748, 8.91886610301316, '2077-12-02T16:52:30.635Z'), +(2.8819879842114893, 42.84069330406337, '2077-12-02T17:05:07.635Z'), +(9.918087933973933, 3.124428832359177, '2077-12-02T17:19:57.635Z'), +(17.928129153382923, 9.833459467565206, '2077-12-02T17:23:46.635Z'), +(4.528022200216062, 0.6150900523862922, '2077-12-02T17:29:45.635Z'), +(5.0785955097885305, 34.7080395801947, '2077-12-02T17:42:20.635Z'), +(2.2414800311370797, 47.05835721450065, '2077-12-02T17:47:01.635Z'), +(14.310279190269377, 16.23532253702411, '2077-12-02T17:59:09.635Z'), +(13.005107788602924, 15.115239242000646, '2077-12-02T17:59:46.635Z'), +(1.8657050751501256, 41.18612649666223, '2077-12-02T18:10:11.635Z'), +(6.642749093290672, 23.130255136941713, '2077-12-02T18:17:05.635Z'), +(8.8010286039398, 32.07560693547331, '2077-12-02T18:20:27.635Z'), +(2.0698013407346108, 29.09794059647514, '2077-12-02T18:23:10.635Z'), +(8.444206654492328, 8.355389560879786, '2077-12-02T18:31:10.635Z'), +(9.19864553033201, 41.213653396152765, '2077-12-02T18:43:12.635Z'), +(21.04538073381088, 3.5855297957988665, '2077-12-02T18:57:19.635Z'), +(9.621233061746086, 2.4796321699755204, '2077-12-02T19:01:34.635Z'), +(20.058098992894724, 25.415010626259555, '2077-12-02T19:10:37.635Z'), +(10.989086000831795, 44.468304457882056, '2077-12-02T19:18:11.635Z'), +(10.55683061434936, 1.1751304704342258, '2077-12-02T19:33:56.635Z'), +(0.15788511634100458, 44.678246073615625, '2077-12-02T19:50:25.635Z'), +(1.2510861307329415, 32.40897277685734, '2077-12-02T19:54:58.635Z'), +(10.307974223744315, 45.733337112714004, '2077-12-02T20:00:54.635Z'), +(1.5061172855323628, 42.51295617427828, '2077-12-02T20:04:22.635Z'), +(0.5252555638621528, 42.5934948831756, '2077-12-02T20:04:43.635Z'), +(23.011626968682116, 2.8905606125426466, '2077-12-02T20:21:15.635Z'), +(22.791027375054814, 36.08280640105431, '2077-12-02T20:32:33.635Z'), +(0.264441713762866, 34.15123465646571, '2077-12-02T20:40:55.635Z'), +(17.030909947150498, 45.68260921237507, '2077-12-02T20:48:25.635Z'), +(15.690207451838477, 9.867373738960476, '2077-12-02T21:01:08.635Z'), +(21.960031506345082, 41.82743785361401, '2077-12-02T21:12:33.635Z'), +(22.922248721920187, 6.290388829794161, '2077-12-02T21:24:41.635Z'), +(8.83702926827686, 26.777918581280915, '2077-12-02T21:33:38.635Z'), +(18.142643650180737, 30.786120690905204, '2077-12-02T21:37:22.635Z'), +(18.422982253047756, 28.024516710848694, '2077-12-02T21:38:20.635Z'), +(0.7091704741589933, 22.53624092684386, '2077-12-02T21:45:11.635Z'), +(18.691740506312478, 48.01639830783524, '2077-12-02T21:56:35.635Z'), +(12.980531187591458, 24.483126171771747, '2077-12-02T22:05:13.635Z'), +(4.881910582129925, 14.602852874294914, '2077-12-02T22:09:54.635Z'), +(9.840196174620749, 24.949267588185464, '2077-12-02T22:14:07.635Z'), +(19.996611119928893, 38.25244290182798, '2077-12-02T22:20:10.635Z'), +(10.673289412502175, 47.563316830089924, '2077-12-02T22:24:57.635Z'), +(3.5335659144347242, 26.47960518147161, '2077-12-02T22:33:08.635Z'), +(8.938621540961531, 35.62401838163028, '2077-12-02T22:37:03.635Z'), +(9.421049586909131, 30.767916612014336, '2077-12-02T22:38:50.635Z'), +(1.9433398692917323, 48.94554530392796, '2077-12-02T22:46:04.635Z'), +(12.004377949650332, 31.389899327186622, '2077-12-02T22:53:31.635Z'), +(19.64491901701923, 42.64223227268975, '2077-12-02T22:58:25.635Z'), +(23.260274770945525, 43.21905054291833, '2077-12-02T22:59:46.635Z'), +(19.4145521015017, 7.879842136548704, '2077-12-02T23:12:01.635Z'), +(4.2293233365128575, 19.852574405922017, '2077-12-02T23:19:07.635Z'), +(1.9840176008136166, 8.107779244678998, '2077-12-02T23:23:32.635Z'), +(7.562712995838274, 24.2002871137398, '2077-12-02T23:29:49.635Z'), +(1.9468121065179507, 47.82110376567364, '2077-12-02T23:38:46.635Z'), +(22.781540181763145, 45.44386500874125, '2077-12-02T23:46:32.635Z'), +(4.613097681231626, 38.411929518112125, '2077-12-02T23:53:43.635Z'), +(10.106458599224595, 2.997099044607578, '2077-12-03T00:06:53.635Z'), +(8.045528169408522, 22.88952067731495, '2077-12-03T00:14:12.635Z'), +(0.6139146834974799, 13.202101554834414, '2077-12-03T00:18:42.635Z'), +(20.979206061656285, 12.587915753338983, '2077-12-03T00:26:15.635Z'), +(21.357157257242466, 45.35785524856072, '2077-12-03T00:37:33.635Z'), +(19.002593157317442, 45.54318701027836, '2077-12-03T00:38:25.635Z'), +(8.888714723606803, 13.014039802932807, '2077-12-03T00:50:40.635Z'), +(18.139317540843024, 24.944866505361578, '2077-12-03T00:56:09.635Z'), +(17.650477668271368, 3.3173192996673255, '2077-12-03T01:03:46.635Z'), +(23.501666864089355, 39.8660851269013, '2077-12-03T01:16:35.635Z'), +(12.84113071473946, 4.132881668419838, '2077-12-03T01:29:43.635Z'), +(11.811037854888133, 31.52626782215269, '2077-12-03T01:39:38.635Z'), +(13.809374193271266, 26.434773970368674, '2077-12-03T01:41:37.635Z'), +(16.453924304304387, 43.260469031952525, '2077-12-03T01:47:42.635Z'), +(20.937748442459746, 47.306891480791734, '2077-12-03T01:49:53.635Z'), +(5.132374371299636, 26.148259891120077, '2077-12-03T01:59:29.635Z'), +(21.967181850583984, 5.480561952068925, '2077-12-03T02:09:10.635Z'), +(19.05708638465443, 41.135715040939786, '2077-12-03T02:21:33.635Z'), +(3.478974575451056, 3.09977817839609, '2077-12-03T02:36:28.635Z'), +(7.941763486484601, 29.32931287634403, '2077-12-03T02:46:16.635Z'), +(1.751191156018859, 35.35518510603961, '2077-12-03T02:49:27.635Z'), +(11.049866637997035, 23.65660111844099, '2077-12-03T02:54:57.635Z'), +(0.6139508582355261, 15.494013768837828, '2077-12-03T02:59:50.635Z'), +(12.964410193751283, 23.829597999717173, '2077-12-03T03:05:20.635Z'), +(11.498706279859652, 5.9828072675792745, '2077-12-03T03:11:49.635Z'), +(3.9510982832762225, 45.2209515986864, '2077-12-03T03:26:28.635Z'), +(4.769242670432844, 45.87023285553176, '2077-12-03T03:26:51.635Z'), +(17.86102521619812, 12.727340145598209, '2077-12-03T03:39:48.635Z'), +(20.54176473328376, 9.724347485420399, '2077-12-03T03:41:14.635Z'), +(17.65396395539584, 49.54302852277933, '2077-12-03T03:55:11.635Z'), +(15.181889540267358, 20.521324026990225, '2077-12-03T04:05:31.635Z'), +(5.089804413560084, 19.813734734325497, '2077-12-03T04:09:15.635Z'), +(0.03697575602451041, 26.79084446258726, '2077-12-03T04:12:26.635Z'), +(0.8860774470904623, 35.07821510834092, '2077-12-03T04:15:31.635Z'), +(3.10220302290822, 32.22649988640799, '2077-12-03T04:16:51.635Z'), +(23.223905325081173, 26.69883072507088, '2077-12-03T04:24:34.635Z'), +(2.099778649808096, 31.47846979821842, '2077-12-03T04:32:34.635Z'), +(6.089503901167868, 43.75408274210339, '2077-12-03T04:37:20.635Z'), +(8.37090550135066, 27.293398642150624, '2077-12-03T04:43:26.635Z'), +(0.4522412235440566, 20.17322242953016, '2077-12-03T04:47:22.635Z'), +(1.9661385302560608, 32.08422004644195, '2077-12-03T04:51:48.635Z'), +(1.207530246768412, 25.705307858245664, '2077-12-03T04:54:10.635Z'), +(7.657899477486654, 14.062880714319613, '2077-12-03T04:59:05.635Z'), +(7.813961620457563, 10.097576062366521, '2077-12-03T05:00:32.635Z'), +(18.111329384267425, 12.791816593524306, '2077-12-03T05:04:28.635Z'), +(20.920452866749446, 13.011874084387964, '2077-12-03T05:05:30.635Z'), +(10.472542339116544, 25.18122607965576, '2077-12-03T05:11:18.635Z'), +(19.939637462180723, 15.837503820449422, '2077-12-03T05:16:08.635Z'), +(11.90411927606549, 23.434281937879657, '2077-12-03T05:20:09.635Z'), +(2.366973470369676, 33.47045575217297, '2077-12-03T05:25:15.635Z'), +(11.919625840810903, 7.011629501978917, '2077-12-03T05:35:35.635Z'), +(17.9030366103695, 31.07118405582946, '2077-12-03T05:44:28.635Z'), +(16.898732508963665, 13.08395529236256, '2077-12-03T05:50:50.635Z'), +(5.6185706730061336, 17.023769407346155, '2077-12-03T05:55:15.635Z'), +(2.5569438050696784, 28.430010072686347, '2077-12-03T05:59:36.635Z'), +(23.058533729903893, 36.3812270226136, '2077-12-03T06:07:43.635Z'), +(0.10032569042363947, 41.48924806158924, '2077-12-03T06:16:25.635Z'), +(5.065622365947315, 11.245480932521332, '2077-12-03T06:27:45.635Z'), +(15.590342218609324, 44.223178342802534, '2077-12-03T06:40:22.635Z'), +(13.048462289025224, 18.45481501903485, '2077-12-03T06:49:39.635Z'), +(18.631935809637472, 2.1185351795791996, '2077-12-03T06:55:49.635Z'), +(19.407516947623503, 29.839526595066985, '2077-12-03T07:05:31.635Z'), +(16.2074675002946, 37.46109282674261, '2077-12-03T07:08:27.635Z'), +(7.694488139090944, 31.917653373732747, '2077-12-03T07:12:11.635Z'), +(4.7839644565170465, 19.333413359622497, '2077-12-03T07:16:56.635Z'), +(22.095803909931444, 13.327880162921366, '2077-12-03T07:23:42.635Z'), +(18.442069061335186, 26.491287524523234, '2077-12-03T07:28:28.635Z'), +(8.377512132171896, 46.29454409602574, '2077-12-03T07:36:30.635Z'), +(12.112588723002773, 8.529132670133434, '2077-12-03T07:50:19.635Z'), +(5.882418517019949, 15.020632182389065, '2077-12-03T07:53:37.635Z'), +(19.57214576981868, 37.31342960623334, '2077-12-03T08:03:07.635Z'), +(4.795885734747944, 8.301025079858755, '2077-12-03T08:14:56.635Z'), +(7.433217871704273, 12.548497564128416, '2077-12-03T08:16:46.635Z'), +(10.098837257280675, 13.652763694193569, '2077-12-03T08:17:50.635Z'), +(10.941912253929411, 49.94234286245723, '2077-12-03T08:31:03.635Z'), +(1.775487487212059, 13.139075967929115, '2077-12-03T08:45:00.635Z'), +(11.258429211570599, 21.641542615547806, '2077-12-03T08:49:42.635Z'), +(17.956392332622908, 7.584505628566413, '2077-12-03T08:55:18.635Z'), +(11.842008737042487, 18.27351166994934, '2077-12-03T08:59:44.635Z'), +(10.538523722121617, 11.544151799886883, '2077-12-03T09:02:13.635Z'), +(10.439534353954054, 48.73773257132341, '2077-12-03T09:15:45.635Z'), +(2.879390665476238, 20.91747552163176, '2077-12-03T09:26:21.635Z'), +(4.998473075710722, 21.195695589463437, '2077-12-03T09:27:08.635Z'), +(22.570750172091998, 41.82041223763826, '2077-12-03T09:36:58.635Z'), +(19.519179796932885, 7.990230613360165, '2077-12-03T09:48:41.635Z'), +(5.547721585887063, 27.061883576773585, '2077-12-03T09:57:17.635Z'), +(22.86626418940162, 34.437054735254144, '2077-12-03T10:04:13.635Z'), +(6.076949945269039, 37.502390048911245, '2077-12-03T10:10:32.635Z'), +(12.208232542576933, 35.136426752784324, '2077-12-03T10:12:57.635Z'), +(20.1714665622137, 40.419731776689666, '2077-12-03T10:16:26.635Z'), +(22.399936369220992, 29.642317955736644, '2077-12-03T10:20:14.635Z'), +(19.913828323018897, 36.977732733467576, '2077-12-03T10:22:55.635Z'), +(12.51238790346233, 39.830756051765455, '2077-12-03T10:25:50.635Z'), +(7.814379672277712, 48.073510449919304, '2077-12-03T10:29:18.635Z'), +(15.33948728728391, 25.124843564261145, '2077-12-03T10:38:04.635Z'), +(20.02622525776165, 23.671298556706642, '2077-12-03T10:39:52.635Z'), +(21.783661226322515, 1.1426709837722029, '2077-12-03T10:47:41.635Z'), +(22.958544725982772, 33.26106640989976, '2077-12-03T10:58:40.635Z'), +(14.550028298541351, 12.924425092503302, '2077-12-03T11:06:26.635Z'), +(2.990366843714898, 12.41015721474081, '2077-12-03T11:10:43.635Z'), +(22.4532375019913, 28.066592134446672, '2077-12-03T11:19:51.635Z'), +(11.976945407698697, 41.60445789799555, '2077-12-03T11:26:00.635Z'), +(10.923265546482702, 3.7021625435122476, '2077-12-03T11:39:45.635Z'), +(14.680228526642665, 15.929282019539455, '2077-12-03T11:44:22.635Z'), +(8.065860506841464, 32.41840840445689, '2077-12-03T11:50:50.635Z'), +(8.799451006877787, 33.21111407616187, '2077-12-03T11:51:13.635Z'), +(22.597505864625948, 45.04135817303501, '2077-12-03T11:57:50.635Z'), +(5.038163685523123, 10.705229508936851, '2077-12-03T12:11:44.635Z'), +(21.003015002364457, 38.32147637536179, '2077-12-03T12:23:17.635Z'), +(4.481782815571623, 37.66599505822084, '2077-12-03T12:29:24.635Z'), +(5.540857756050589, 15.31322651929412, '2077-12-03T12:37:39.635Z'), +(1.8937951682332228, 48.99251619621969, '2077-12-03T12:50:10.635Z'), +(22.934624176912642, 8.22014079944596, '2077-12-03T13:06:45.635Z'), +(22.808606615684727, 20.73020368508481, '2077-12-03T13:11:01.635Z'), +(12.077085332444973, 10.168278144170339, '2077-12-03T13:16:28.635Z'), +(1.4380353158823984, 23.505277575115663, '2077-12-03T13:22:45.635Z'), +(21.634667309564016, 24.242803600668374, '2077-12-03T13:30:14.635Z'), +(3.862143660491665, 34.555827149616356, '2077-12-03T13:37:47.635Z'), +(2.6738806008103913, 8.76701872233981, '2077-12-03T13:47:20.635Z'), +(6.239129080964969, 12.087711419399735, '2077-12-03T13:49:08.635Z'), +(11.618394838695053, 15.744518654752337, '2077-12-03T13:51:32.635Z'), +(7.263628132986623, 22.798295062127096, '2077-12-03T13:54:34.635Z'), +(15.56458175444611, 49.1354989838439, '2077-12-03T14:04:36.635Z'), +(0.08294921114473376, 44.49689120238472, '2077-12-03T14:10:35.635Z'), +(0.8058714264635375, 30.247367098745134, '2077-12-03T14:15:52.635Z'), +(5.44143658923388, 42.03296855921476, '2077-12-03T14:20:33.635Z'), +(13.403641828650018, 18.14575716086721, '2077-12-03T14:29:45.635Z'), +(4.413188515597769, 16.79909807948508, '2077-12-03T14:33:07.635Z'), +(18.80744511835726, 18.33595074538922, '2077-12-03T14:38:28.635Z'), +(22.876251777669918, 45.9935046531425, '2077-12-03T14:48:09.635Z'), +(22.66448410007337, 37.297715929257734, '2077-12-03T14:51:07.635Z'), +(10.246228621171241, 41.551055850433215, '2077-12-03T14:55:57.635Z'), +(0.5900603149618965, 27.052934574120158, '2077-12-03T15:02:22.635Z'), +(17.03605560453942, 4.895787216113959, '2077-12-03T15:12:29.635Z'), +(20.314380374892863, 42.018299752173064, '2077-12-03T15:25:32.635Z'), +(16.923938948232372, 1.7179135290891163, '2077-12-03T15:39:42.635Z'), +(7.3967756126237205, 47.44151108221327, '2077-12-03T15:56:35.635Z'), +(9.045260183426304, 0.735143360719508, '2077-12-03T16:13:43.635Z'), +(21.928904388534583, 24.415438226964586, '2077-12-03T16:23:24.635Z'), +(7.054489286284189, 43.40272256001516, '2077-12-03T16:32:08.635Z'), +(14.181345048345284, 43.1302335173219, '2077-12-03T16:34:46.635Z'), +(1.0695326912277912, 4.590694327862482, '2077-12-03T16:49:42.635Z'), +(1.5551816507362006, 44.58703688307883, '2077-12-03T17:04:31.635Z'), +(11.71282334178283, 42.071499846539496, '2077-12-03T17:08:23.635Z'), +(18.71028167931531, 20.924394342353743, '2077-12-03T17:16:22.635Z'), +(18.81785006822464, 5.958440896706142, '2077-12-03T17:21:37.635Z'), +(22.55160553121639, 10.726640874586023, '2077-12-03T17:23:46.635Z'), +(20.509381206271645, 16.829628681533052, '2077-12-03T17:26:00.635Z'), +(21.131635017293494, 42.43132629075059, '2077-12-03T17:34:51.635Z'), +(1.5289723158977957, 16.066577172153494, '2077-12-03T17:46:49.635Z'), +(5.4868309542159865, 41.53675032121082, '2077-12-03T17:56:21.635Z'), +(8.817015924363227, 10.446873615187602, '2077-12-03T18:07:50.635Z'), +(20.04076718455703, 16.542498926079652, '2077-12-03T18:12:31.635Z'), +(3.334033864885504, 22.80039294588613, '2077-12-03T18:19:06.635Z'), +(3.3039029279504346, 6.76643131417076, '2077-12-03T18:25:01.635Z'), +(18.159946112321315, 42.70239028524819, '2077-12-03T18:39:10.635Z'), +(6.391718458441396, 27.34868001504648, '2077-12-03T18:46:13.635Z'), +(19.240842453891798, 13.431087085596237, '2077-12-03T18:53:08.635Z'), +(20.14965719374634, 33.44776261227469, '2077-12-03T19:00:07.635Z'), +(3.181856111423321, 36.13999553443657, '2077-12-03T19:06:28.635Z'), +(3.7221532927833194, 11.195827441957512, '2077-12-03T19:15:41.635Z'), +(7.417516086869024, 48.705605593909155, '2077-12-03T19:29:35.635Z'), +(12.84843420917751, 21.377491167194584, '2077-12-03T19:39:44.635Z'), +(3.6627267829078725, 20.97868340410504, '2077-12-03T19:43:08.635Z'), +(15.353574787765487, 43.499117422392295, '2077-12-03T19:52:25.635Z'), +(20.263930483217887, 13.893416763240173, '2077-12-03T20:03:00.635Z'), +(6.460594486505298, 0.571696909499083, '2077-12-03T20:10:00.635Z'), +(23.339473048380313, 24.571505785374026, '2077-12-03T20:20:35.635Z'), +(12.084788941886996, 47.8939584589418, '2077-12-03T20:29:47.635Z'), +(1.4922368912280122, 5.8138905500074625, '2077-12-03T20:45:43.635Z'), +(9.148881478057282, 39.92383009997476, '2077-12-03T20:58:36.635Z'), +(10.539481929240187, 47.07733272212859, '2077-12-03T21:01:15.635Z'), +(12.31085666940257, 39.61002560871704, '2077-12-03T21:04:02.635Z'), +(11.978228388924052, 16.621324419408317, '2077-12-03T21:12:21.635Z'), +(14.060476142789216, 44.910528127224474, '2077-12-03T21:22:35.635Z'), +(8.486569056253968, 37.67768335520161, '2077-12-03T21:25:55.635Z'), +(4.373138054523839, 36.84286768043741, '2077-12-03T21:27:28.635Z'), +(6.6081201823256785, 48.955624418736726, '2077-12-03T21:32:00.635Z'), +(5.981345956240833, 15.698784422991372, '2077-12-03T21:44:15.635Z'), +(6.619532696936475, 14.57514773935007, '2077-12-03T21:44:43.635Z'), +(7.538699512014944, 21.436843413525214, '2077-12-03T21:47:15.635Z'), +(10.754922223824488, 36.286472919976084, '2077-12-03T21:52:48.635Z'), +(6.600112165708422, 31.039960213681688, '2077-12-03T21:55:15.635Z'), +(19.205285719571485, 32.308555836904006, '2077-12-03T21:59:56.635Z'), +(18.531654770690544, 48.20724371810191, '2077-12-03T22:05:30.635Z'), +(11.08855026015329, 19.825860817737773, '2077-12-03T22:16:01.635Z'), +(0.06391776423188703, 45.13207498779247, '2077-12-03T22:26:11.635Z'), +(4.906513793198326, 21.911637893224565, '2077-12-03T22:34:57.635Z'), +(15.73915511618742, 29.11420427434103, '2077-12-03T22:39:44.635Z'), +(6.079094022053196, 49.89344293574546, '2077-12-03T22:48:05.635Z'), +(21.91354082537294, 41.67055814455389, '2077-12-03T22:54:39.635Z'), +(7.988618687097582, 50.034456197394285, '2077-12-03T23:00:36.635Z'), +(2.673269954005914, 23.34501072309989, '2077-12-03T23:10:38.635Z'), +(20.63017624011356, 12.429818229796561, '2077-12-03T23:18:22.635Z'), +(9.074441170925986, 8.034279734645372, '2077-12-03T23:22:55.635Z'), +(3.0730776239629725, 19.51779674043838, '2077-12-03T23:27:41.635Z'), +(13.397017336287952, 25.348520295669434, '2077-12-03T23:32:03.635Z'), +(16.87221041840019, 18.877004361490638, '2077-12-03T23:34:41.635Z'), +(11.51849560736424, 46.410636919800396, '2077-12-03T23:44:45.635Z'), +(18.470556021651337, 34.46213695565431, '2077-12-03T23:49:44.635Z'), +(21.97691683663632, 44.94308645559815, '2077-12-03T23:53:36.635Z'), +(0.5962232167630485, 19.232275937159393, '2077-12-04T00:05:48.635Z'), +(10.85827218099936, 25.51043398692524, '2077-12-04T00:10:15.635Z'), +(16.416355845500494, 26.802479244174634, '2077-12-04T00:12:21.635Z'), +(16.6692459828122, 33.8408840111388, '2077-12-04T00:14:51.635Z'), +(7.982029475883958, 22.42521981162648, '2077-12-04T00:20:05.635Z'), +(21.622372033929427, 49.217702110721596, '2077-12-04T00:30:54.635Z'), +(17.102888650613544, 15.803480569266943, '2077-12-04T00:42:40.635Z'), +(6.42141158312458, 26.08147062754077, '2077-12-04T00:48:06.635Z'), +(13.715260721035124, 49.62415281004737, '2077-12-04T00:57:05.635Z'), +(3.292159837168906, 38.05367625970465, '2077-12-04T01:02:48.635Z'), +(11.790446154135074, 40.33303702025529, '2077-12-04T01:06:03.635Z'), +(8.00963283095468, 21.082131437279195, '2077-12-04T01:13:12.635Z'), +(19.228711680750624, 42.04255193544996, '2077-12-04T01:21:48.635Z'), +(19.81728673569874, 32.87301990561867, '2077-12-04T01:25:00.635Z'), +(0.06768217782903639, 8.701656984449354, '2077-12-04T01:36:25.635Z'), +(7.276426825066795, 5.108110370798564, '2077-12-04T01:39:24.635Z'), +(8.908798602107725, 23.628734312029213, '2077-12-04T01:46:13.635Z'), +(10.264246509970718, 5.86822985407201, '2077-12-04T01:52:43.635Z'), +(8.683326422336755, 44.67094720246407, '2077-12-04T02:06:54.635Z'), +(14.855635364819044, 40.44335940362639, '2077-12-04T02:09:39.635Z'), +(2.4811854790310277, 46.015894017977516, '2077-12-04T02:14:40.635Z'), +(19.981996333206286, 35.110136222603415, '2077-12-04T02:22:15.635Z'), +(8.425553024833063, 23.159184056460063, '2077-12-04T02:28:18.635Z'), +(18.67631063962994, 0.27392590779294257, '2077-12-04T02:37:21.635Z'), +(9.661791691945286, 18.072875686106922, '2077-12-04T02:44:33.635Z'), +(7.400523523703143, 18.708069873199317, '2077-12-04T02:45:25.635Z'), +(8.527133808596613, 9.30362663218011, '2077-12-04T02:48:53.635Z'), +(3.2206958219870336, 40.39433841523, '2077-12-04T03:00:30.635Z'), +(16.02710753523428, 11.805076834195425, '2077-12-04T03:11:57.635Z'), +(18.816864095077705, 44.55288029232004, '2077-12-04T03:23:33.635Z'), +(8.189650691677627, 14.02276647528681, '2077-12-04T03:35:12.635Z'), +(8.524709827097, 44.747323930357396, '2077-12-04T03:46:27.635Z'), +(7.042440746397029, 12.787809226837894, '2077-12-04T03:58:11.635Z'), +(1.3212051383537327, 24.28980520355796, '2077-12-04T04:02:55.635Z'), +(3.861777520465295, 20.157837664105422, '2077-12-04T04:04:42.635Z'), +(3.7737289368598526, 43.15252100324607, '2077-12-04T04:13:12.635Z'), +(12.738886729797143, 49.10892370251708, '2077-12-04T04:17:10.635Z'), +(0.35390081794911826, 21.437354258042316, '2077-12-04T04:28:19.635Z'), +(14.912182260838458, 45.08323683194915, '2077-12-04T04:38:31.635Z'), +(8.751653118040647, 37.50168608742098, '2077-12-04T04:42:05.635Z'), +(15.328680618549793, 16.206692623606127, '2077-12-04T04:50:10.635Z'), +(0.35619971192704336, 19.107465293552586, '2077-12-04T04:55:49.635Z'), +(15.06656084851453, 41.7748454770603, '2077-12-04T05:05:44.635Z'), +(11.993356080208569, 43.85344688023583, '2077-12-04T05:07:05.635Z'), +(7.421089749697728, 29.836344766638224, '2077-12-04T05:12:28.635Z'), +(11.88684161423844, 10.783609884450852, '2077-12-04T05:19:37.635Z'), +(22.207457645679188, 7.106270351302897, '2077-12-04T05:23:39.635Z'), +(17.492901126458584, 15.490711083085124, '2077-12-04T05:27:03.635Z'), +(10.745621652185605, 33.87414164200575, '2077-12-04T05:34:06.635Z'), +(9.045313452469177, 22.612224063458605, '2077-12-04T05:38:15.635Z'), +(0.7931884221613558, 9.445466858392995, '2077-12-04T05:43:59.635Z'), +(13.825944680684502, 43.590683106012, '2077-12-04T05:57:24.635Z'), +(22.520544403850625, 19.24430656300485, '2077-12-04T06:06:32.635Z'), +(14.67203888922454, 38.35609117536844, '2077-12-04T06:13:50.635Z'), +(10.455672277541602, 38.646852737073914, '2077-12-04T06:15:23.635Z'), +(17.72186997598762, 18.62871884877788, '2077-12-04T06:23:03.635Z'), +(1.6744939536033903, 8.685315261573404, '2077-12-04T06:30:00.635Z'), +(1.0299765412104713, 7.748473574664276, '2077-12-04T06:30:25.635Z'), +(0.7572950210907572, 22.080323614649295, '2077-12-04T06:35:43.635Z'), +(17.16211421692363, 39.546033227638155, '2077-12-04T06:44:31.635Z'), +(19.783718204435132, 16.891946308599227, '2077-12-04T06:52:32.635Z'), +(9.284767082561267, 31.07279344471112, '2077-12-04T06:58:55.635Z'), +(7.7785270892408995, 22.895981188404516, '2077-12-04T07:01:57.635Z'), +(0.04854931168741314, 8.286645074062188, '2077-12-04T07:08:03.635Z'), +(0.5362437636807776, 49.47667774326424, '2077-12-04T07:23:19.635Z'), +(19.24726863915068, 12.523340263649146, '2077-12-04T07:38:25.635Z'), +(11.206036501575516, 13.819224776319249, '2077-12-04T07:41:25.635Z'), +(4.27682169145437, 2.2979695939449414, '2077-12-04T07:46:21.635Z'), +(22.063253019927927, 3.1020581953880915, '2077-12-04T07:52:56.635Z'), +(13.012494774164894, 19.77621450239074, '2077-12-04T07:59:42.635Z'), +(1.0530002984517655, 21.160878944936822, '2077-12-04T08:04:09.635Z'), +(21.66445492770768, 7.208393808989207, '2077-12-04T08:13:18.635Z'), +(13.58705235794586, 44.761512447503236, '2077-12-04T08:26:51.635Z'), +(6.662503651513542, 39.350174998599456, '2077-12-04T08:30:05.635Z'), +(9.414624145753084, 31.553901496217968, '2077-12-04T08:33:07.635Z'), +(0.13217713465624273, 10.065622735090477, '2077-12-04T08:41:45.635Z'), +(0.8072681657344194, 7.9633636740109095, '2077-12-04T08:42:34.635Z'), +(2.600627752694855, 13.11395453838727, '2077-12-04T08:44:35.635Z'), +(9.27253104166336, 25.02363780719411, '2077-12-04T08:49:37.635Z'), +(14.892564190322389, 21.961577838841144, '2077-12-04T08:51:58.635Z'), +(0.39621573552609335, 28.317606128396317, '2077-12-04T08:57:49.635Z'), +(17.539143536601227, 40.43467791537376, '2077-12-04T09:05:33.635Z'), +(22.46321243242495, 23.778958741392124, '2077-12-04T09:11:37.635Z'), +(15.037541096446796, 38.32537722837123, '2077-12-04T09:17:24.635Z'), +(0.3504489334530224, 13.536509007062172, '2077-12-04T09:27:59.635Z'), +(9.646124214814312, 48.918765187006, '2077-12-04T09:41:28.635Z'), +(11.83299229633586, 38.424373444299704, '2077-12-04T09:45:22.635Z'), +(18.210752470423046, 10.154862056839672, '2077-12-04T09:55:44.635Z'), +(5.68827101376775, 20.305793435507912, '2077-12-04T10:01:39.635Z'), +(19.626409911524853, 23.500635661989715, '2077-12-04T10:06:56.635Z'), +(2.0228021505649223, 45.09642919798954, '2077-12-04T10:17:07.635Z'), +(1.5102412327334067, 13.727485699041898, '2077-12-04T10:28:44.635Z'), +(13.705513366369926, 22.173454631887985, '2077-12-04T10:34:12.635Z'), +(21.422346304538014, 49.16000852169123, '2077-12-04T10:44:08.635Z'), +(7.66203481177781, 17.755937567029, '2077-12-04T10:56:27.635Z'), +(20.175761483202983, 9.968540111324229, '2077-12-04T11:01:51.635Z'), +(4.653374610530427, 8.867972361185206, '2077-12-04T11:07:37.635Z'), +(4.568980776052835, 10.355042963268724, '2077-12-04T11:08:10.635Z'), +(19.04624408865549, 31.98139617686114, '2077-12-04T11:17:39.635Z'), +(9.249163190572947, 34.10134432987053, '2077-12-04T11:21:21.635Z'), +(1.4750020189661732, 28.813295588788975, '2077-12-04T11:24:49.635Z'), +(17.46135477291407, 34.55874071481518, '2077-12-04T11:31:06.635Z'), +(14.541922036073512, 20.998380022578093, '2077-12-04T11:36:02.635Z'), +(1.1494468652440546, 23.94445940525796, '2077-12-04T11:41:06.635Z'), +(10.42928249510035, 25.61461702104636, '2077-12-04T11:44:35.635Z'), +(8.437549754328714, 30.7578467192038, '2077-12-04T11:46:36.635Z'), +(20.809682121660817, 22.16683208592897, '2077-12-04T11:52:07.635Z'), +(8.298883350392176, 19.701415964143383, '2077-12-04T11:56:50.635Z'), +(13.73763475054482, 48.35825531299097, '2077-12-04T12:07:26.635Z'), +(9.052344097190078, 14.110535989937528, '2077-12-04T12:19:59.635Z'), +(23.094577322384318, 2.862431123766132, '2077-12-04T12:26:32.635Z'), +(15.427213849871096, 9.347003934162421, '2077-12-04T12:30:10.635Z'), +(0.12316857504175575, 9.661909774520565, '2077-12-04T12:35:50.635Z'), +(6.254646447949823, 30.46210346553542, '2077-12-04T12:43:51.635Z'), +(19.009067865577947, 44.40948431596488, '2077-12-04T12:50:45.635Z'), +(23.37316494291346, 43.666411322774124, '2077-12-04T12:52:23.635Z'), +(13.138662097500937, 49.411637994397886, '2077-12-04T12:56:40.635Z'), +(19.203453417005704, 45.78134224103797, '2077-12-04T12:59:15.635Z'), +(8.491226409002092, 41.68531250939107, '2077-12-04T13:03:29.635Z'), +(18.131274881127307, 31.49127305945242, '2077-12-04T13:08:36.635Z'), +(10.233488651236964, 3.937360389086641, '2077-12-04T13:18:54.635Z'), +(6.337268419592738, 45.15477196269262, '2077-12-04T13:34:04.635Z'), +(3.555907781631736, 41.555808981985855, '2077-12-04T13:35:44.635Z'), +(18.384599278038134, 28.517706554544837, '2077-12-04T13:42:59.635Z'), +(10.453287727597234, 13.01958991571157, '2077-12-04T13:49:16.635Z'), +(7.546661871024763, 31.3847544687063, '2077-12-04T13:56:04.635Z'), +(8.210347385721683, 9.138471637353197, '2077-12-04T14:04:14.635Z'), +(3.4802499155948596, 49.77442394657144, '2077-12-04T14:19:18.635Z'), +(0.5448848333419899, 22.017056428810093, '2077-12-04T14:29:38.635Z'), +(19.80141526850124, 31.359913908973724, '2077-12-04T14:37:32.635Z'), +(19.963236207873802, 1.0432266509447, '2077-12-04T14:48:05.635Z'), +(19.035035866378028, 15.219326229762695, '2077-12-04T14:53:02.635Z'), +(18.295191444713904, 35.395854082384815, '2077-12-04T15:00:07.635Z'), +(11.521167901864176, 41.8284705289464, '2077-12-04T15:03:31.635Z'), +(19.352369006759588, 11.749086749056115, '2077-12-04T15:14:37.635Z'), +(18.39745406209525, 44.20777526031458, '2077-12-04T15:25:59.635Z'), +(12.455041766218045, 46.90658756867553, '2077-12-04T15:28:23.635Z'), +(0.8363766130588343, 36.122286992925424, '2077-12-04T15:34:14.635Z'), +(6.716275824760256, 13.797811564711903, '2077-12-04T15:42:46.635Z'), +(23.42833373902074, 7.429373394239393, '2077-12-04T15:49:21.635Z'), +(12.209824737327295, 12.952230195210124, '2077-12-04T15:53:56.635Z'), +(8.76344773298978, 24.98573572442818, '2077-12-04T15:58:30.635Z'), +(7.608607895275272, 28.384161718004705, '2077-12-04T15:59:49.635Z'), +(8.93097909123284, 33.74981162362622, '2077-12-04T16:01:50.635Z'), +(13.556919173396993, 4.041029494876663, '2077-12-04T16:12:45.635Z'), +(20.533962471270375, 7.249808437318737, '2077-12-04T16:15:34.635Z'), +(7.924996862472897, 46.57416890985139, '2077-12-04T16:30:23.635Z'), +(7.377873885792006, 16.33185927299068, '2077-12-04T16:41:29.635Z'), +(4.303789895008514, 37.05391421978639, '2077-12-04T16:49:12.635Z'), +(2.6707137371882634, 32.65147143742075, '2077-12-04T16:50:56.635Z'), +(20.845126853233115, 1.6581909156877712, '2077-12-04T17:03:59.635Z'), +(10.418471153177379, 49.09036769460402, '2077-12-04T17:21:17.635Z'), +(20.163905116061883, 35.86802041665842, '2077-12-04T17:27:13.635Z'), +(13.279670083916935, 18.520311550914343, '2077-12-04T17:33:52.635Z'), +(0.11106440066559853, 4.769418975281381, '2077-12-04T17:40:53.635Z'), +(19.568562457914318, 40.947860409679876, '2077-12-04T17:55:52.635Z'), +(17.635785235392422, 8.99182740065558, '2077-12-04T18:07:05.635Z'), +(11.98688793254993, 15.858627112932888, '2077-12-04T18:10:18.635Z'), +(10.399083660247358, 33.53273873156751, '2077-12-04T18:16:45.635Z'), +(9.208202177159766, 46.86185370268389, '2077-12-04T18:21:38.635Z'), +(8.765400339199571, 37.7504875922776, '2077-12-04T18:24:58.635Z'), +(5.095845251367695, 29.214383672148443, '2077-12-04T18:28:23.635Z'), +(23.04872874488219, 32.56978447534014, '2077-12-04T18:35:08.635Z'), +(11.37645931968942, 43.27756630956615, '2077-12-04T18:40:52.635Z'), +(19.358789334637493, 42.02511561836907, '2077-12-04T18:43:51.635Z'), +(22.1116929381196, 30.345167112972746, '2077-12-04T18:48:01.635Z'), +(2.4917765426651717, 30.483708222846808, '2077-12-04T18:55:17.635Z'), +(7.906238858014489, 49.99167935419526, '2077-12-04T19:02:45.635Z'), +(7.804619598302015, 23.390319886694655, '2077-12-04T19:12:30.635Z'), +(4.610120392713287, 29.741491429779842, '2077-12-04T19:15:07.635Z'), +(23.34236762386966, 35.688454382809105, '2077-12-04T19:22:22.635Z'), +(0.23561407657113814, 47.09800162527474, '2077-12-04T19:31:51.635Z'), +(16.689849058340066, 29.246913245054355, '2077-12-04T19:40:46.635Z'), +(9.915351300778731, 16.903422483666205, '2077-12-04T19:45:52.635Z'), +(1.5620770713649057, 29.60046202376697, '2077-12-04T19:51:28.635Z'), +(8.623522642679136, 43.98703444900663, '2077-12-04T19:57:23.635Z'), +(3.099299061797638, 35.44557858266676, '2077-12-04T20:01:08.635Z'), +(13.197519708016685, 23.806353306814543, '2077-12-04T20:06:48.635Z'), +(14.179096462282969, 25.196118656977905, '2077-12-04T20:07:25.635Z'), +(8.351797325675117, 35.98320857901205, '2077-12-04T20:11:53.635Z'), +(14.332056975478372, 44.85702102830202, '2077-12-04T20:15:47.635Z'), +(5.3932038941589315, 29.682888439628616, '2077-12-04T20:22:14.635Z'), +(8.823501574158906, 32.195422100307646, '2077-12-04T20:23:48.635Z'), +(7.576607691877935, 49.873020810649784, '2077-12-04T20:30:18.635Z'), +(18.020465893907996, 33.40661010268914, '2077-12-04T20:37:23.635Z'), +(15.259532295704627, 17.371696149449903, '2077-12-04T20:43:10.635Z'), +(7.314509103706773, 24.75899431178704, '2077-12-04T20:47:09.635Z'), +(6.59045043143408, 41.2204544891261, '2077-12-04T20:53:12.635Z'), +(0.7247785885807391, 48.66235643331698, '2077-12-04T20:56:42.635Z'), +(5.134378665431962, 34.05547877384264, '2077-12-04T21:02:20.635Z'), +(14.295729622282938, 32.290454796637064, '2077-12-04T21:05:47.635Z'), +(22.9440657328352, 6.067152197261866, '2077-12-04T21:15:31.635Z'), +(0.5163420142564197, 6.351367771278694, '2077-12-04T21:23:49.635Z'), +(9.299119855056421, 43.90382777277276, '2077-12-04T21:38:02.635Z'), +(14.906037973293142, 3.9564109155509817, '2077-12-04T21:52:38.635Z'), +(8.20551480161665, 35.111639428774396, '2077-12-04T22:04:12.635Z'), +(21.654221783303612, 28.929334472327014, '2077-12-04T22:09:39.635Z'), +(3.082407499099342, 1.6749962819745106, '2077-12-04T22:21:38.635Z'), +(11.704798659210287, 17.634334823075605, '2077-12-04T22:28:18.635Z'), +(19.251719612332785, 16.654670366996893, '2077-12-04T22:31:07.635Z'), +(23.10431076626168, 32.43729599484784, '2077-12-04T22:36:45.635Z'), +(12.305033823320384, 34.030959426175144, '2077-12-04T22:40:47.635Z'), +(15.691977779747988, 0.20493551051982226, '2077-12-04T22:53:00.635Z'), +(17.203912239168194, 39.92495066720356, '2077-12-04T23:07:06.635Z'), +(17.965104119497372, 44.15266090150493, '2077-12-04T23:08:37.635Z'), +(3.427091259788249, 21.247027110410247, '2077-12-04T23:18:31.635Z'), +(9.19804195575813, 12.623150199875699, '2077-12-04T23:22:20.635Z'), +(15.505761764028728, 46.60698477306076, '2077-12-04T23:34:50.635Z'), +(16.458382438769785, 24.03293823629757, '2077-12-04T23:42:52.635Z'), +(9.09224729780928, 40.28369251161993, '2077-12-04T23:49:20.635Z'), +(15.59855830221154, 44.798125688624516, '2077-12-04T23:52:14.635Z'), +(8.044505589018046, 5.236334850193783, '2077-12-05T00:06:49.635Z'), +(3.128420524455236, 27.973939451524583, '2077-12-05T00:15:23.635Z'), +(19.135353243805294, 6.997937342383741, '2077-12-05T00:25:01.635Z'), +(10.223926820199836, 15.344502134083475, '2077-12-05T00:29:28.635Z'), +(16.67881203105667, 27.96909514639738, '2077-12-05T00:34:36.635Z'), +(22.744648841353204, 31.073538883235436, '2077-12-05T00:37:05.635Z'), +(6.3305416950450955, 32.769951837700056, '2077-12-05T00:43:11.635Z'), +(18.09115686273739, 38.649692347608784, '2077-12-05T00:48:01.635Z'), +(14.308392346102012, 6.783114341167204, '2077-12-05T00:59:25.635Z'), +(1.0971224244166011, 43.047193744126304, '2077-12-05T01:13:34.635Z'), +(16.184888100156254, 22.725614603336293, '2077-12-05T01:22:51.635Z'), +(14.669278690880855, 34.35387726642996, '2077-12-05T01:27:02.635Z'), +(9.85178790598212, 30.240573434579943, '2077-12-05T01:29:21.635Z'), +(1.870524766587186, 10.342504279692212, '2077-12-05T01:37:15.635Z'), +(12.04935215031307, 49.39042226716128, '2077-12-05T01:52:04.635Z'), +(21.394158135459932, 40.50343721653851, '2077-12-05T01:56:44.635Z'), +(4.121490775748595, 30.60328031820517, '2077-12-05T02:04:03.635Z'), +(21.35953071457059, 22.552149693534002, '2077-12-05T02:11:03.635Z'), +(7.655938886091524, 44.02652648467476, '2077-12-05T02:20:15.635Z'), +(15.60719217641488, 35.09469721903148, '2077-12-05T02:24:37.635Z'), +(10.100765215918408, 23.74599146435221, '2077-12-05T02:29:11.635Z'), +(21.59160100575469, 48.33619154325733, '2077-12-05T02:38:54.635Z'), +(11.717690100137862, 7.258916428955449, '2077-12-05T02:53:53.635Z'), +(9.406620677136639, 33.22148732533844, '2077-12-05T03:03:22.635Z'), +(18.883771687171798, 34.73563405296325, '2077-12-05T03:06:55.635Z'), +(10.606011923541564, 3.9563594580222086, '2077-12-05T03:18:20.635Z'), +(15.279933592820496, 10.42480076398275, '2077-12-05T03:21:14.635Z'), +(22.222641084272848, 49.66437923994771, '2077-12-05T03:35:12.635Z'), +(19.334549723847243, 1.0131611179652396, '2077-12-05T03:52:01.635Z'), +(7.945821927707137, 14.481957356406408, '2077-12-05T03:58:26.635Z'), +(8.504224116757248, 31.473900152346694, '2077-12-05T04:04:40.635Z'), +(18.606268586463884, 30.742014239203687, '2077-12-05T04:08:25.635Z'), +(3.4830785086190144, 12.090305040483965, '2077-12-05T04:17:11.635Z'), +(0.5303624181267094, 15.499860385101297, '2077-12-05T04:18:51.635Z'), +(9.718267829232051, 24.24136608613326, '2077-12-05T04:23:32.635Z'), +(15.502956516698658, 34.00165627257833, '2077-12-05T04:27:39.635Z'), +(8.988992241994127, 5.187775755600498, '2077-12-05T04:38:21.635Z'), +(1.253511410914567, 31.952791599189407, '2077-12-05T04:48:37.635Z'), +(0.28768380865432075, 48.87070633265135, '2077-12-05T04:54:53.635Z'), +(7.714351180030526, 7.40541799752626, '2077-12-05T05:10:26.635Z'), +(2.4333694485630586, 36.673149640783535, '2077-12-05T05:21:24.635Z'), +(9.44734084161204, 14.216680197351572, '2077-12-05T05:30:04.635Z'), +(19.309888006345897, 4.8329768726158004, '2077-12-05T05:35:02.635Z'), +(7.8755405511880205, 17.60075265311032, '2077-12-05T05:41:16.635Z'), +(1.4404065014101994, 20.8475022561569, '2077-12-05T05:43:56.635Z'), +(9.61934130319859, 4.841003791882434, '2077-12-05T05:50:33.635Z'), +(11.788164340520048, 22.817975314443256, '2077-12-05T05:57:08.635Z'), +(20.064981222452236, 47.758457867040896, '2077-12-05T06:06:31.635Z'), +(4.7144617374580555, 24.478623736733848, '2077-12-05T06:16:39.635Z'), +(3.4405088958866257, 20.915091262085028, '2077-12-05T06:18:02.635Z'), +(6.051658694776411, 30.323191139201704, '2077-12-05T06:21:38.635Z'), +(11.687462209381533, 16.477790149044306, '2077-12-05T06:27:06.635Z'), +(1.3638058928647978, 46.39391158541123, '2077-12-05T06:38:44.635Z'), +(0.9336689414994012, 42.09509543508206, '2077-12-05T06:40:20.635Z'), +(16.830977138523988, 27.114574090512455, '2077-12-05T06:48:22.635Z'), +(17.130713726584762, 4.577194266607962, '2077-12-05T06:56:21.635Z'), +(18.91801199429461, 8.509945561990216, '2077-12-05T06:57:53.635Z'), +(18.75682473463575, 3.7556148093770494, '2077-12-05T06:59:33.635Z'), +(12.996022251058188, 2.470493323430029, '2077-12-05T07:01:44.635Z'), +(22.527438636141415, 19.003818542534443, '2077-12-05T07:08:32.635Z'), +(16.052294714872655, 17.27798020871044, '2077-12-05T07:11:00.635Z'), +(4.850991118893723, 19.51467372249152, '2077-12-05T07:15:13.635Z'), +(0.8383610230326375, 47.0034434093243, '2077-12-05T07:25:29.635Z'), +(23.354008484152708, 35.420454583558595, '2077-12-05T07:34:48.635Z'), +(12.159777209383718, 13.379438526440635, '2077-12-05T07:43:35.635Z'), +(13.518393928903311, 2.3094583540505287, '2077-12-05T07:47:36.635Z'), +(4.12260205171824, 36.94981407986036, '2077-12-05T08:00:44.635Z'), +(10.020362903322566, 50.14841315102435, '2077-12-05T08:06:03.635Z'), +(2.5985671710356595, 24.67511360158715, '2077-12-05T08:15:49.635Z'), +(0.31394312808638697, 25.16464115592879, '2077-12-05T08:16:40.635Z'), +(0.889995263716384, 9.014553765859626, '2077-12-05T08:22:39.635Z'), +(14.203402731517892, 23.511317306623372, '2077-12-05T08:29:54.635Z'), +(0.511229851072578, 9.170567678888219, '2077-12-05T08:37:12.635Z'), +(0.5359123474226352, 12.286558978311641, '2077-12-05T08:38:21.635Z'), +(1.7695152395284468, 39.51231894312031, '2077-12-05T08:48:26.635Z'), +(9.166107249412354, 15.460856527086891, '2077-12-05T08:57:42.635Z'), +(0.6907488100565229, 24.83374750854821, '2077-12-05T09:02:22.635Z'), +(7.323158135657017, 4.049688764254978, '2077-12-05T09:10:25.635Z'), +(18.614976154874846, 47.824053650768874, '2077-12-05T09:26:43.635Z'), +(3.5531682846182053, 31.028875753296884, '2077-12-05T09:34:58.635Z'), +(10.518771332270626, 47.66205039685171, '2077-12-05T09:41:36.635Z'), +(17.819427925042273, 2.205553258240182, '2077-12-05T09:58:07.635Z'), +(22.283055794200674, 12.937502817589207, '2077-12-05T10:02:12.635Z'), +(1.4816493123191612, 14.567471566488862, '2077-12-05T10:09:55.635Z'), +(14.425891663742133, 6.050628655535498, '2077-12-05T10:15:38.635Z'), +(6.900655190104706, 44.736118556404215, '2077-12-05T10:29:58.635Z'), +(14.469341984984325, 45.091496866893564, '2077-12-05T10:32:46.635Z'), +(13.513654727153709, 18.015025937016247, '2077-12-05T10:42:30.635Z'), +(17.0065943391469, 46.65201645777435, '2077-12-05T10:52:48.635Z'), +(3.339265616810039, 40.829940329034294, '2077-12-05T10:58:17.635Z'), +(12.539351588822502, 5.091276906715461, '2077-12-05T11:11:49.635Z'), +(16.063234154550678, 10.3574035038054, '2077-12-05T11:14:06.635Z'), +(1.4778012892473493, 40.251509640038094, '2077-12-05T11:26:16.635Z'), +(3.0241398700141873, 13.741713886572802, '2077-12-05T11:36:06.635Z'), +(17.976026515600836, 41.60758718528788, '2077-12-05T11:47:38.635Z'), +(11.244985275244264, 13.680463285401704, '2077-12-05T11:57:56.635Z'), +(5.913975365132134, 36.12581187982495, '2077-12-05T12:06:23.635Z'), +(3.2914226925595425, 30.424850188633876, '2077-12-05T12:08:42.635Z'), +(12.642372211279811, 42.77217915279338, '2077-12-05T12:14:24.635Z'), +(12.896718284914892, 33.99241158950626, '2077-12-05T12:17:34.635Z'), +(22.748221471583143, 35.51026118223943, '2077-12-05T12:21:15.635Z'), +(3.868271084627885, 32.60770739348503, '2077-12-05T12:28:19.635Z'), +(5.007234512578487, 17.658264459652315, '2077-12-05T12:33:51.635Z'), +(8.730089186785412, 39.585440528449844, '2077-12-05T12:42:02.635Z'), +(17.358670392379747, 20.188321937285526, '2077-12-05T12:49:43.635Z'), +(18.070030698912284, 24.44696325750589, '2077-12-05T12:51:14.635Z'), +(21.81776017100178, 38.04834254973071, '2077-12-05T12:56:10.635Z'), +(21.449866706785517, 4.022198739045036, '2077-12-05T13:07:52.635Z'), +(6.779703869724434, 10.637313381835448, '2077-12-05T13:13:47.635Z'), +(10.80637532691284, 38.40435274101127, '2077-12-05T13:24:03.635Z'), +(14.10821027325748, 33.12761394482103, '2077-12-05T13:26:19.635Z'), +(21.93819320628197, 47.909667037685395, '2077-12-05T13:32:16.635Z'), +(8.336858611588244, 23.99529205222451, '2077-12-05T13:42:10.635Z'), +(22.809617052969585, 4.472328932254928, '2077-12-05T13:50:56.635Z'), +(10.839989815203165, 45.25998629149454, '2077-12-05T14:06:00.635Z'), +(12.680836477415689, 7.821497747594755, '2077-12-05T14:19:35.635Z'), +(6.376025768945469, 48.47043530928587, '2077-12-05T14:34:36.635Z'), +(19.27876731908816, 1.0762013627433002, '2077-12-05T14:52:19.635Z'), +(10.452056150088405, 18.435323602630703, '2077-12-05T14:59:20.635Z'), +(14.801779443405325, 27.467712000269007, '2077-12-05T15:02:58.635Z'), +(22.313272158636057, 13.271119209876462, '2077-12-05T15:08:40.635Z'), +(15.591596041284177, 41.01567235540273, '2077-12-05T15:18:41.635Z'), +(17.101721497335006, 4.720763885296387, '2077-12-05T15:31:35.635Z'), +(10.652139230418161, 45.726713676555775, '2077-12-05T15:46:30.635Z'), +(6.122321752911894, 14.749252349711838, '2077-12-05T15:57:58.635Z'), +(3.025100894623556, 48.8371081099089, '2077-12-05T16:10:36.635Z'), +(8.063742734227416, 43.22527030299192, '2077-12-05T16:13:23.635Z'), +(0.005113137710207693, 12.662206459420945, '2077-12-05T16:25:03.635Z'), +(18.565955277138407, 13.378390456578824, '2077-12-05T16:31:56.635Z'), +(17.837492770057377, 39.660083866791574, '2077-12-05T16:41:10.635Z'), +(5.5399655789937565, 29.413666326395965, '2077-12-05T16:47:02.635Z'), +(2.0495173716317745, 0.7034217120173415, '2077-12-05T16:57:43.635Z'), +(19.09181331186705, 18.381875182568283, '2077-12-05T17:06:43.635Z'), +(15.111746419744408, 31.103288825951623, '2077-12-05T17:11:27.635Z'), +(11.721419588812903, 12.403775145049773, '2077-12-05T17:18:18.635Z'), +(8.124825035257803, 17.052010299750282, '2077-12-05T17:20:27.635Z'), +(8.255918583107876, 1.7831299846828137, '2077-12-05T17:26:03.635Z'), +(10.353875474748527, 40.85672088562662, '2077-12-05T17:40:21.635Z'), +(15.04884538736036, 34.30877678323643, '2077-12-05T17:43:17.635Z'), +(2.245977843769921, 2.2763861219269805, '2077-12-05T17:55:54.635Z'), +(18.27722097896158, 20.754213224499527, '2077-12-05T18:04:51.635Z'), +(15.115537518049297, 7.282045632124726, '2077-12-05T18:09:46.635Z'), +(1.7198805400056225, 20.78382648607143, '2077-12-05T18:16:46.635Z'), +(4.731934345349916, 32.05628037145759, '2077-12-05T18:21:05.635Z'), +(21.816845018709152, 6.598523386574384, '2077-12-05T18:32:12.635Z'), +(12.507207229104228, 0.3481456914537804, '2077-12-05T18:36:17.635Z'), +(6.298786812282451, 15.410010981874331, '2077-12-05T18:42:14.635Z'), +(1.1784873662830337, 17.465698293159637, '2077-12-05T18:44:16.635Z'), +(3.7813881573304644, 45.898528685883164, '2077-12-05T18:54:50.635Z'), +(6.787421350134524, 2.306366663029302, '2077-12-05T19:10:57.635Z'), +(0.4961994201227052, 43.1198350954227, '2077-12-05T19:26:13.635Z'), +(18.850700929854554, 40.67901422050898, '2077-12-05T19:33:04.635Z'), +(7.254396142082423, 25.19461608828062, '2077-12-05T19:40:06.635Z'), +(9.188404371072146, 28.94916565080161, '2077-12-05T19:41:39.635Z'), +(0.035295140082758504, 23.88039752745215, '2077-12-05T19:45:31.635Z'), +(5.700774878261686, 17.816343573837297, '2077-12-05T19:48:35.635Z'), +(22.20621993739802, 28.05183500853208, '2077-12-05T19:55:42.635Z'), +(19.68105375592532, 43.89283944063818, '2077-12-05T20:01:15.635Z'), +(9.237607038964786, 1.9133736425392076, '2077-12-05T20:16:45.635Z'), +(22.656622082893016, 25.452901910934937, '2077-12-05T20:26:28.635Z'), +(17.617821758284983, 12.951717837312748, '2077-12-05T20:31:11.635Z'), +(5.8320304164161225, 18.0885439817048, '2077-12-05T20:35:55.635Z'), +(16.60513826574138, 25.489387569636474, '2077-12-05T20:40:43.635Z'), +(18.75796449990095, 0.9132093616943899, '2077-12-05T20:49:25.635Z'), +(15.579977837678966, 1.5779836946024925, '2077-12-05T20:50:37.635Z'), +(14.484935257008704, 10.872703710464132, '2077-12-05T20:53:58.635Z'), +(14.884580314878876, 46.25733958697286, '2077-12-05T21:06:38.635Z'), +(22.66750003989429, 33.70999715451224, '2077-12-05T21:11:53.635Z'), +(17.04354796285202, 23.841304070510837, '2077-12-05T21:15:54.635Z'), +(17.93942904298474, 6.293745858787818, '2077-12-05T21:22:06.635Z'), +(4.191535898187791, 12.565569958122381, '2077-12-05T21:27:40.635Z'), +(17.3089292357983, 24.46480499071986, '2077-12-05T21:34:10.635Z'), +(3.2314682970100717, 24.37147837180886, '2077-12-05T21:39:23.635Z'), +(20.9723674172248, 18.699719169107826, '2077-12-05T21:46:16.635Z'), +(10.33347871763104, 19.469554017516092, '2077-12-05T21:50:13.635Z'), +(16.580419579154302, 7.378637890855785, '2077-12-05T21:55:08.635Z'), +(3.012253172027685, 15.55573461783274, '2077-12-05T22:00:58.635Z'), +(1.0374928004221358, 0.7047226044558489, '2077-12-05T22:06:30.635Z'), +(3.4871501961079723, 47.17596528933544, '2077-12-05T22:23:43.635Z'), +(3.5669465725015637, 44.46957503648756, '2077-12-05T22:24:43.635Z'), +(16.97388303530501, 19.38912821678198, '2077-12-05T22:35:06.635Z'), +(3.2810229618280062, 32.99826821501987, '2077-12-05T22:42:11.635Z'), +(9.304589904377252, 32.280042053692, '2077-12-05T22:44:25.635Z'), +(14.064840787874964, 13.431413259112912, '2077-12-05T22:51:28.635Z'), +(0.4347213951108442, 41.722975822645, '2077-12-05T23:03:00.635Z'), +(19.985318519614047, 22.65077898957681, '2077-12-05T23:13:01.635Z'), +(12.209692194205036, 34.46711058307613, '2077-12-05T23:18:06.635Z'), +(2.3963041009937815, 38.660846958659114, '2077-12-05T23:22:02.635Z'), +(9.960500221499345, 43.59880229996125, '2077-12-05T23:25:22.635Z'), +(15.783160262093878, 25.32357124632539, '2077-12-05T23:32:18.635Z'), +(18.91051738703385, 16.312609187653255, '2077-12-05T23:35:41.635Z'), +(16.78749974922382, 26.532882425752923, '2077-12-05T23:39:22.635Z'), +(2.862063424865915, 33.17237084253067, '2077-12-05T23:45:03.635Z'), +(3.43135059338284, 30.92205672620112, '2077-12-05T23:45:54.635Z'), +(17.837914554461282, 1.3682771320349612, '2077-12-05T23:57:53.635Z'), +(11.210926658484832, 43.65054995862445, '2077-12-06T00:13:13.635Z'), +(15.649081757064327, 1.767902293597023, '2077-12-06T00:28:22.635Z'), +(1.3006033165996636, 2.836724849857584, '2077-12-06T00:33:41.635Z'), +(17.3033178625191, 28.49262607263777, '2077-12-06T00:44:45.635Z'), +(6.246962148666278, 29.586680406920912, '2077-12-06T00:48:52.635Z'), +(0.18503943935321837, 47.732905861528046, '2077-12-06T00:55:56.635Z'), +(16.166179861011223, 16.037499105834208, '2077-12-06T01:08:56.635Z'), +(16.941749579858378, 39.9193258981034, '2077-12-06T01:17:25.635Z'), +(21.997079773419113, 27.938599329284035, '2077-12-06T01:22:00.635Z'), +(6.874070345798096, 47.12886824452877, '2077-12-06T01:30:51.635Z'), +(6.619056931242638, 41.69982340628072, '2077-12-06T01:32:51.635Z'), +(14.329870682400903, 16.350193360784914, '2077-12-06T01:42:30.635Z'), +(4.406335661424535, 10.10696873166667, '2077-12-06T01:46:49.635Z'), +(20.025960595652414, 24.27425279633773, '2077-12-06T01:54:32.635Z'), +(0.14303808280615116, 48.3955671582588, '2077-12-06T02:05:58.635Z'), +(20.275031404212093, 41.69356141477984, '2077-12-06T02:13:48.635Z'), +(13.534743415898808, 13.66357100427448, '2077-12-06T02:24:02.635Z'), +(2.2607950889601085, 45.89731713741272, '2077-12-06T02:36:33.635Z'), +(0.7023364009538977, 24.317340034636704, '2077-12-06T02:44:33.635Z'), +(5.855876606345953, 16.657912136635638, '2077-12-06T02:47:58.635Z'), +(7.274364634008104, 15.299366371380717, '2077-12-06T02:48:41.635Z'), +(14.497586147305665, 15.999683561910313, '2077-12-06T02:51:22.635Z'), +(5.424653403221804, 14.078474821153215, '2077-12-06T02:54:48.635Z'), +(8.029286081393854, 2.4498951421658783, '2077-12-06T02:59:11.635Z'), +(8.574384353984536, 27.827486084865015, '2077-12-06T03:08:29.635Z'), +(2.751191202855293, 46.995048000244516, '2077-12-06T03:15:52.635Z'), +(19.457658518218608, 36.75992407814582, '2077-12-06T03:23:05.635Z'), +(4.6442987226617625, 25.197904832116766, '2077-12-06T03:29:58.635Z'), +(15.289862804591014, 39.435656431764734, '2077-12-06T03:36:29.635Z'), +(4.225085548068091, 4.849476533567925, '2077-12-06T03:49:44.635Z'), +(8.755018686036024, 19.323896948556595, '2077-12-06T03:55:19.635Z'), +(4.202181099229687, 42.931528356824835, '2077-12-06T04:04:10.635Z'), +(14.263446277817833, 4.434491753247447, '2077-12-06T04:18:42.635Z'), +(16.338240974238424, 33.73614551812061, '2077-12-06T04:29:11.635Z'), +(8.691412565863228, 40.4628725858565, '2077-12-06T04:32:55.635Z'), +(11.533648827856423, 35.43560329347053, '2077-12-06T04:35:01.635Z'), +(21.44023151030831, 17.70752204643064, '2077-12-06T04:42:17.635Z'), +(14.512175445082145, 49.74003984982142, '2077-12-06T04:53:50.635Z'), +(17.12069369142654, 7.820793841225821, '2077-12-06T05:08:47.635Z'), +(15.557306511058458, 16.04328300466177, '2077-12-06T05:11:45.635Z'), +(18.85225162634056, 33.143098091299265, '2077-12-06T05:17:55.635Z'), +(16.843043905217208, 8.19235647726164, '2077-12-06T05:26:44.635Z'), +(8.760207072491095, 38.806078602051954, '2077-12-06T05:38:10.635Z'), +(2.6045858327609315, 33.98733766032195, '2077-12-06T05:41:03.635Z'), +(4.907807725980393, 18.121151144981848, '2077-12-06T05:46:58.635Z'), +(3.725623310745351, 17.00991701670142, '2077-12-06T05:47:34.635Z'), +(11.39466132592453, 46.78428858257122, '2077-12-06T05:58:51.635Z'), +(12.536702342246684, 14.33414126290901, '2077-12-06T06:10:37.635Z'), +(3.579335106340542, 34.1516047403852, '2077-12-06T06:18:36.635Z'), +(5.88734507430553, 0.7653643975729735, '2077-12-06T06:30:57.635Z'), +(20.611253058317228, 14.175027273733292, '2077-12-06T06:38:13.635Z'), +(17.44287414838252, 30.024063905659933, '2077-12-06T06:43:53.635Z'), +(20.439615931824036, 5.269374418938414, '2077-12-06T06:52:37.635Z'), +(21.308939267981007, 22.644352302321867, '2077-12-06T06:58:38.635Z'), +(0.9837654675872363, 27.290289485063447, '2077-12-06T07:06:21.635Z'), +(14.922367077196487, 34.757248204138634, '2077-12-06T07:12:11.635Z'), +(7.10330085466159, 44.58989472045364, '2077-12-06T07:16:47.635Z'), +(1.189052391482959, 10.163309404966203, '2077-12-06T07:29:41.635Z'), +(5.042628420545538, 50.28594510912937, '2077-12-06T07:44:35.635Z'), +(14.621474230244141, 45.2527671431411, '2077-12-06T07:48:34.635Z'), +(8.162681854439823, 40.474041822593605, '2077-12-06T07:51:31.635Z'), +(21.40294312826285, 48.341001230115296, '2077-12-06T07:57:10.635Z'), +(6.9212323373014755, 47.36488822779318, '2077-12-06T08:02:32.635Z'), +(22.71009581845402, 48.3791061914526, '2077-12-06T08:08:23.635Z'), +(20.994544351330838, 5.4475660422531265, '2077-12-06T08:23:06.635Z'), +(6.8468652357745, 13.63648293475449, '2077-12-06T08:29:06.635Z'), +(20.61583396174439, 4.337835901318169, '2077-12-06T08:35:11.635Z'), +(6.869030552447363, 8.901321503984738, '2077-12-06T08:40:32.635Z'), +(7.120356723297786, 20.686314318307517, '2077-12-06T08:44:52.635Z'), +(7.425576165437371, 18.831102701385554, '2077-12-06T08:45:33.635Z'), +(20.771425974839744, 9.641671029629695, '2077-12-06T08:51:29.635Z'), +(16.8723585897582, 31.57278120687561, '2077-12-06T08:59:18.635Z'), +(1.5304324732570713, 3.6124051477867054, '2077-12-06T09:10:58.635Z'), +(22.006829220303423, 28.808502289775923, '2077-12-06T09:22:48.635Z'), +(10.763025020032465, 17.12688171003412, '2077-12-06T09:28:40.635Z'), +(11.727369458533605, 38.45171977191905, '2077-12-06T09:36:25.635Z'), +(12.935898763593025, 49.398706051641746, '2077-12-06T09:40:24.635Z'), +(8.582321776717189, 4.3202649913988695, '2077-12-06T09:56:52.635Z'), +(21.634864089902916, 40.55705803881741, '2077-12-06T10:10:39.635Z'), +(21.776037321556377, 6.9560901440857315, '2077-12-06T10:22:11.635Z'), +(2.769635137671464, 25.34143488675726, '2077-12-06T10:31:51.635Z'), +(1.9645968496436492, 23.790580704062485, '2077-12-06T10:32:29.635Z'), +(11.428274437655414, 15.392063473231422, '2077-12-06T10:37:09.635Z'), +(15.179768254801852, 11.677642376661787, '2077-12-06T10:39:04.635Z'), +(5.574714431937615, 43.35019545388766, '2077-12-06T10:51:07.635Z'), +(11.531114605800186, 18.465483567669022, '2077-12-06T11:00:29.635Z'), +(13.569204849360064, 19.45085116845506, '2077-12-06T11:01:19.635Z'), +(15.32639461674605, 28.00183556970134, '2077-12-06T11:04:27.635Z'), +(14.226769912816659, 15.166930477886398, '2077-12-06T11:09:04.635Z'), +(9.690939342552571, 14.015201611323404, '2077-12-06T11:10:47.635Z'), +(9.73617006833808, 33.370687760334036, '2077-12-06T11:17:51.635Z'), +(20.398734753955388, 30.488784053364956, '2077-12-06T11:21:56.635Z'), +(21.139319840654835, 24.156822004986697, '2077-12-06T11:24:08.635Z'), +(23.151660181681024, 6.124091772132479, '2077-12-06T11:30:21.635Z'), +(13.571046612459552, 38.717447385578886, '2077-12-06T11:42:19.635Z'), +(22.087440234775755, 22.343041095674252, '2077-12-06T11:48:53.635Z'), +(2.7896031805387533, 15.331326448453733, '2077-12-06T11:56:28.635Z'), +(3.7396471559355433, 1.850277519779887, '2077-12-06T12:01:28.635Z'), +(5.401688128603146, 43.69725746595231, '2077-12-06T12:16:56.635Z'), +(12.566943080558547, 44.42611911466062, '2077-12-06T12:19:36.635Z'), +(12.933114652389122, 39.15758069590234, '2077-12-06T12:21:30.635Z'), +(2.9182492849542276, 4.728549036724442, '2077-12-06T12:34:39.635Z'), +(13.285412499829764, 32.20161364885596, '2077-12-06T12:45:25.635Z'), +(19.563074786925373, 13.887409252218939, '2077-12-06T12:52:19.635Z'), +(4.94915026205042, 34.675845703579995, '2077-12-06T13:01:34.635Z'), +(20.22167753522157, 8.776061723559362, '2077-12-06T13:12:28.635Z'), +(15.331739266644343, 34.83776738211689, '2077-12-06T13:21:49.635Z'), +(17.199824053540908, 8.41642061276804, '2077-12-06T13:31:14.635Z'), +(14.338026811351776, 23.06890000438726, '2077-12-06T13:36:33.635Z'), +(19.049191205751793, 45.89447037436752, '2077-12-06T13:44:49.635Z'), +(21.447883955443906, 30.35888450759026, '2077-12-06T13:50:17.635Z'), +(10.500544325695769, 39.95753425340546, '2077-12-06T13:55:35.635Z'), +(1.8214668043107798, 7.252749225460853, '2077-12-06T14:08:02.635Z'), +(22.143555648172107, 42.136615013069026, '2077-12-06T14:22:40.635Z'), +(6.135276404256976, 11.751021737658414, '2077-12-06T14:35:03.635Z'), +(18.34200883619778, 18.200183375299616, '2077-12-06T14:40:08.635Z'), +(2.0598074239297985, 2.3785742968022983, '2077-12-06T14:48:28.635Z'), +(17.262916281384232, 11.642222880961372, '2077-12-06T14:55:02.635Z'), +(0.12441268957860045, 9.441414686534156, '2077-12-06T15:01:26.635Z'), +(12.369650227956008, 47.691960273546, '2077-12-06T15:16:12.635Z'), +(11.709681941482467, 3.4272863033920924, '2077-12-06T15:32:13.635Z'), +(14.839729586870336, 21.19811416468959, '2077-12-06T15:38:43.635Z'), +(10.884483633938503, 48.28302616161236, '2077-12-06T15:48:36.635Z'), +(19.752721937040405, 47.82492159664063, '2077-12-06T15:51:53.635Z'), +(5.255617178498573, 3.6071555430183015, '2077-12-06T16:08:41.635Z'), +(6.294382060731257, 3.735123312574862, '2077-12-06T16:09:04.635Z'), +(5.152402954545953, 8.133509735111957, '2077-12-06T16:10:44.635Z'), +(7.637454307982522, 45.277875834236184, '2077-12-06T16:24:26.635Z'), +(23.54982818323113, 3.1639291607318745, '2077-12-06T16:40:30.635Z'), +(9.216155494149682, 3.410902285970709, '2077-12-06T16:45:48.635Z'), +(8.080848549999684, 37.34645211111294, '2077-12-06T16:58:14.635Z'), +(9.739953873744652, 48.711558655752675, '2077-12-06T17:02:26.635Z'), +(10.106024225468682, 15.54314179335824, '2077-12-06T17:14:32.635Z'), +(17.906447616294482, 31.722458179737497, '2077-12-06T17:21:01.635Z'), +(15.105178770497101, 25.846435369535808, '2077-12-06T17:23:20.635Z'), +(0.7560312845956693, 24.78461580951146, '2077-12-06T17:28:39.635Z'), +(19.999014929193667, 42.419702577299766, '2077-12-06T17:38:13.635Z'), +(10.944448677824935, 39.30565967961545, '2077-12-06T17:41:45.635Z'), +(18.82604565529819, 2.8812581704540356, '2077-12-06T17:55:05.635Z'), +(20.622202279435385, 4.866122651292115, '2077-12-06T17:56:02.635Z'), +(2.1504775958203295, 13.015933321013623, '2077-12-06T18:03:29.635Z'), +(6.176842396900387, 4.814677405141109, '2077-12-06T18:06:51.635Z'), +(8.521223742127749, 32.49192208641158, '2077-12-06T18:17:03.635Z'), +(19.718395172332148, 39.32401254883029, '2077-12-06T18:21:52.635Z'), +(22.414535281515942, 34.12250493429556, '2077-12-06T18:23:55.635Z'), +(18.56391921579862, 12.804313258042859, '2077-12-06T18:31:26.635Z'), +(0.05150787463396012, 35.98977090711527, '2077-12-06T18:42:18.635Z'), +(20.578899771871374, 44.73674761496589, '2077-12-06T18:50:32.635Z'), +(12.929479774806374, 41.17850046588972, '2077-12-06T18:53:38.635Z'), +(7.7900572743302305, 46.28882645601534, '2077-12-06T18:56:17.635Z'), +(19.46404604528853, 8.345591063727522, '2077-12-06T19:10:34.635Z'), +(12.066975492687433, 19.25762576657662, '2077-12-06T19:15:19.635Z'), +(1.9859207019738632, 9.237544738836464, '2077-12-06T19:20:33.635Z'), +(17.889658250872472, 42.90428160894311, '2077-12-06T19:34:08.635Z'), +(21.835801376488273, 17.232917413256963, '2077-12-06T19:43:11.635Z'), +(14.359523909082027, 38.1064185487707, '2077-12-06T19:51:01.635Z'), +(10.253126623786413, 34.24288731102375, '2077-12-06T19:53:05.635Z'), +(4.889176880613124, 32.98056128770944, '2077-12-06T19:55:07.635Z'), +(21.412579293964043, 29.991625017458134, '2077-12-06T20:01:20.635Z'), +(0.14037923581099843, 27.692056950266757, '2077-12-06T20:09:15.635Z'), +(13.78191868575281, 45.836666469792284, '2077-12-06T20:17:36.635Z'), +(17.713200697912225, 23.718451092712083, '2077-12-06T20:25:37.635Z'), +(20.17077786729953, 43.93206177382324, '2077-12-06T20:32:45.635Z'), +(2.761580950894382, 12.115980112790261, '2077-12-06T20:45:56.635Z'), +(5.62442749114799, 8.329694999208906, '2077-12-06T20:47:41.635Z'), +(19.796472218329118, 45.00347120712159, '2077-12-06T21:01:53.635Z'), +(10.373830758551, 13.909826746130058, '2077-12-06T21:13:31.635Z'), +(3.1870990347937243, 19.960067648524426, '2077-12-06T21:16:59.635Z'), +(23.19276737001308, 11.896239616804305, '2077-12-06T21:24:56.635Z'), +(7.922180054282954, 30.259176569154494, '2077-12-06T21:33:34.635Z'), +(7.727870715448015, 14.25534137938403, '2077-12-06T21:39:26.635Z'), +(19.611834117854304, 21.80291306823323, '2077-12-06T21:44:36.635Z'), +(4.0522161326556985, 37.834732287162744, '2077-12-06T21:52:46.635Z'), +(10.664156546483202, 32.501026838483284, '2077-12-06T21:55:54.635Z'), +(1.8213491350910282, 31.319695285909976, '2077-12-06T21:59:12.635Z'), +(13.190983914618782, 17.792539736321977, '2077-12-06T22:05:42.635Z'), +(7.42660709580517, 16.11955856221033, '2077-12-06T22:07:55.635Z'), +(19.655386694527298, 15.56405502526454, '2077-12-06T22:12:27.635Z'), +(17.074007606419954, 39.813799005096854, '2077-12-06T22:21:01.635Z'), +(16.44148828911669, 48.40632053025672, '2077-12-06T22:24:04.635Z'), +(10.97053955076421, 38.27040309353095, '2077-12-06T22:28:14.635Z'), +(5.560449423541168, 14.9771990864034, '2077-12-06T22:37:00.635Z'), +(14.08080627760012, 15.521938923731522, '2077-12-06T22:40:09.635Z'), +(5.864686091223044, 26.60373964257221, '2077-12-06T22:45:12.635Z'), +(5.119602159266741, 49.753506520438535, '2077-12-06T22:53:44.635Z'), +(10.729284832872235, 31.814597362945406, '2077-12-06T23:00:38.635Z'), +(5.780148143711667, 26.903646190897927, '2077-12-06T23:03:12.635Z'), +(21.52523920941328, 25.695638544552093, '2077-12-06T23:09:03.635Z'), +(19.35082777386356, 7.713760612498742, '2077-12-06T23:15:20.635Z'), +(2.826683113814038, 28.913209039156825, '2077-12-06T23:25:09.635Z'), +(5.86825800253817, 18.919007691024184, '2077-12-06T23:29:00.635Z'), +(20.412374275316076, 16.778477200351844, '2077-12-06T23:34:26.635Z'), +(9.41941566168546, 40.075524833252864, '2077-12-06T23:43:42.635Z'), +(22.09726081021016, 33.21924091459636, '2077-12-06T23:48:59.635Z'), +(7.070125185792935, 16.857413004603274, '2077-12-06T23:57:03.635Z'), +(16.88080753981063, 35.86699274225265, '2077-12-07T00:04:49.635Z'), +(14.971397717168232, 3.8221603206255814, '2077-12-07T00:16:14.635Z'), +(4.0444673097467225, 21.91004519664445, '2077-12-07T00:23:58.635Z'), +(2.797368470872108, 17.907548060818037, '2077-12-07T00:25:31.635Z'), +(2.80625198108181, 49.86920222397656, '2077-12-07T00:37:20.635Z'), +(2.2403126721459015, 43.90276935996612, '2077-12-07T00:39:33.635Z'), +(14.579441179810939, 5.2880254973970935, '2077-12-07T00:54:23.635Z'), +(22.92424496909276, 0.10307257555105291, '2077-12-07T00:57:58.635Z'), +(22.706172155769394, 29.72173946323235, '2077-12-07T01:08:04.635Z'), +(16.193087191372598, 8.199790849780943, '2077-12-07T01:15:57.635Z'), +(15.23355674414521, 34.32151915946673, '2077-12-07T01:25:16.635Z'), +(8.242350324861205, 23.82851676393785, '2077-12-07T01:29:52.635Z'), +(16.905239046011395, 2.3376504725234173, '2077-12-07T01:38:16.635Z'), +(23.263460562632723, 5.333162371220998, '2077-12-07T01:40:50.635Z'), +(9.99178446039952, 16.61176493053234, '2077-12-07T01:47:10.635Z'), +(21.414605218825557, 10.57582186479615, '2077-12-07T01:51:54.635Z'), +(15.502621532873446, 26.047292157834224, '2077-12-07T01:57:45.635Z'), +(2.501881146071783, 1.1074753754031934, '2077-12-07T02:08:03.635Z'), +(2.532151373018175, 45.01390621592586, '2077-12-07T02:24:18.635Z'), +(10.89684358758154, 9.966325284251868, '2077-12-07T02:37:33.635Z'), +(12.467183605964804, 19.732208716576356, '2077-12-07T02:41:08.635Z'), +(2.863278971974323, 22.112558997374975, '2077-12-07T02:44:47.635Z'), +(17.966123559625416, 17.172628486917702, '2077-12-07T02:50:39.635Z'), +(21.24299208585266, 39.30105128203808, '2077-12-07T02:58:27.635Z'), +(3.1111297832786704, 34.78885391977182, '2077-12-07T03:05:21.635Z'), +(15.365492388850557, 43.27055583193947, '2077-12-07T03:10:50.635Z'), +(11.426611646132894, 25.001881333787203, '2077-12-07T03:17:34.635Z'), +(2.0960001618640307, 5.992026951283789, '2077-12-07T03:25:21.635Z'), +(3.0293642939924483, 23.45378299004547, '2077-12-07T03:31:49.635Z'), +(6.168776161804245, 18.799939659582577, '2077-12-07T03:33:53.635Z'), +(11.349295562877803, 35.353123039692015, '2077-12-07T03:40:14.635Z'), +(12.891880253389758, 24.655146143788098, '2077-12-07T03:44:09.635Z'), +(18.68722287907606, 43.376813232474994, '2077-12-07T03:51:09.635Z'), +(14.166374009921189, 15.08219454364793, '2077-12-07T04:01:20.635Z'), +(13.554851847832111, 6.400643929780085, '2077-12-07T04:04:27.635Z'), +(15.322211937789318, 36.37678279173007, '2077-12-07T04:15:13.635Z'), +(9.036982550099992, 14.671675586480953, '2077-12-07T04:23:24.635Z'), +(20.682907821252666, 13.315860733213158, '2077-12-07T04:27:44.635Z'), +(2.114549720851682, 3.3782200894204197, '2077-12-07T04:35:29.635Z'), +(12.139741613184905, 21.365995554727853, '2077-12-07T04:43:03.635Z'), +(12.65424182470952, 15.050308992260826, '2077-12-07T04:45:20.635Z'), +(16.737100715980425, 5.589518739593911, '2077-12-07T04:49:02.635Z'), +(17.177503265936004, 10.799959219200304, '2077-12-07T04:50:53.635Z'), +(5.621634574383314, 44.09013660066991, '2077-12-07T05:03:41.635Z'), +(8.08066151932726, 10.46732971809344, '2077-12-07T05:16:05.635Z'), +(16.95826279724021, 9.809141873032281, '2077-12-07T05:19:22.635Z'), +(1.792611371512366, 0.4209226032096945, '2077-12-07T05:25:56.635Z'), +(2.251634169234025, 34.311236861479735, '2077-12-07T05:38:29.635Z'), +(4.2160541552711495, 2.720182647870952, '2077-12-07T05:50:11.635Z'), +(10.50190736636733, 9.42212311969557, '2077-12-07T05:53:34.635Z'), +(2.9689360199772272, 6.16973802573329, '2077-12-07T05:56:36.635Z'), +(3.1071138574585473, 24.46792108267247, '2077-12-07T06:03:22.635Z'), +(22.050173239868922, 13.521658446784256, '2077-12-07T06:11:25.635Z'), +(22.09517682587858, 20.431534782530175, '2077-12-07T06:13:47.635Z'), +(3.215225823914689, 5.677100003454182, '2077-12-07T06:22:33.635Z'), +(8.926911521587494, 13.608741188651287, '2077-12-07T06:26:09.635Z'), +(4.4495432216253405, 20.94806027839348, '2077-12-07T06:29:19.635Z'), +(4.119711335919198, 7.75626513426532, '2077-12-07T06:34:11.635Z'), +(10.634918893051067, 0.5355548769497438, '2077-12-07T06:37:46.635Z'), +(13.861358575877897, 24.136010041014895, '2077-12-07T06:46:23.635Z'), +(15.187257863511418, 14.59566709746675, '2077-12-07T06:49:50.635Z'), +(4.728795986249031, 37.315569701327505, '2077-12-07T06:58:58.635Z'), +(10.457076047516999, 8.18938410085072, '2077-12-07T07:09:52.635Z'), +(14.952864910674485, 4.647066670907225, '2077-12-07T07:11:58.635Z'), +(6.6940264034460855, 41.70977340155768, '2077-12-07T07:25:46.635Z'), +(8.711191899401625, 24.47536053549891, '2077-12-07T07:32:08.635Z'), +(8.476925457622498, 11.31435579208325, '2077-12-07T07:36:57.635Z'), +(13.79189147897867, 41.33749534035428, '2077-12-07T07:48:02.635Z'), +(0.22589692683927637, 23.98547345105724, '2077-12-07T07:56:08.635Z'), +(17.1050328258907, 32.69825142636896, '2077-12-07T08:03:09.635Z'), +(8.957786491560878, 3.1500776764867027, '2077-12-07T08:14:13.635Z'), +(19.880733496396957, 29.171580095262616, '2077-12-07T08:24:22.635Z'), +(2.61740355712555, 47.433492613657805, '2077-12-07T08:33:33.635Z'), +(6.168471713254974, 32.20358137547708, '2077-12-07T08:39:19.635Z'), +(12.048154997206934, 8.953311756442952, '2077-12-07T08:48:05.635Z'), +(20.200683045959394, 49.97631409999361, '2077-12-07T09:02:57.635Z'), +(18.518660024941575, 0.3647898065811575, '2077-12-07T09:20:14.635Z'), +(17.65810981912368, 15.526141617129745, '2077-12-07T09:25:34.635Z'), +(5.437929035652271, 25.270726462833846, '2077-12-07T09:31:18.635Z'), +(7.593588959197916, 36.95481772320701, '2077-12-07T09:35:40.635Z'), +(14.248167726001546, 17.244247802854186, '2077-12-07T09:43:14.635Z'), +(10.165247674978497, 40.03176542162058, '2077-12-07T09:51:37.635Z'), +(12.583701135441489, 24.09302066795668, '2077-12-07T09:57:28.635Z'), +(21.668349162119902, 24.118108994110248, '2077-12-07T10:00:50.635Z'), +(2.6073860576689247, 28.580671675326244, '2077-12-07T10:08:04.635Z'), +(14.111563409879983, 1.5274757962273244, '2077-12-07T10:18:50.635Z'), +(1.3491912785976377, 32.016599956855956, '2077-12-07T10:30:57.635Z'), +(8.996124350212957, 23.92346556146004, '2077-12-07T10:35:03.635Z'), +(20.033830174609506, 5.82553096921783, '2077-12-07T10:42:42.635Z'), +(19.53617474775135, 11.528968493659287, '2077-12-07T10:44:41.635Z'), +(13.24272457006845, 23.300596596570024, '2077-12-07T10:49:28.635Z'), +(12.534846794650093, 21.031260820514817, '2077-12-07T10:50:19.635Z'), +(3.9667237826259387, 1.002491941034499, '2077-12-07T10:58:18.635Z'), +(7.3153367391805, 18.62163003659459, '2077-12-07T11:04:54.635Z'), +(21.9837766592752, 39.913693025896436, '2077-12-07T11:14:15.635Z'), +(23.41591709249379, 37.38133925255115, '2077-12-07T11:15:15.635Z'), +(8.467942569103316, 38.179409169205655, '2077-12-07T11:20:47.635Z'), +(12.731347432773719, 6.118329151192619, '2077-12-07T11:32:33.635Z'), +(19.17473753416156, 35.09657987224365, '2077-12-07T11:43:08.635Z'), +(21.36709747142408, 0.6998142131707701, '2077-12-07T11:55:05.635Z'), +(1.4601644550246948, 31.030023659997955, '2077-12-07T12:08:17.635Z'), +(5.838415059168941, 41.52626261512357, '2077-12-07T12:12:29.635Z'), +(18.278086955135404, 8.978672983206703, '2077-12-07T12:25:07.635Z'), +(4.04559116145476, 17.777357635115663, '2077-12-07T12:31:16.635Z'), +(5.946632561080438, 18.54135583959396, '2077-12-07T12:32:01.635Z'), +(6.174051459857089, 49.07224102678216, '2077-12-07T12:43:16.635Z'), +(0.4997114594444551, 8.014610690349468, '2077-12-07T12:58:35.635Z'), +(5.1370055911899115, 17.31239999796647, '2077-12-07T13:02:25.635Z'), +(14.04415177287545, 11.000256870343607, '2077-12-07T13:06:26.635Z'), +(16.656760618585636, 19.919440266799363, '2077-12-07T13:09:45.635Z'), +(10.197369611576578, 3.4616929475996243, '2077-12-07T13:16:08.635Z'), +(12.174317678369933, 39.41181708266086, '2077-12-07T13:29:12.635Z'), +(6.971066753863152, 0.08278082150557195, '2077-12-07T13:43:41.635Z'), +(16.994667764757953, 34.05727101737205, '2077-12-07T13:56:31.635Z'), +(23.536140950831467, 38.03163136292842, '2077-12-07T13:59:18.635Z'), +(7.8293081282287895, 4.023994629323019, '2077-12-07T14:12:42.635Z'), +(9.058733947849253, 18.049531704276454, '2077-12-07T14:17:51.635Z'), +(9.831313343220994, 43.43003912870674, '2077-12-07T14:27:07.635Z'), +(13.425589851728763, 23.150198215912372, '2077-12-07T14:34:35.635Z'), +(6.838197901447827, 39.31780910146394, '2077-12-07T14:40:57.635Z'), +(19.110418420223752, 41.017968445379076, '2077-12-07T14:45:32.635Z'), +(6.296780363018166, 10.32577292919429, '2077-12-07T14:57:34.635Z'), +(20.13570520617352, 45.50897669072292, '2077-12-07T15:11:12.635Z'), +(19.150111026185773, 1.554811100034142, '2077-12-07T15:26:30.635Z'), +(22.979168393755, 33.45560065890749, '2077-12-07T15:37:36.635Z'), +(21.605719787483054, 44.348225676780245, '2077-12-07T15:41:22.635Z'), +(19.67163157956017, 8.001728249970405, '2077-12-07T15:53:57.635Z'), +(4.970678344580376, 8.780069891041968, '2077-12-07T15:59:24.635Z'), +(20.7448766963345, 18.47563470625768, '2077-12-07T16:06:12.635Z'), +(14.669469331543445, 1.606555297953228, '2077-12-07T16:12:33.635Z'), +(15.674909890174565, 22.50448263498105, '2077-12-07T16:20:01.635Z'), +(21.65579513701165, 22.601627403432765, '2077-12-07T16:22:14.635Z'), +(22.435957746254864, 3.367114022501761, '2077-12-07T16:28:50.635Z'), +(7.942942058293505, 32.87949040304838, '2077-12-07T16:40:38.635Z'), +(18.962603306636794, 40.9782471190124, '2077-12-07T16:45:39.635Z'), +(12.417850584442405, 6.131837070125539, '2077-12-07T16:58:17.635Z'), +(15.68026853940589, 8.978591237914364, '2077-12-07T16:59:52.635Z'), +(5.219026096171337, 48.49374501664608, '2077-12-07T17:14:45.635Z'), +(19.13959034109205, 0.8369482931329176, '2077-12-07T17:32:42.635Z'), +(16.782759803466504, 30.97283187382564, '2077-12-07T17:43:20.635Z'), +(10.036243386082651, 9.979816323479955, '2077-12-07T17:51:17.635Z'), +(8.93358714414942, 16.049332827565323, '2077-12-07T17:53:32.635Z'), +(15.422198480129166, 11.290608106184411, '2077-12-07T17:56:29.635Z'), +(1.0076396663083842, 47.169112714051224, '2077-12-07T18:10:38.635Z'), +(12.714098184047451, 22.108592582484334, '2077-12-07T18:20:48.635Z'), +(18.765008961195235, 5.326661520396584, '2077-12-07T18:27:11.635Z'), +(18.307981156748298, 36.702883864196615, '2077-12-07T18:38:11.635Z'), +(12.129296335598694, 43.321636941127636, '2077-12-07T18:41:28.635Z'), +(8.762252405125606, 4.471519388299992, '2077-12-07T18:55:40.635Z'), +(16.05069292846904, 3.5394932080469372, '2077-12-07T18:58:23.635Z'), +(11.04205582164964, 8.981757952960292, '2077-12-07T19:01:04.635Z'), +(14.55064607452839, 38.66053503210213, '2077-12-07T19:11:51.635Z'), +(7.231205149586699, 38.73162788557233, '2077-12-07T19:14:33.635Z'), +(3.1557204912249714, 25.055366586668267, '2077-12-07T19:19:49.635Z'), +(5.055726442573288, 10.013630271924008, '2077-12-07T19:25:25.635Z'), +(17.96999687405565, 9.41752968921716, '2077-12-07T19:30:12.635Z'), +(17.147095613900333, 47.99406306988227, '2077-12-07T19:43:48.635Z'), +(1.8547165918387567, 35.53902632554589, '2077-12-07T19:51:03.635Z'), +(7.215822200043406, 35.65771990059168, '2077-12-07T19:53:02.635Z'), +(3.4004178371767124, 43.52568522943022, '2077-12-07T19:56:15.635Z'), +(3.1489271225194577, 4.1217353664813405, '2077-12-07T20:10:49.635Z'), +(14.692722953492792, 26.944554474251184, '2077-12-07T20:20:11.635Z'), +(21.757006983751772, 38.909859371079605, '2077-12-07T20:25:08.635Z'), +(15.542068045536165, 28.48788442645811, '2077-12-07T20:29:27.635Z'), +(2.925586503210253, 26.18825716089833, '2077-12-07T20:34:12.635Z'), +(19.809820097146066, 4.585578424259157, '2077-12-07T20:44:12.635Z'), +(21.747691498232292, 10.302724206401592, '2077-12-07T20:46:18.635Z'), +(20.253289822291546, 16.536774062246575, '2077-12-07T20:48:31.635Z'), +(10.635291064783791, 25.156283797928833, '2077-12-07T20:53:13.635Z'), +(7.579134530104788, 35.00004858405576, '2077-12-07T20:56:59.635Z'), +(1.648841588407949, 41.00733824072274, '2077-12-07T21:00:06.635Z'), +(3.56854459274781, 8.865305999872367, '2077-12-07T21:12:01.635Z'), +(9.40298130045932, 42.89450210507221, '2077-12-07T21:24:43.635Z'), +(7.677242311355111, 39.94712925695699, '2077-12-07T21:25:58.635Z'), +(9.110040477772174, 44.992250551912086, '2077-12-07T21:27:53.635Z'), +(17.645158821998553, 36.6528024075159, '2077-12-07T21:32:14.635Z'), +(15.723555587261188, 19.266403178559752, '2077-12-07T21:38:26.635Z'), +(15.70567537482102, 16.165449634349184, '2077-12-07T21:39:32.635Z'), +(18.65904720521685, 32.836639449949494, '2077-12-07T21:45:32.635Z'), +(2.1516896167177, 3.806591373451414, '2077-12-07T21:57:43.635Z'), +(17.067044041139575, 2.933122501301084, '2077-12-07T22:03:15.635Z'), +(0.7304578543456124, 13.878696504383859, '2077-12-07T22:10:30.635Z'), +(6.566135416608095, 31.338127081638994, '2077-12-07T22:17:18.635Z'), +(17.638590080952202, 20.240483777985858, '2077-12-07T22:23:02.635Z'), +(3.4670964379700804, 10.77825299452779, '2077-12-07T22:29:18.635Z'), +(15.444442685824757, 29.64527868579864, '2077-12-07T22:37:29.635Z'), +(11.653491608480094, 39.799113940184014, '2077-12-07T22:41:24.635Z'), +(21.57686634501492, 18.208787972194717, '2077-12-07T22:49:53.635Z'), +(3.7850481063871144, 18.27155643532943, '2077-12-07T22:56:28.635Z'), +(15.619863649375445, 27.516482279494227, '2077-12-07T23:01:59.635Z'), +(14.745700598214377, 14.369674413377185, '2077-12-07T23:06:41.635Z'), +(19.79981298819689, 28.27179504493862, '2077-12-07T23:11:56.635Z'), +(17.36808113760749, 38.649034142395784, '2077-12-07T23:15:41.635Z'), +(5.334917584957251, 9.934275087863437, '2077-12-07T23:27:00.635Z'), +(16.571227391132943, 47.62590243481519, '2077-12-07T23:41:18.635Z'), +(8.45078221732256, 3.747980215369513, '2077-12-07T23:57:25.635Z'), +(14.273231405837716, 47.7234564427369, '2077-12-08T00:13:31.635Z'), +(12.326014044918464, 46.32107688858042, '2077-12-08T00:14:23.635Z'), +(23.319037467104582, 38.98331868672604, '2077-12-08T00:19:12.635Z'), +(5.714630084696383, 40.977859654259134, '2077-12-08T00:25:45.635Z'), +(12.277862488530245, 3.4545167529547354, '2077-12-08T00:39:41.635Z'), +(18.552285475621662, 1.587832316961222, '2077-12-08T00:42:06.635Z'), +(14.784337742173287, 37.54917237247728, '2077-12-08T00:54:55.635Z'), +(9.29649167413569, 8.004565753374454, '2077-12-08T01:05:48.635Z'), +(9.337959317017846, 37.367455415094724, '2077-12-08T01:16:32.635Z'), +(2.2433256473423655, 41.958478102601994, '2077-12-08T01:19:39.635Z'), +(19.659072375579303, 43.78683820324756, '2077-12-08T01:26:08.635Z'), +(2.3928267314298965, 39.82541583853962, '2077-12-08T01:32:41.635Z'), +(6.279724541651608, 38.13761933932225, '2077-12-08T01:34:15.635Z'), +(1.0423296171336336, 12.668387088101591, '2077-12-08T01:43:51.635Z'), +(7.205958745671187, 17.62449416239868, '2077-12-08T01:46:46.635Z'), +(13.742324618415799, 48.99849069044047, '2077-12-08T01:58:26.635Z'), +(7.479595608107843, 13.823965140410083, '2077-12-08T02:11:26.635Z'), +(10.18500832486401, 37.01130009924201, '2077-12-08T02:19:58.635Z'), +(11.197566070223214, 23.010185800280663, '2077-12-08T02:25:04.635Z'), +(18.4972217640786, 26.77762598585906, '2077-12-08T02:28:05.635Z'), +(19.384754886252953, 24.24111867970848, '2077-12-08T02:29:01.635Z'), +(19.774404562594675, 17.79087552593543, '2077-12-08T02:31:16.635Z'), +(8.098788844328197, 6.3467798083876215, '2077-12-08T02:37:14.635Z'), +(2.3233323347864308, 1.0974875140553026, '2077-12-08T02:40:07.635Z'), +(14.919821418753846, 50.10602327285285, '2077-12-08T02:58:37.635Z'), +(2.860224032100044, 9.316868623632939, '2077-12-08T03:14:10.635Z'), +(17.70249779992073, 27.9389576805446, '2077-12-08T03:22:53.635Z'), +(9.218246810608552, 28.266708159440952, '2077-12-08T03:26:01.635Z'), +(1.6941298779190743, 28.552941572010738, '2077-12-08T03:28:48.635Z'), +(8.17434790206075, 26.469157408583975, '2077-12-08T03:31:19.635Z'), +(2.931021057838872, 38.61279050006808, '2077-12-08T03:36:11.635Z'), +(11.011486599816559, 17.883771698755677, '2077-12-08T03:44:22.635Z'), +(18.97967279088644, 16.941943435823482, '2077-12-08T03:47:20.635Z'), +(22.853974087317987, 15.876930140921905, '2077-12-08T03:48:48.635Z'), +(7.378475071760565, 12.848721296095894, '2077-12-08T03:54:38.635Z'), +(10.352342706888756, 22.567411791478435, '2077-12-08T03:58:21.635Z'), +(4.978661552222413, 41.69600653605201, '2077-12-08T04:05:39.635Z'), +(9.205853593349344, 8.746214767382504, '2077-12-08T04:17:51.635Z'), +(18.863756412996157, 13.097758871929344, '2077-12-08T04:21:45.635Z'), +(1.3721315133807845, 41.581394571130026, '2077-12-08T04:33:57.635Z'), +(20.56304989711053, 27.271113756790278, '2077-12-08T04:42:44.635Z'), +(9.061452871215886, 46.95604470400323, '2077-12-08T04:50:57.635Z'), +(14.52866423608222, 33.75672171831867, '2077-12-08T04:56:08.635Z'), +(11.581887050340368, 19.321559897955524, '2077-12-08T05:01:27.635Z'), +(8.158517169482263, 42.31830067920813, '2077-12-08T05:09:56.635Z'), +(22.661455259135927, 27.568031921764117, '2077-12-08T05:17:26.635Z'), +(7.428456946876989, 48.393656077315256, '2077-12-08T05:26:45.635Z'), +(10.875479573127869, 21.609374824477886, '2077-12-08T05:36:37.635Z'), +(22.85142534475246, 35.220138343625884, '2077-12-08T05:43:09.635Z'), +(16.406112141937598, 7.012098209360265, '2077-12-08T05:53:15.635Z'), +(11.329943139775738, 33.532375093186886, '2077-12-08T06:02:58.635Z'), +(2.4487839273070255, 19.212660521000828, '2077-12-08T06:09:10.635Z'), +(21.61873707966477, 43.733343875391704, '2077-12-08T06:20:30.635Z'), +(6.997434855996535, 33.47522925568041, '2077-12-08T06:27:02.635Z'), +(22.58838073894342, 39.96164758841851, '2077-12-08T06:33:15.635Z'), +(16.661822888383245, 8.84187491134565, '2077-12-08T06:44:18.635Z'), +(13.693327810312338, 41.27184996825373, '2077-12-08T06:55:56.635Z'), +(6.822013171157114, 5.184209159522966, '2077-12-08T07:09:19.635Z'), +(5.2066337319644065, 15.110911658715096, '2077-12-08T07:13:01.635Z'), +(14.818142975408383, 42.90208527393383, '2077-12-08T07:23:45.635Z'), +(18.443187482349483, 15.508225167692748, '2077-12-08T07:33:33.635Z'), +(6.25185562622699, 33.795516987499354, '2077-12-08T07:41:33.635Z'), +(11.207449127637254, 38.04701399444646, '2077-12-08T07:43:57.635Z'), +(4.7282670916563525, 25.905898757571073, '2077-12-08T07:49:00.635Z'), +(21.670116481250147, 25.57512671795979, '2077-12-08T07:55:16.635Z'), +(13.54136145117529, 49.82265970888447, '2077-12-08T08:04:19.635Z'), +(5.327733500433976, 35.31983476937674, '2077-12-08T08:10:25.635Z'), +(14.3293820951487, 46.41505340209883, '2077-12-08T08:15:39.635Z'), +(0.8922028969435664, 13.217598859062937, '2077-12-08T08:28:47.635Z'), +(17.18420413375748, 24.20627916795136, '2077-12-08T08:36:01.635Z'), +(7.204134693560999, 6.430049334959858, '2077-12-08T08:43:26.635Z'), +(10.433110870575934, 8.132816159286527, '2077-12-08T08:44:46.635Z'), +(9.87643268164123, 19.83924447726458, '2077-12-08T08:49:02.635Z'), +(6.967211248674813, 8.624078942945784, '2077-12-08T08:53:17.635Z'), +(5.466322467154396, 26.839150512128285, '2077-12-08T09:00:01.635Z'), +(7.160468250860852, 6.627096857406851, '2077-12-08T09:07:29.635Z'), +(14.627404823578642, 12.617201328907719, '2077-12-08T09:11:00.635Z'), +(20.960438034917757, 22.703439657955386, '2077-12-08T09:15:15.635Z'), +(6.217023882793369, 10.523034023958912, '2077-12-08T09:22:14.635Z'), +(7.796230787679779, 33.82327248952924, '2077-12-08T09:30:49.635Z'), +(14.6877538652583, 42.15005657658792, '2077-12-08T09:34:46.635Z'), +(18.30733089646811, 12.325512028500182, '2077-12-08T09:45:26.635Z'), +(4.184722369176912, 4.410101822239786, '2077-12-08T09:51:24.635Z'), +(8.978038699360589, 23.661560100126774, '2077-12-08T09:58:42.635Z'), +(15.58667709414948, 17.75228657892028, '2077-12-08T10:01:57.635Z'), +(13.539382524130207, 19.441723631616867, '2077-12-08T10:02:55.635Z'), +(14.056617463581555, 37.11152690066262, '2077-12-08T10:09:16.635Z'), +(3.088360751768934, 34.79309565987503, '2077-12-08T10:13:25.635Z'), +(12.983630206475341, 0.35949105445049584, '2077-12-08T10:26:33.635Z'), +(17.514259683229835, 23.068492087957537, '2077-12-08T10:34:50.635Z'), +(9.247331021013077, 2.0143248349481584, '2077-12-08T10:43:00.635Z'), +(18.448034931976583, 16.4528971488389, '2077-12-08T10:49:12.635Z'), +(5.841868518885862, 39.44566435153693, '2077-12-08T10:58:43.635Z'), +(18.370376656446023, 10.426425226431977, '2077-12-08T11:10:11.635Z'), +(22.316161387520598, 11.073351968367525, '2077-12-08T11:11:39.635Z'), +(11.746172755781783, 14.901138560957653, '2077-12-08T11:15:47.635Z'), +(18.211596220382127, 0.6357187806924837, '2077-12-08T11:21:25.635Z'), +(21.74724491582636, 2.116772581369791, '2077-12-08T11:22:49.635Z'), +(12.591619209980339, 46.85510435372579, '2077-12-08T11:38:57.635Z'), +(5.452616670131107, 26.022545349978184, '2077-12-08T11:47:00.635Z'), +(8.856805385826117, 8.624035697180759, '2077-12-08T11:53:31.635Z'), +(9.79788237683865, 49.89199407877916, '2077-12-08T12:08:36.635Z'), +(9.831486527244568, 7.241759705603869, '2077-12-08T12:24:09.635Z'), +(7.78902390613816, 44.55641787850997, '2077-12-08T12:37:49.635Z'), +(16.109165106224854, 17.85105424796099, '2077-12-08T12:47:58.635Z'), +(16.944153800214224, 4.083323239400052, '2077-12-08T12:52:52.635Z'), +(15.764345433417525, 15.66124801491301, '2077-12-08T12:57:00.635Z'), +(21.41180011394148, 39.8040245215031, '2077-12-08T13:05:43.635Z'), +(15.214397768609436, 4.338830703037349, '2077-12-08T13:18:22.635Z'), +(19.29331291441242, 14.483094246224596, '2077-12-08T13:22:15.635Z'), +(11.562666880540108, 14.486826481216559, '2077-12-08T13:25:06.635Z'), +(16.77504470731262, 47.16848018701749, '2077-12-08T13:36:59.635Z'), +(11.365460940865862, 23.91274896726673, '2077-12-08T13:45:34.635Z'), +(16.505972904978258, 36.5501527997142, '2077-12-08T13:50:29.635Z'), +(3.0634547652012283, 20.255652641950775, '2077-12-08T13:58:14.635Z'), +(23.25239894386719, 47.51879041361296, '2077-12-08T14:10:32.635Z'), +(9.413454431611475, 42.292600364620746, '2077-12-08T14:15:59.635Z'), +(20.00512278714841, 13.363132923137826, '2077-12-08T14:27:02.635Z'), +(6.857282514218051, 14.648485927871741, '2077-12-08T14:31:55.635Z'), +(0.686895066975497, 29.720446086183923, '2077-12-08T14:37:56.635Z'), +(22.09651095179536, 34.17954554590202, '2077-12-08T14:46:01.635Z'), +(10.751279924249218, 24.60370189094812, '2077-12-08T14:51:25.635Z'), +(9.118290480758606, 26.141672844273472, '2077-12-08T14:52:14.635Z'), +(1.023260456270273, 39.2509598956495, '2077-12-08T14:57:55.635Z'), +(13.017282913894244, 3.6054602684630463, '2077-12-08T15:11:44.635Z'), +(14.948593807274753, 16.54598652079293, '2077-12-08T15:16:26.635Z'), +(22.085927541543843, 21.236996083577598, '2077-12-08T15:19:32.635Z'), +(11.35139522768548, 42.67344475462647, '2077-12-08T15:28:06.635Z'), +(6.042069761599743, 0.02772817469486592, '2077-12-08T15:43:50.635Z'), +(22.04469928952155, 2.191917021194316, '2077-12-08T15:49:48.635Z'), +(8.930388958359497, 34.82893166815647, '2077-12-08T16:02:23.635Z'), +(6.901887652471372, 10.526129246693243, '2077-12-08T16:11:20.635Z'), +(17.459676691151262, 13.028142267320861, '2077-12-08T16:15:20.635Z'), +(7.693124044481606, 5.82335445128339, '2077-12-08T16:19:47.635Z'), +(15.369482503759631, 11.231640544072109, '2077-12-08T16:23:14.635Z'), +(8.597495349456517, 10.815254334378594, '2077-12-08T16:25:44.635Z'), +(4.265121736116223, 5.091292722759434, '2077-12-08T16:28:22.635Z'), +(17.604039407272843, 25.431140263670358, '2077-12-08T16:37:15.635Z'), +(18.994235373852117, 12.516111209279986, '2077-12-08T16:41:49.635Z'), +(4.4044341566279135, 26.396943085882278, '2077-12-08T16:49:11.635Z'), +(20.279919127905753, 29.699064240018878, '2077-12-08T16:55:11.635Z'), +(15.423831199392618, 8.611309358429898, '2077-12-08T17:02:49.635Z'), +(2.680167404214424, 22.040470432344804, '2077-12-08T17:09:37.635Z'), +(11.249523007441564, 18.094018030901026, '2077-12-08T17:13:06.635Z'), +(21.276819372783542, 30.06254057010287, '2077-12-08T17:18:44.635Z'), +(10.79463549803862, 16.270575958949753, '2077-12-08T17:24:59.635Z'), +(3.909359465607828, 31.154180252304993, '2077-12-08T17:31:01.635Z'), +(15.103396119555981, 13.052156320913962, '2077-12-08T17:38:49.635Z'), +(21.003922492134745, 6.960413937500181, '2077-12-08T17:41:52.635Z'), +(22.87844111736295, 49.51047997551912, '2077-12-08T17:56:27.635Z'), +(8.376852847282892, 20.58611417826273, '2077-12-08T18:08:03.635Z'), +(17.66785859979403, 23.88862948819782, '2077-12-08T18:11:41.635Z'), +(20.88397161394427, 28.371009362161676, '2077-12-08T18:13:39.635Z'), +(7.04607304562066, 22.796478309702856, '2077-12-08T18:19:09.635Z'), +(8.149049835593695, 27.513278540435106, '2077-12-08T18:20:55.635Z'), +(21.340763372547908, 30.02114459587649, '2077-12-08T18:25:53.635Z'), +(20.56356839963108, 36.97805099755929, '2077-12-08T18:28:18.635Z'), +(14.883239402347419, 13.180609316018684, '2077-12-08T18:36:57.635Z'), +(9.416294178286613, 34.47302871888385, '2077-12-08T18:44:55.635Z'), +(16.349248408141968, 47.96417537768087, '2077-12-08T18:50:25.635Z'), +(4.166732351698274, 12.113693129935218, '2077-12-08T19:04:13.635Z'), +(12.761330396546457, 22.989332791897308, '2077-12-08T19:09:19.635Z'), +(5.9650105926821295, 45.910556288637906, '2077-12-08T19:18:03.635Z'), +(11.647808547913199, 21.03771433668075, '2077-12-08T19:27:23.635Z'), +(1.0018905845047228, 12.275164808265403, '2077-12-08T19:32:28.635Z'), +(18.690393109642244, 26.163005387157508, '2077-12-08T19:40:44.635Z'), +(1.3806885327596248, 43.58946406084551, '2077-12-08T19:49:44.635Z'), +(1.942117707476816, 18.84998298370496, '2077-12-08T19:58:54.635Z'), +(13.905377199509369, 35.61253949058473, '2077-12-08T20:06:28.635Z'), +(9.203042173603356, 27.882116681618093, '2077-12-08T20:09:46.635Z'), +(0.9206829264117202, 8.167791217196223, '2077-12-08T20:17:39.635Z'), +(13.154668145021578, 32.087701828977686, '2077-12-08T20:27:31.635Z'), +(17.63641671554117, 49.70535796223605, '2077-12-08T20:34:01.635Z'), +(2.1266921894290967, 6.569246381042491, '2077-12-08T20:50:43.635Z'), +(8.786525219339426, 17.299905240906984, '2077-12-08T20:55:22.635Z'), +(2.6616350839482896, 14.149855930274295, '2077-12-08T20:57:54.635Z'), +(4.844828090966431, 1.9196913722400202, '2077-12-08T21:02:29.635Z'), +(13.368394756679002, 22.96684200818744, '2077-12-08T21:10:48.635Z'), +(11.51010924859087, 43.980281873873174, '2077-12-08T21:18:26.635Z'), +(5.664580232171612, 11.798352591909673, '2077-12-08T21:30:24.635Z'), +(19.094425089553507, 30.90141538505859, '2077-12-08T21:38:54.635Z'), +(16.48564218431359, 20.172042480675398, '2077-12-08T21:42:48.635Z'), +(14.981901287683344, 39.70088916777266, '2077-12-08T21:49:47.635Z'), +(21.741527680261648, 21.51303697174661, '2077-12-08T21:56:38.635Z'), +(7.919290301519996, 35.178811803910534, '2077-12-08T22:03:42.635Z'), +(18.60649038138326, 17.51296439887854, '2077-12-08T22:11:11.635Z'), +(10.182706743731009, 31.122421559704943, '2077-12-08T22:16:58.635Z'), +(23.15538125183502, 45.518073042117486, '2077-12-08T22:23:58.635Z'), +(16.768293347532254, 18.64831034059459, '2077-12-08T22:33:36.635Z'), +(14.651956003605227, 47.3915019549257, '2077-12-08T22:43:52.635Z'), +(6.111616387740173, 20.961590883216708, '2077-12-08T22:53:59.635Z'), +(10.564305475240253, 41.099047535470255, '2077-12-08T23:01:32.635Z'), +(21.096156712668456, 3.61264828082763, '2077-12-08T23:15:25.635Z'), +(3.9918466506040398, 0.3148735677682901, '2077-12-08T23:21:52.635Z'), +(2.650828072297406, 37.86292710591947, '2077-12-08T23:35:46.635Z'), +(3.6423737162972634, 21.2867049820785, '2077-12-08T23:41:54.635Z'), +(17.3541367907223, 29.65417362055444, '2077-12-08T23:47:49.635Z'), +(14.058311834139019, 9.0530427571123, '2077-12-08T23:55:15.635Z'), +(18.847444118160055, 40.16628515066367, '2077-12-09T00:06:26.635Z'), +(21.789308198250268, 10.160016115833631, '2077-12-09T00:16:54.635Z'), +(16.660968722132377, 14.92676733839916, '2077-12-09T00:19:25.635Z'), +(14.144946993503583, 33.49542409970862, '2077-12-09T00:26:06.635Z'), +(15.068206134606472, 25.624398662893537, '2077-12-09T00:28:56.635Z'), +(13.844444834911977, 7.125409317171123, '2077-12-09T00:35:35.635Z'), +(23.36496528805936, 49.05078286949149, '2077-12-09T00:50:40.635Z'), +(22.961173349583326, 1.3183348851116001, '2077-12-09T01:06:51.635Z'), +(2.8686205740258273, 36.630135211778665, '2077-12-09T01:21:32.635Z'), +(13.141368138460075, 41.44939834120091, '2077-12-09T01:25:43.635Z'), +(22.80996741962322, 18.12134738639513, '2077-12-09T01:34:40.635Z'), +(6.999857066390229, 26.192897205380056, '2077-12-09T01:41:11.635Z'), +(15.089727800858375, 13.852772605215392, '2077-12-09T01:46:34.635Z'), +(13.561859767122119, 41.65547929918617, '2077-12-09T01:56:33.635Z'), +(19.713882926979768, 30.4741517502841, '2077-12-09T02:01:07.635Z'), +(1.4886210405345182, 15.625277040338002, '2077-12-09T02:09:45.635Z'), +(18.91104727870627, 9.745687132067902, '2077-12-09T02:16:33.635Z'), +(7.290450895329637, 35.076154348946034, '2077-12-09T02:26:38.635Z'), +(19.780548799508047, 7.290245075442818, '2077-12-09T02:37:38.635Z'), +(9.48870492736782, 18.358708660667624, '2077-12-09T02:43:08.635Z'), +(6.531798940607967, 0.03317278875483923, '2077-12-09T02:49:56.635Z'), +(21.35713587322383, 32.36692985170824, '2077-12-09T03:02:45.635Z'), +(2.7021353496606353, 14.724168612074893, '2077-12-09T03:12:08.635Z'), +(16.69751516756043, 47.19085190465025, '2077-12-09T03:25:02.635Z'), +(2.4813084657510713, 39.193289809375706, '2077-12-09T03:31:03.635Z'), +(6.502857140328336, 11.37860616096975, '2077-12-09T03:41:25.635Z'), +(19.489113241823684, 46.68645600849799, '2077-12-09T03:55:00.635Z'), +(16.93663026242951, 9.788904453555034, '2077-12-09T04:08:00.635Z'), +(10.68880840879262, 3.5684521055889182, '2077-12-09T04:11:13.635Z'), +(23.51735072729735, 8.318956897922059, '2077-12-09T04:16:15.635Z'), +(7.584951535070959, 35.94957530932251, '2077-12-09T04:27:42.635Z'), +(20.477214960959987, 7.190772832931787, '2077-12-09T04:39:03.635Z'), +(14.131513558320103, 41.240152774334796, '2077-12-09T04:51:18.635Z'), +(20.140519591046374, 3.0747617365567286, '2077-12-09T05:04:58.635Z'), +(20.79865302482346, 24.699387383353436, '2077-12-09T05:12:28.635Z'), +(21.999101498580714, 27.77040618004804, '2077-12-09T05:13:36.635Z'), +(8.145356068865846, 17.114236516848838, '2077-12-09T05:19:59.635Z'), +(0.3093529869390998, 43.69228630950994, '2077-12-09T05:30:13.635Z'), +(4.120535602585693, 43.34090185944869, '2077-12-09T05:31:38.635Z'), +(13.961224328322295, 1.5036412646926542, '2077-12-09T05:47:20.635Z'), +(22.212398213742134, 10.821707995095478, '2077-12-09T05:51:49.635Z'), +(13.11356359995703, 24.480370200521303, '2077-12-09T05:57:41.635Z'), +(0.4081807325775818, 46.01290750469125, '2077-12-09T06:06:53.635Z'), +(3.5748495231658555, 31.49448791015043, '2077-12-09T06:12:23.635Z'), +(21.03221428188258, 15.468826696290353, '2077-12-09T06:21:03.635Z'), +(14.544083671667787, 20.98715437817619, '2077-12-09T06:24:08.635Z'), +(2.5169567728232263, 2.0291735630042087, '2077-12-09T06:32:22.635Z'), +(3.617595898437095, 48.156947467427315, '2077-12-09T06:49:26.635Z'), +(3.011304599102135, 12.970927537831322, '2077-12-09T07:02:27.635Z'), +(11.259942847875084, 39.943034658914314, '2077-12-09T07:12:49.635Z'), +(10.58671760884231, 3.4908406156732465, '2077-12-09T07:26:04.635Z'), +(21.69155480531697, 47.402782947851044, '2077-12-09T07:42:10.635Z'), +(7.558317164538619, 8.02485269896194, '2077-12-09T07:57:10.635Z'), +(14.83351435478059, 34.098246157378924, '2077-12-09T08:07:00.635Z'), +(2.904382665119652, 6.769948601594173, '2077-12-09T08:17:55.635Z'), +(21.909843366870355, 39.84664719000552, '2077-12-09T08:31:44.635Z'), +(8.595191513628986, 22.066956605948114, '2077-12-09T08:39:45.635Z'), +(3.9361615919493205, 24.694566043484514, '2077-12-09T08:41:43.635Z'), +(0.5989988482037896, 31.444136320350765, '2077-12-09T08:44:30.635Z'), +(22.70206708518696, 1.1391715463132406, '2077-12-09T08:58:08.635Z'), +(7.011090903765326, 4.248070972999289, '2077-12-09T09:04:03.635Z'), +(15.28384100054661, 11.148442921306296, '2077-12-09T09:08:00.635Z'), +(7.307031701322672, 43.78106812064054, '2077-12-09T09:20:12.635Z'), +(9.262967103072247, 40.326591447967836, '2077-12-09T09:21:39.635Z'), +(19.44906247482156, 28.16792680103453, '2077-12-09T09:27:24.635Z'), +(9.806063977811837, 33.864952318217966, '2077-12-09T09:31:30.635Z'), +(12.252295634969544, 50.17665792084465, '2077-12-09T09:37:30.635Z'), +(20.259116574741697, 1.955149389444455, '2077-12-09T09:54:51.635Z'), +(18.780071065449242, 10.90667122995504, '2077-12-09T09:58:01.635Z'), +(22.633070667037515, 30.398831588623455, '2077-12-09T10:04:55.635Z'), +(21.12836334062519, 39.55633513223308, '2077-12-09T10:08:06.635Z'), +(16.327864356809147, 7.3709051049880925, '2077-12-09T10:19:31.635Z'), +(17.059257103054073, 10.964459161921578, '2077-12-09T10:20:49.635Z'), +(4.579868389523666, 0.16188901925374585, '2077-12-09T10:26:52.635Z'), +(13.464697746674304, 12.837970935732795, '2077-12-09T10:32:33.635Z'), +(22.330219871533917, 47.48967265376793, '2077-12-09T10:45:10.635Z'), +(3.9939819987959564, 49.569539084058285, '2077-12-09T10:52:00.635Z'), +(6.749376673098802, 16.960895333168047, '2077-12-09T11:04:04.635Z'), +(4.522889319893141, 48.63180797072099, '2077-12-09T11:15:46.635Z'), +(2.473277667550935, 28.438355189979582, '2077-12-09T11:23:16.635Z'), +(12.721483512449723, 32.9713887728951, '2077-12-09T11:27:24.635Z'), +(10.440432187964038, 5.363493266148887, '2077-12-09T11:37:27.635Z'), +(22.17693502038586, 13.270989769166434, '2077-12-09T11:42:37.635Z'), +(12.956842439809982, 10.369396289427069, '2077-12-09T11:46:11.635Z'), +(17.44052297447465, 16.00056175373349, '2077-12-09T11:48:47.635Z'), +(0.7901602137065646, 39.756401522571856, '2077-12-09T11:59:24.635Z'), +(1.8224530359195026, 7.291857733974862, '2077-12-09T12:11:26.635Z'), +(18.933542277260738, 48.510915239039115, '2077-12-09T12:27:40.635Z'), +(6.14658394401987, 16.25280194255799, '2077-12-09T12:40:13.635Z'), +(4.696585266371149, 39.4923342164766, '2077-12-09T12:48:48.635Z'), +(8.216270814514917, 13.09835411821199, '2077-12-09T12:58:36.635Z'), +(3.4477573404138533, 29.892621537069484, '2077-12-09T13:05:02.635Z'), +(7.271288703924681, 25.704246646266835, '2077-12-09T13:07:07.635Z'), +(1.3430045555196495, 41.37077010821221, '2077-12-09T13:13:18.635Z'), +(4.492620626967322, 3.854319129310539, '2077-12-09T13:27:14.635Z'), +(20.820965858026813, 42.98894938696607, '2077-12-09T13:42:33.635Z'), +(7.409859264338628, 48.19680139533693, '2077-12-09T13:47:51.635Z'), +(9.53479407004222, 33.61996127210733, '2077-12-09T13:53:15.635Z'), +(16.581031341775596, 24.782403962747832, '2077-12-09T13:57:22.635Z'), +(5.598138834184942, 46.1245205458871, '2077-12-09T14:06:07.635Z'), +(6.806626598470928, 30.423200923283304, '2077-12-09T14:11:55.635Z'), +(20.365556932889337, 41.62563966122947, '2077-12-09T14:18:21.635Z'), +(16.244747867906803, 15.637119429364219, '2077-12-09T14:27:36.635Z'), +(1.9520772782215965, 12.240821253315058, '2077-12-09T14:33:02.635Z'), +(19.27361526062817, 24.927971256908236, '2077-12-09T14:40:55.635Z'), +(6.752205702751025, 44.54445944621808, '2077-12-09T14:49:22.635Z'), +(15.87044762439523, 6.301372073459116, '2077-12-09T15:03:38.635Z'), +(4.949153267693071, 42.166990586507424, '2077-12-09T15:17:17.635Z'), +(8.368782078156636, 43.62939453851399, '2077-12-09T15:18:39.635Z'), +(12.310477279607785, 45.05433947649888, '2077-12-09T15:20:12.635Z'), +(9.295496151426189, 25.78637433958431, '2077-12-09T15:27:18.635Z'), +(19.792712779955526, 37.342839098137574, '2077-12-09T15:32:58.635Z'), +(10.12358079160808, 18.74590146395992, '2077-12-09T15:40:31.635Z'), +(0.6746209918018203, 22.4160105578683, '2077-12-09T15:44:16.635Z'), +(2.0864462179715177, 47.29459428992228, '2077-12-09T15:53:29.635Z'), +(18.02400392193048, 21.51991461491574, '2077-12-09T16:04:33.635Z'), +(4.333966100314641, 33.45915671235433, '2077-12-09T16:11:13.635Z'), +(11.073268051070626, 17.23407047200916, '2077-12-09T16:17:40.635Z'), +(0.861462130353747, 11.039187942267722, '2077-12-09T16:22:05.635Z'), +(4.974734583513059, 7.358229831462683, '2077-12-09T16:24:07.635Z'), +(7.256547692604852, 3.314004724859431, '2077-12-09T16:25:49.635Z'), +(22.341486575478864, 34.11064522027439, '2077-12-09T16:38:08.635Z'), +(2.126889382261937, 9.323654396625464, '2077-12-09T16:49:47.635Z'), +(5.9533654922266885, 10.613477013656189, '2077-12-09T16:51:16.635Z'), +(2.213256146484008, 49.99554781515613, '2077-12-09T17:05:53.635Z'), +(4.8737715003337945, 14.310199279187968, '2077-12-09T17:19:07.635Z'), +(3.9435995576998857, 45.2164551292891, '2077-12-09T17:30:32.635Z'), +(17.99809177050832, 20.698912048458023, '2077-12-09T17:40:50.635Z'), +(6.471615491645423, 17.76809268513024, '2077-12-09T17:45:14.635Z'), +(15.51753012417299, 11.05704325153358, '2077-12-09T17:49:22.635Z'), +(15.64408859233133, 25.23672548223569, '2077-12-09T17:54:25.635Z'), +(20.98301768555474, 3.7241665397598895, '2077-12-09T18:02:13.635Z'), +(12.954568183129169, 34.19196406485372, '2077-12-09T18:13:23.635Z'), +(17.194903863985637, 47.73689950444075, '2077-12-09T18:18:28.635Z'), +(18.849373724370057, 17.11474600169641, '2077-12-09T18:29:15.635Z'), +(15.052934968503925, 35.00559749675354, '2077-12-09T18:35:44.635Z'), +(4.853938276824646, 38.298883842118975, '2077-12-09T18:39:41.635Z'), +(8.46532938100027, 30.460765890584405, '2077-12-09T18:42:51.635Z'), +(8.62186770215613, 39.23554165836002, '2077-12-09T18:46:04.635Z'), +(13.834781473734118, 40.55241587258403, '2077-12-09T18:48:03.635Z'), +(20.346521750206783, 14.769868562422582, '2077-12-09T18:57:29.635Z'), +(8.026335929024249, 40.350813576880405, '2077-12-09T19:07:43.635Z'), +(12.928995011856395, 37.38490058015926, '2077-12-09T19:09:49.635Z'), +(22.777663514722157, 0.11200431575506209, '2077-12-09T19:23:25.635Z'), +(18.26409753861837, 16.02870489968743, '2077-12-09T19:29:11.635Z'), +(5.818710938701691, 49.85126090081853, '2077-12-09T19:42:14.635Z'), +(4.22728373835837, 14.383525989236391, '2077-12-09T19:55:20.635Z'), +(3.8607746966851373, 8.569795594121862, '2077-12-09T19:57:29.635Z'), +(6.027092697099257, 34.23082991525356, '2077-12-09T20:06:59.635Z'), +(14.428640871585207, 6.137063286582985, '2077-12-09T20:17:40.635Z'), +(4.294174746753775, 17.546685654915738, '2077-12-09T20:23:16.635Z'), +(2.525212533632163, 40.40067430594397, '2077-12-09T20:31:44.635Z'), +(5.43352838713531, 39.517991966859206, '2077-12-09T20:32:51.635Z'), +(0.29384936819715446, 6.5674291133520715, '2077-12-09T20:45:11.635Z'), +(20.35496284379686, 41.462428197728244, '2077-12-09T20:59:51.635Z'), +(16.675512384123344, 5.227866306016731, '2077-12-09T21:12:37.635Z'), +(17.544906440322773, 29.992989613915032, '2077-12-09T21:21:23.635Z'), +(3.508851494898506, 25.742256357636894, '2077-12-09T21:26:48.635Z'), +(4.470990859793225, 15.54935376108444, '2077-12-09T21:30:35.635Z'), +(22.006583851285914, 19.14933163343842, '2077-12-09T21:37:12.635Z'), +(7.8561199673644655, 8.667508608766449, '2077-12-09T21:43:38.635Z'), +(14.710501878541596, 22.84705528171486, '2077-12-09T21:49:22.635Z'), +(16.89743619232806, 10.263736676473986, '2077-12-09T21:53:55.635Z'), +(7.671534961449279, 16.648431384435106, '2077-12-09T21:58:02.635Z'), +(22.531265289361418, 6.492036140189639, '2077-12-09T22:04:37.635Z'), +(14.95715496801584, 6.513754520834707, '2077-12-09T22:07:25.635Z'), +(22.64160704439673, 23.52990165132926, '2077-12-09T22:14:01.635Z'), +(0.33126955306343653, 41.339602619516654, '2077-12-09T22:24:29.635Z'), +(7.0009375516052375, 22.43598192978902, '2077-12-09T22:31:53.635Z'), +(17.49264577254754, 15.917596596144984, '2077-12-09T22:36:25.635Z'), +(22.15261704822029, 2.2641076679786156, '2077-12-09T22:41:28.635Z'), +(7.8769843520654375, 21.933436178847693, '2077-12-09T22:50:15.635Z'), +(20.64931751329637, 0.49613562683268714, '2077-12-09T22:59:16.635Z'), +(7.013896486583231, 21.057878632847302, '2077-12-09T23:08:12.635Z'), +(0.721791838861154, 21.31214595122883, '2077-12-09T23:10:32.635Z'), +(11.787200952259823, 48.70638561491416, '2077-12-09T23:21:24.635Z'), +(7.979436655435312, 31.287128359714565, '2077-12-09T23:27:54.635Z'), +(1.171804318825393, 49.36344808909401, '2077-12-09T23:35:02.635Z'), +(20.96409715698711, 13.068976423404303, '2077-12-09T23:50:03.635Z'), +(5.491749150641382, 7.443169065834885, '2077-12-09T23:56:07.635Z'), +(14.474493769853067, 13.245523489636728, '2077-12-10T00:00:03.635Z'), +(13.922114652473653, 17.993346674542718, '2077-12-10T00:01:46.635Z'), +(14.142809474590537, 5.213304027186737, '2077-12-10T00:06:21.635Z'), +(19.867126257067646, 14.197224614361616, '2077-12-10T00:10:10.635Z'), +(10.292858747059274, 6.202204341617055, '2077-12-10T00:14:43.635Z'), +(19.8964261841926, 33.13993091272322, '2077-12-10T00:24:58.635Z'), +(14.845447865050005, 23.73949132055319, '2077-12-10T00:28:46.635Z'), +(15.593248448707982, 8.27443072634593, '2077-12-10T00:34:18.635Z'), +(18.306621057413626, 45.25966325202036, '2077-12-10T00:47:25.635Z'), +(21.49451740818618, 39.17207981097138, '2077-12-10T00:49:50.635Z'), +(3.983710678522735, 28.588302069252506, '2077-12-10T00:57:21.635Z'), +(13.164901257974277, 23.00156072849624, '2077-12-10T01:01:19.635Z'), +(11.94596821885999, 5.977609271337905, '2077-12-10T01:07:29.635Z'), +(8.567999729905425, 24.389163937639378, '2077-12-10T01:14:18.635Z'), +(20.18824882886593, 35.64284799327387, '2077-12-10T01:20:11.635Z'), +(4.888487097634186, 39.32177162567269, '2077-12-10T01:26:00.635Z'), +(7.569543991321604, 3.19865382443065, '2077-12-10T01:39:20.635Z'), +(0.44425489695706105, 40.76618474219105, '2077-12-10T01:53:27.635Z'), +(22.079254435473185, 28.936835172250394, '2077-12-10T02:02:32.635Z'), +(18.720620968453915, 9.572046573501817, '2077-12-10T02:09:22.635Z'), +(2.0015503009133213, 15.741586459994, '2077-12-10T02:15:57.635Z'), +(22.393352564607362, 36.577845290539, '2077-12-10T02:26:35.635Z'), +(19.867949977448088, 42.99054293892435, '2077-12-10T02:28:59.635Z'), +(16.323121012997973, 26.172327896133016, '2077-12-10T02:35:02.635Z'), +(3.5998325515104637, 47.28413892877538, '2077-12-10T02:44:03.635Z'), +(17.642766438784466, 48.29446898981786, '2077-12-10T02:49:16.635Z'), +(13.533960502507675, 35.59106390895232, '2077-12-10T02:54:02.635Z'), +(7.673191004684243, 12.040672814247937, '2077-12-10T03:02:52.635Z'), +(21.353234579830918, 35.9519704513698, '2077-12-10T03:12:48.635Z'), +(17.495014458531198, 49.49936223421499, '2077-12-10T03:17:44.635Z'), +(10.073178572382902, 6.044542058680643, '2077-12-10T03:33:34.635Z'), +(20.393666868532367, 7.230803110176726, '2077-12-10T03:37:24.635Z'), +(3.2816601742744838, 8.383998077864803, '2077-12-10T03:43:45.635Z'), +(3.2037737737094445, 7.274275932934699, '2077-12-10T03:44:09.635Z'), +(14.650759884916498, 6.57248978776321, '2077-12-10T03:48:24.635Z'), +(7.417165834248667, 14.83103001624099, '2077-12-10T03:52:25.635Z'), +(22.90132521914848, 15.51198555928474, '2077-12-10T03:58:09.635Z'), +(5.6378424209738585, 5.512391187709873, '2077-12-10T04:05:28.635Z'), +(9.51920233437987, 7.250453179168297, '2077-12-10T04:07:02.635Z'), +(15.78811964192214, 1.2939139047282786, '2077-12-10T04:10:12.635Z'), +(15.560636941554293, 17.949091703165205, '2077-12-10T04:16:08.635Z'), +(16.373988527399774, 7.08489431128729, '2077-12-10T04:20:00.635Z'), +(6.008394829002159, 49.24408990541567, '2077-12-10T04:35:46.635Z'), +(23.15429703169172, 34.43653752709513, '2077-12-10T04:44:01.635Z'), +(22.23132029938552, 49.76608661552145, '2077-12-10T04:49:16.635Z'), +(4.08943962451501, 7.029595982770587, '2077-12-10T05:06:00.635Z'), +(2.310384003810032, 28.317250165374585, '2077-12-10T05:13:54.635Z'), +(6.337225038791293, 4.778171549627726, '2077-12-10T05:22:43.635Z'), +(22.072563178426297, 20.29293422764038, '2077-12-10T05:30:46.635Z'), +(18.384579935618824, 17.131054054955854, '2077-12-10T05:32:31.635Z'), +(16.09832161948772, 8.331763298984114, '2077-12-10T05:35:44.635Z'), +(1.3901430002321904, 36.96015384498129, '2077-12-10T05:47:31.635Z'), +(6.493337043131392, 16.699130557568342, '2077-12-10T05:55:14.635Z'), +(3.7678529251255997, 31.83151242633845, '2077-12-10T06:00:54.635Z'), +(3.189195886053058, 41.72691703772844, '2077-12-10T06:04:34.635Z'), +(2.5140105583924073, 32.561134783362604, '2077-12-10T06:07:58.635Z'), +(18.368141833011986, 36.90784454920152, '2077-12-10T06:14:03.635Z'), +(17.015158585256465, 19.267867079434158, '2077-12-10T06:20:17.635Z'), +(18.572132805401342, 34.165006508021314, '2077-12-10T06:25:34.635Z'), +(4.2665728270574546, 46.920244030002216, '2077-12-10T06:32:35.635Z'), +(19.010053571986116, 37.86431340049558, '2077-12-10T06:38:57.635Z'), +(2.1585021380384655, 34.837726399556935, '2077-12-10T06:45:17.635Z'), +(8.763254984913983, 22.346835346953384, '2077-12-10T06:50:29.635Z'), +(7.163991300837248, 31.18133316873048, '2077-12-10T06:53:46.635Z'), +(14.103388253891143, 6.746296178006307, '2077-12-10T07:03:01.635Z'), +(0.6744269937246158, 16.793470871330243, '2077-12-10T07:09:12.635Z'), +(17.703069719592204, 41.88081206248541, '2077-12-10T07:20:18.635Z'), +(16.787540395459985, 19.6426869877984, '2077-12-10T07:28:10.635Z'), +(21.609914453254838, 19.120197705386886, '2077-12-10T07:29:57.635Z'), +(2.6650545474594005, 5.34350496184504, '2077-12-10T07:38:33.635Z'), +(9.835175408630853, 44.15868985515006, '2077-12-10T07:53:04.635Z'), +(14.627643927275544, 19.37383702564948, '2077-12-10T08:02:12.635Z'), +(6.592765470348024, 24.297265421834336, '2077-12-10T08:05:40.635Z'), +(14.576195270713793, 34.559435560079805, '2077-12-10T08:10:25.635Z'), +(6.7924288381065425, 32.0667238741566, '2077-12-10T08:13:26.635Z'), +(0.25104384759319365, 9.961020097498634, '2077-12-10T08:21:57.635Z'), +(4.336585413712197, 44.807262015770924, '2077-12-10T08:34:56.635Z'), +(17.330197863377894, 21.88440202543181, '2077-12-10T08:44:32.635Z'), +(21.14033816259667, 28.67090347860619, '2077-12-10T08:47:17.635Z'), +(7.536463291758461, 1.4055698657772189, '2077-12-10T08:58:16.635Z'), +(20.35116719655002, 10.531908982038749, '2077-12-10T09:04:02.635Z'), +(20.08129627389593, 4.948158948010329, '2077-12-10T09:05:58.635Z'), +(11.971413243686122, 49.847332657477665, '2077-12-10T09:22:11.635Z'), +(12.825925702530855, 31.964008190913916, '2077-12-10T09:28:39.635Z'), +(19.235508553942502, 40.854644680947516, '2077-12-10T09:32:36.635Z'), +(7.593163144289074, 14.633930984718873, '2077-12-10T09:42:58.635Z'), +(16.48110294684183, 42.0115912699685, '2077-12-10T09:53:24.635Z'), +(11.173854585991455, 44.00182311777519, '2077-12-10T09:55:29.635Z'), +(17.624167208338726, 31.501961057986172, '2077-12-10T10:00:33.635Z'), +(18.220746289344262, 34.69026053062841, '2077-12-10T10:01:41.635Z'), +(23.269005836903872, 41.83608884465447, '2077-12-10T10:04:47.635Z'), +(19.04093618565996, 13.009494492323014, '2077-12-10T10:14:51.635Z'), +(4.003358406227158, 19.566114503338042, '2077-12-10T10:20:54.635Z'), +(4.396675579543778, 7.112544502618, '2077-12-10T10:25:30.635Z'), +(7.560089562264376, 19.9099417467303, '2077-12-10T10:30:21.635Z'), +(20.017465127179072, 35.00347783575372, '2077-12-10T10:37:28.635Z'), +(9.978554650473267, 36.09348281628706, '2077-12-10T10:41:12.635Z'), +(6.743015133829992, 29.53914135160787, '2077-12-10T10:43:53.635Z'), +(13.382489941844382, 48.164830823879825, '2077-12-10T10:51:06.635Z'), +(21.315885902115276, 21.462953917071424, '2077-12-10T11:00:58.635Z'), +(1.4253539885184472, 32.316506331707664, '2077-12-10T11:09:19.635Z'), +(23.049217344084227, 36.39141118335132, '2077-12-10T11:17:27.635Z'), +(20.91348543627646, 1.6155839686917728, '2077-12-10T11:29:24.635Z'), +(15.834380652412015, 6.081455364334818, '2077-12-10T11:31:51.635Z'), +(6.850171656002832, 10.149240295645791, '2077-12-10T11:35:29.635Z'), +(2.5584743215594297, 8.032380679292663, '2077-12-10T11:37:15.635Z'), +(4.647415243419276, 14.030834083768841, '2077-12-10T11:39:36.635Z'), +(22.391709019057632, 22.31783341889153, '2077-12-10T11:46:49.635Z'), +(3.3302506790578192, 42.78666411199682, '2077-12-10T11:57:00.635Z'), +(9.231071969131815, 31.611415388952036, '2077-12-10T12:01:39.635Z'), +(20.376291421129892, 26.477232768500407, '2077-12-10T12:06:10.635Z'), +(16.079778636898297, 47.07608715372458, '2077-12-10T12:13:35.635Z'), +(4.59962019929372, 9.29858441287198, '2077-12-10T12:27:58.635Z'), +(13.301286436005384, 33.76828103599393, '2077-12-10T12:37:28.635Z'), +(8.77172119187454, 9.068475698071712, '2077-12-10T12:46:36.635Z'), +(21.435857075147094, 32.19114926477059, '2077-12-10T12:56:05.635Z'), +(22.581203904976068, 43.59243576373549, '2077-12-10T13:00:01.635Z'), +(19.09177975002781, 40.9657772652925, '2077-12-10T13:01:35.635Z'), +(15.688925978191465, 35.98117050176667, '2077-12-10T13:03:45.635Z'), +(12.437055626213265, 42.29785512176199, '2077-12-10T13:06:19.635Z'), +(8.54197632649355, 21.736583728840483, '2077-12-10T13:13:56.635Z'), +(5.525767836236789, 49.71790487314714, '2077-12-10T13:24:17.635Z'), +(2.0552190150604113, 8.947306260799287, '2077-12-10T13:39:24.635Z'), +(10.496422137782853, 47.98517132674816, '2077-12-10T13:54:06.635Z'), +(2.997460314359776, 27.210946842890603, '2077-12-10T14:02:13.635Z'), +(17.441402249176818, 31.126772275849145, '2077-12-10T14:07:45.635Z'), +(7.210386195828389, 28.352143460722324, '2077-12-10T14:11:40.635Z'), +(21.103489762578413, 35.30673646651385, '2077-12-10T14:17:23.635Z'), +(8.216766318097065, 21.9052694746403, '2077-12-10T14:24:08.635Z'), +(14.778973959942133, 28.37279962585127, '2077-12-10T14:27:30.635Z'), +(4.599149950269335, 18.13012394322271, '2077-12-10T14:32:48.635Z'), +(14.374925531004871, 42.242839120478266, '2077-12-10T14:42:19.635Z'), +(3.363270435602762, 19.7018662973001, '2077-12-10T14:51:30.635Z'), +(5.160668833807077, 43.74564097269492, '2077-12-10T15:00:24.635Z'), +(0.694958061092447, 23.02416803402564, '2077-12-10T15:08:14.635Z'), +(10.708255050400313, 1.5710908194239206, '2077-12-10T15:16:57.635Z'), +(10.407788477877142, 21.551706325719532, '2077-12-10T15:24:13.635Z'), +(21.737178363300824, 10.76926504714932, '2077-12-10T15:29:54.635Z'), +(14.931852569175788, 42.781939843155115, '2077-12-10T15:41:25.635Z'), +(7.022803967273149, 37.523272562722404, '2077-12-10T15:44:54.635Z'), +(17.0081245804384, 15.180834441758787, '2077-12-10T15:53:47.635Z'), +(20.490299929294707, 20.251031637009753, '2077-12-10T15:55:58.635Z'), +(2.4951951248767807, 35.86957595632742, '2077-12-10T16:04:42.635Z'), +(0.8463056515390444, 17.532814301879466, '2077-12-10T16:11:31.635Z'), +(9.635154034508146, 47.609899626666504, '2077-12-10T16:23:04.635Z'), +(1.6642959955978351, 48.40302315255831, '2077-12-10T16:26:02.635Z'), +(20.534206491229646, 35.39691845154179, '2077-12-10T16:34:27.635Z'), +(19.01431021611037, 34.86143270005314, '2077-12-10T16:35:02.635Z'), +(1.576224547726048, 30.99950663240329, '2077-12-10T16:41:38.635Z'), +(1.9458048556822134, 45.860307056536875, '2077-12-10T16:47:08.635Z'), +(1.1781082442985704, 1.9237147038063143, '2077-12-10T17:03:24.635Z'), +(19.624820967070328, 38.27465092677488, '2077-12-10T17:18:14.635Z'), +(22.162570019461228, 0.46084158732750896, '2077-12-10T17:31:19.635Z'), +(20.854189305697872, 36.116814254015615, '2077-12-10T17:43:35.635Z'), +(8.978995742093138, 36.13181753117187, '2077-12-10T17:47:59.635Z'), +(6.759487541471137, 12.43639589048567, '2077-12-10T17:56:43.635Z'), +(7.240372728636313, 3.8570642307723713, '2077-12-10T17:59:52.635Z'), +(7.9318929271021235, 37.552322263027925, '2077-12-10T18:12:14.635Z'), +(10.704116860843069, 25.546360209109338, '2077-12-10T18:16:44.635Z'), +(11.896610335957142, 25.36322306587554, '2077-12-10T18:17:10.635Z'), +(19.433178160302663, 9.981482320749286, '2077-12-10T18:23:19.635Z'), +(10.911055113419824, 48.061012017423494, '2077-12-10T18:37:16.635Z'), +(23.432110282948887, 24.296659762183534, '2077-12-10T18:46:51.635Z'), +(20.814934866656678, 6.14672097479675, '2077-12-10T18:53:09.635Z'), +(14.248864119944987, 24.20291551457502, '2077-12-10T18:59:58.635Z'), +(21.490299625556986, 19.172298627278575, '2077-12-10T19:03:11.635Z'), +(16.986649963519834, 36.22479641469233, '2077-12-10T19:09:22.635Z'), +(16.691290882500944, 22.643241741081216, '2077-12-10T19:14:11.635Z'), +(12.14127004201588, 37.49062797568687, '2077-12-10T19:19:46.635Z'), +(15.664715769567952, 42.280265378549025, '2077-12-10T19:21:55.635Z'), +(20.526773334821197, 31.47404385339007, '2077-12-10T19:26:07.635Z'), +(10.392125223435759, 5.629400771553089, '2077-12-10T19:36:03.635Z'), +(5.353333610234107, 46.373040647384045, '2077-12-10T19:51:06.635Z'), +(23.013399229793226, 31.498762187031154, '2077-12-10T19:59:32.635Z'), +(2.3433704081203275, 16.73809568741277, '2077-12-10T20:08:51.635Z'), +(18.335576651399187, 48.41469691475116, '2077-12-10T20:21:47.635Z'), +(5.503810390292008, 9.471209334336566, '2077-12-10T20:36:38.635Z'), +(10.619946404779208, 16.965481266605394, '2077-12-10T20:39:58.635Z'), +(5.287985955241034, 4.269849289963908, '2077-12-10T20:45:01.635Z'), +(17.56025388732645, 9.475989817958641, '2077-12-10T20:49:56.635Z'), +(18.53317010302215, 25.80407406930721, '2077-12-10T20:55:41.635Z'), +(15.02377832894495, 12.568413996364955, '2077-12-10T21:00:33.635Z'), +(2.81468374101375, 15.690961910377, '2077-12-10T21:05:13.635Z'), +(9.430965299136394, 9.197690180054977, '2077-12-10T21:08:38.635Z'), +(16.843010689697298, 23.49366347135751, '2077-12-10T21:14:28.635Z'), +(22.97823321723063, 25.593962562909578, '2077-12-10T21:16:51.635Z'), +(6.9389231137839875, 34.7918072230398, '2077-12-10T21:23:38.635Z'), +(18.36069563933631, 48.15115193082125, '2077-12-10T21:30:02.635Z'), +(21.605012382017016, 14.642071270811012, '2077-12-10T21:41:44.635Z'), +(21.818139246193, 48.403228571288395, '2077-12-10T21:53:20.635Z'), +(5.522549487179169, 18.48856094234913, '2077-12-10T22:05:38.635Z'), +(20.598793820269005, 21.034671412337417, '2077-12-10T22:11:17.635Z'), +(7.972167400858329, 34.17978424463642, '2077-12-10T22:17:55.635Z'), +(12.78375357857103, 9.982002647167446, '2077-12-10T22:26:54.635Z'), +(21.694784070334016, 2.4235610935921192, '2077-12-10T22:31:08.635Z'), +(6.9556775944430305, 2.8114861824364765, '2077-12-10T22:36:35.635Z'), +(15.938569173857651, 33.53286773030318, '2077-12-10T22:48:12.635Z'), +(2.344800319271054, 40.7860518073769, '2077-12-10T22:53:53.635Z'), +(5.383920594605774, 48.63852576859588, '2077-12-10T22:56:59.635Z'), +(12.673027984768211, 6.633526814919307, '2077-12-10T23:12:34.635Z'), +(10.8921879126774, 38.458146139504244, '2077-12-10T23:24:07.635Z'), +(18.300519803716348, 3.285491617432122, '2077-12-10T23:37:00.635Z'), +(7.548954046533999, 2.9537578846965094, '2077-12-10T23:40:59.635Z'), +(22.52777714550758, 48.154812547533716, '2077-12-10T23:58:00.635Z'), +(22.378001576050586, 28.09355626535615, '2077-12-11T00:04:52.635Z'), +(3.665551077745902, 24.3692800941904, '2077-12-11T00:11:55.635Z'), +(16.639756975216695, 15.440648824510836, '2077-12-11T00:17:43.635Z'), +(6.161096520496801, 35.299073031732085, '2077-12-11T00:25:53.635Z'), +(10.352390803857027, 24.95663903243391, '2077-12-11T00:29:58.635Z'), +(1.3121025273048073, 49.79357666010827, '2077-12-11T00:39:42.635Z'), +(1.0759746523321536, 49.12065805463495, '2077-12-11T00:39:57.635Z'), +(6.369919365483789, 10.370059709202296, '2077-12-11T00:54:24.635Z'), +(4.503591840103195, 29.23935655003245, '2077-12-11T01:01:23.635Z'), +(5.275250498571965, 48.97653377564407, '2077-12-11T01:08:40.635Z'), +(20.80368297541063, 34.06666633069572, '2077-12-11T01:16:32.635Z'), +(19.33888542354278, 34.44731009478536, '2077-12-11T01:17:05.635Z'), +(8.871516202799075, 42.940255193220935, '2077-12-11T01:22:01.635Z'), +(10.770756376874282, 47.76969775338383, '2077-12-11T01:23:54.635Z'), +(20.368304556348342, 45.92734653404469, '2077-12-11T01:27:31.635Z'), +(20.990188037904957, 11.064901059785242, '2077-12-11T01:39:35.635Z'), +(11.055988747490453, 31.589282302457942, '2077-12-11T01:47:45.635Z'), +(2.911866665772132, 37.63871871764319, '2077-12-11T01:51:29.635Z'), +(9.70637536598949, 21.97415012140654, '2077-12-11T01:57:46.635Z'), +(5.7701869866398035, 13.080268628786127, '2077-12-11T02:01:20.635Z'), +(14.528351963927722, 43.81079076408704, '2077-12-11T02:12:59.635Z'), +(11.454498566753413, 25.6528228744619, '2077-12-11T02:19:38.635Z'), +(4.86757851498054, 6.917309172461275, '2077-12-11T02:26:55.635Z'), +(16.41111048239124, 14.08465984733179, '2077-12-11T02:31:55.635Z'), +(3.550291468346167, 14.759479761833001, '2077-12-11T02:36:41.635Z'), +(16.672100298873108, 0.11671933446868844, '2077-12-11T02:43:53.635Z'), +(9.069150105203965, 14.90973268046584, '2077-12-11T02:49:55.635Z'), +(1.0908464928032466, 33.36459905665563, '2077-12-11T02:57:20.635Z'), +(2.7838575039281883, 36.925380645317155, '2077-12-11T02:58:47.635Z'), +(6.167023112464555, 4.034768953036937, '2077-12-11T03:10:59.635Z'), +(9.688966319023187, 39.44457256994325, '2077-12-11T03:24:02.635Z'), +(16.84140725300684, 11.170302940957956, '2077-12-11T03:34:33.635Z'), +(10.666769552350942, 22.89005521404397, '2077-12-11T03:39:20.635Z'), +(6.50067670277829, 1.8729661361412213, '2077-12-11T03:47:11.635Z'), +(7.64928909747456, 24.58191535796428, '2077-12-11T03:55:32.635Z'), +(2.9580234992314423, 26.7142233373364, '2077-12-11T03:57:26.635Z'), +(12.54996179871607, 33.41448975852264, '2077-12-11T04:01:45.635Z'), +(20.76289864130648, 12.534330400728738, '2077-12-11T04:09:45.635Z'), +(2.600567427913894, 28.26666180989493, '2077-12-11T04:18:33.635Z'), +(0.15255194040150616, 34.26150914272967, '2077-12-11T04:20:56.635Z'), +(16.336884084557145, 5.446437723023937, '2077-12-11T04:33:03.635Z'), +(7.133938236761247, 4.589941057782882, '2077-12-11T04:36:28.635Z'), +(19.098275073070027, 24.99428277888872, '2077-12-11T04:45:02.635Z'), +(0.3055716738446714, 40.83016642308925, '2077-12-11T04:54:04.635Z'), +(7.48238022980583, 15.05793168872976, '2077-12-11T05:03:57.635Z'), +(4.367932088610215, 40.94117883963666, '2077-12-11T05:13:33.635Z'), +(0.32254185945681574, 28.325295087973686, '2077-12-11T05:18:27.635Z'), +(2.06052071618363, 26.64596892549188, '2077-12-11T05:19:20.635Z'), +(16.45502667399815, 30.913802913205046, '2077-12-11T05:24:53.635Z'), +(8.74106577881874, 8.350522928092456, '2077-12-11T05:33:31.635Z'), +(21.50217870539255, 37.75644032878694, '2077-12-11T05:45:01.635Z'), +(21.314094870027784, 7.14304520430122, '2077-12-11T05:55:33.635Z'), +(18.668820580806948, 2.7151317992979185, '2077-12-11T05:57:22.635Z'), +(21.12951090053989, 30.634323304224797, '2077-12-11T06:07:07.635Z'), +(6.485114313214725, 3.8440506061163493, '2077-12-11T06:18:09.635Z'), +(8.838384919736406, 11.847959585929226, '2077-12-11T06:21:12.635Z'), +(14.756377311090565, 1.644876379934211, '2077-12-11T06:25:30.635Z'), +(0.4332857391980337, 22.058042613793308, '2077-12-11T06:34:40.635Z'), +(11.105592055765909, 15.538337669759969, '2077-12-11T06:39:17.635Z'), +(17.988938376441293, 17.21630954505204, '2077-12-11T06:41:54.635Z'), +(22.41360148905442, 19.888882326880612, '2077-12-11T06:43:47.635Z'), +(4.770775092693177, 47.546312413525875, '2077-12-11T06:55:39.635Z'), +(12.933525852185872, 42.60295622130568, '2077-12-11T06:59:10.635Z'), +(18.18081884898745, 14.943477334428804, '2077-12-11T07:09:13.635Z'), +(20.872965618152325, 17.07668522103595, '2077-12-11T07:10:27.635Z'), +(11.239242835097084, 22.3954058457684, '2077-12-11T07:14:29.635Z'), +(9.498309799629556, 12.808107077565996, '2077-12-11T07:18:02.635Z'), +(17.12728471298211, 7.110206895328559, '2077-12-11T07:21:31.635Z'), +(18.265448885636093, 10.160368646545624, '2077-12-11T07:22:40.635Z'), +(17.042622285547004, 29.087618574775725, '2077-12-11T07:29:21.635Z'), +(1.317141495213289, 31.012581355194424, '2077-12-11T07:35:13.635Z'), +(18.7226954589285, 28.549327355700175, '2077-12-11T07:41:43.635Z'), +(17.017436664713138, 41.356179374875374, '2077-12-11T07:46:16.635Z'), +(18.57742295232499, 47.098957992460925, '2077-12-11T07:48:22.635Z'), +(22.242976425937208, 22.439933584789742, '2077-12-11T07:57:01.635Z'), +(17.06769419860823, 20.99634133026651, '2077-12-11T07:58:59.635Z'), +(15.661827755457926, 37.381917109610704, '2077-12-11T08:04:49.635Z'), +(0.17784175523180323, 25.394978798828994, '2077-12-11T08:12:02.635Z'), +(4.694424250795693, 15.41411529625348, '2077-12-11T08:16:05.635Z'), +(17.430374840675036, 36.227196282747556, '2077-12-11T08:24:59.635Z'), +(7.404199786070815, 35.40938699969281, '2077-12-11T08:28:42.635Z'), +(21.733218536603882, 12.908028193352484, '2077-12-11T08:38:20.635Z'), +(11.06328876344872, 3.3624008122565843, '2077-12-11T08:43:32.635Z'), +(15.891505562967648, 29.776875339164047, '2077-12-11T08:53:12.635Z'), +(3.3922287396793216, 8.36920814202227, '2077-12-11T09:02:16.635Z'), +(5.33309751984642, 29.914636457552994, '2077-12-11T09:10:15.635Z'), +(7.123085973764158, 32.42733674222263, '2077-12-11T09:11:23.635Z'), +(13.584536203826877, 33.086421158793904, '2077-12-11T09:13:47.635Z'), +(10.807446136980762, 35.94798272314141, '2077-12-11T09:15:14.635Z'), +(7.87900344693154, 15.679285431603581, '2077-12-11T09:22:43.635Z'), +(4.588924413681745, 37.0474031487986, '2077-12-11T09:30:40.635Z'), +(16.789322708378343, 18.704739331316407, '2077-12-11T09:38:43.635Z'), +(10.639519712589566, 21.692298574667234, '2077-12-11T09:41:14.635Z'), +(13.287687329950474, 22.988791366058955, '2077-12-11T09:42:19.635Z'), +(9.577874152699607, 48.743212584413946, '2077-12-11T09:51:46.635Z'), +(1.5560312760205706, 9.439523168081527, '2077-12-11T10:06:33.635Z'), +(5.133989149131366, 26.19404297086212, '2077-12-11T10:12:53.635Z'), +(9.283340133118495, 10.494318116464044, '2077-12-11T10:18:51.635Z'), +(9.72839015632746, 10.909254495169822, '2077-12-11T10:19:04.635Z'), +(14.574072323205876, 7.356725856145206, '2077-12-11T10:21:16.635Z'), +(13.999709429348849, 9.402807473822484, '2077-12-11T10:22:01.635Z'), +(14.334061462280994, 39.86818157089925, '2077-12-11T10:32:57.635Z'), +(16.270646087171198, 10.577530806206674, '2077-12-11T10:43:26.635Z'), +(8.560006771053871, 39.888195720733364, '2077-12-11T10:54:24.635Z'), +(11.66690983467625, 40.63682500534386, '2077-12-11T10:55:35.635Z'), +(20.191193448328633, 49.39114017290838, '2077-12-11T11:00:01.635Z'), +(14.78320342821305, 24.616715109037987, '2077-12-11T11:08:59.635Z'), +(2.645532634205439, 49.49672570381878, '2077-12-11T11:19:07.635Z'), +(5.369433721633435, 27.574125766706914, '2077-12-11T11:27:17.635Z'), +(7.75281519284116, 24.332306854106907, '2077-12-11T11:28:46.635Z'), +(3.7148040823793513, 48.289007617219475, '2077-12-11T11:37:43.635Z'), +(8.219413275169615, 38.2204038061898, '2077-12-11T11:41:47.635Z'), +(22.00664417438897, 3.058818095371853, '2077-12-11T11:55:18.635Z'), +(16.40084143708334, 42.78407072967821, '2077-12-11T12:09:19.635Z'), +(10.783173939207932, 8.267328804381808, '2077-12-11T12:21:54.635Z'), +(5.567332809618269, 25.15798247924984, '2077-12-11T12:28:23.635Z'), +(11.898776598534104, 50.29275419580966, '2077-12-11T12:37:52.635Z'), +(6.189110666019214, 27.538858159139924, '2077-12-11T12:46:27.635Z'), +(21.452083731574977, 45.57524853809828, '2077-12-11T12:55:02.635Z'), +(3.129133206450344, 2.42757548871684, '2077-12-11T13:11:59.635Z'), +(17.888408293983897, 21.8994611606687, '2077-12-11T13:20:55.635Z'), +(0.9083076683828285, 45.84900825858473, '2077-12-11T13:31:40.635Z'), +(17.207294555701992, 10.183877878035247, '2077-12-11T13:46:00.635Z'), +(3.2720852272679455, 50.04728903197897, '2077-12-11T14:01:23.635Z'), +(21.80585144537768, 5.826397038931392, '2077-12-11T14:18:42.635Z'), +(17.248611267946497, 17.288027939196954, '2077-12-11T14:23:02.635Z'), +(8.236383203222475, 49.76028552786016, '2077-12-11T14:35:13.635Z'), +(1.4611412132290256, 11.446201767231166, '2077-12-11T14:49:34.635Z'), +(6.921996712422717, 27.559140319706074, '2077-12-11T14:55:51.635Z'), +(2.4503962519680487, 41.97695406559787, '2077-12-11T15:01:25.635Z'), +(12.263159267146953, 24.5620401795853, '2077-12-11T15:08:46.635Z'), +(17.080779390186017, 32.908748250442066, '2077-12-11T15:12:15.635Z'), +(4.112478523371884, 22.399256163003674, '2077-12-11T15:18:23.635Z'), +(11.041773235036539, 0.8809342138248244, '2077-12-11T15:26:41.635Z'), +(3.0912597580251413, 45.450786728942425, '2077-12-11T15:43:19.635Z'), +(5.865823745605008, 20.855084289693952, '2077-12-11T15:52:27.635Z'), +(3.490186965646215, 38.05478307486817, '2077-12-11T15:58:51.635Z'), +(17.43619389626553, 41.12624214999673, '2077-12-11T16:04:08.635Z'), +(16.508908360171166, 34.39855792335159, '2077-12-11T16:06:32.635Z'), +(10.975685456948788, 37.46951105107885, '2077-12-11T16:08:51.635Z'), +(3.119594546172618, 6.480947756634105, '2077-12-11T16:20:36.635Z'), +(18.738888120801064, 20.786707827295157, '2077-12-11T16:28:22.635Z'), +(18.055317381596385, 9.71170296519439, '2077-12-11T16:32:16.635Z'), +(14.526415527716045, 35.665873994751884, '2077-12-11T16:41:35.635Z'), +(4.971870096301328, 47.30457910570493, '2077-12-11T16:47:06.635Z'), +(19.854523456080265, 49.6702400282815, '2077-12-11T16:52:40.635Z'), +(9.580288718730399, 8.27020459082094, '2077-12-11T17:07:56.635Z'), +(11.361161265638255, 39.50080725031011, '2077-12-11T17:19:19.635Z'), +(6.747465052370332, 10.63966155009726, '2077-12-11T17:30:00.635Z'), +(9.92059712019716, 20.014443947171618, '2077-12-11T17:33:37.635Z'), +(13.283387590870209, 25.93528574672832, '2077-12-11T17:36:06.635Z'), +(8.52604683853328, 50.26824086502067, '2077-12-11T17:45:07.635Z'), +(15.698358083026793, 32.287486523730045, '2077-12-11T17:52:08.635Z'), +(4.552682833214557, 46.21898123341183, '2077-12-11T17:58:40.635Z'), +(5.663642967778738, 11.218236852286118, '2077-12-11T18:11:35.635Z'), +(2.4876610922102187, 37.35204289393169, '2077-12-11T18:21:18.635Z'), +(14.647245350093039, 26.664311798256026, '2077-12-11T18:27:15.635Z'), +(16.180541052970945, 42.15261357100473, '2077-12-11T18:32:48.635Z'), +(5.390111634297407, 0.48107541164056705, '2077-12-11T18:48:27.635Z'), +(7.1635140403299795, 34.75291789862448, '2077-12-11T19:01:05.635Z'), +(10.70953718983706, 21.660009653497298, '2077-12-11T19:06:03.635Z'), +(7.877455152403299, 38.30067638111005, '2077-12-11T19:12:13.635Z'), +(20.949715524517323, 11.327816004114185, '2077-12-11T19:23:00.635Z'), +(16.12571421239757, 11.466130419205966, '2077-12-11T19:24:47.635Z'), +(4.539551056196494, 49.51244434336837, '2077-12-11T19:39:16.635Z'), +(7.516400151732869, 29.488443970640237, '2077-12-11T19:46:43.635Z'), +(7.727427701838155, 6.639350978585222, '2077-12-11T19:55:06.635Z'), +(23.031436886590253, 29.241503367035573, '2077-12-11T20:04:56.635Z'), +(9.241200911607178, 2.1074655225456893, '2077-12-11T20:15:49.635Z'), +(16.857966363048913, 4.119362762018409, '2077-12-11T20:18:43.635Z'), +(17.006396791056748, 33.27713518684801, '2077-12-11T20:29:02.635Z'), +(21.21899992065166, 35.84337069578788, '2077-12-11T20:30:50.635Z'), +(14.089211984553483, 11.355540555701197, '2077-12-11T20:39:51.635Z'), +(8.03874760371289, 12.519795087252675, '2077-12-11T20:42:07.635Z'), +(6.66259607307156, 9.558129478339914, '2077-12-11T20:43:19.635Z'), +(10.26426511771151, 11.529319234628817, '2077-12-11T20:44:50.635Z'), +(13.704373092218454, 49.47341023512151, '2077-12-11T20:58:38.635Z'), +(13.650041918355479, 37.44736387347339, '2077-12-11T21:02:57.635Z'), +(21.370760461961456, 13.080736737507092, '2077-12-11T21:12:00.635Z'), +(13.30045979467185, 4.218536579642763, '2077-12-11T21:16:19.635Z'), +(5.4726877799832785, 33.46000650774634, '2077-12-11T21:27:23.635Z'), +(10.787130577676786, 23.300873859700435, '2077-12-11T21:31:35.635Z'), +(3.1891831401828457, 10.927113263939873, '2077-12-11T21:36:55.635Z'), +(9.31763447170355, 6.672917817002853, '2077-12-11T21:39:40.635Z'), +(0.369038496733854, 20.54609665788946, '2077-12-11T21:45:45.635Z'), +(7.377436641850819, 5.188473630948079, '2077-12-11T21:51:59.635Z'), +(1.8413787313924652, 14.830766217319285, '2077-12-11T21:56:05.635Z'), +(23.407768802006792, 35.94470374354098, '2077-12-11T22:07:06.635Z'), +(22.87315469350862, 8.569346142449916, '2077-12-11T22:16:25.635Z'), +(4.112382475387642, 28.713825460410327, '2077-12-11T22:26:26.635Z'), +(15.600375620323904, 47.1689168567986, '2077-12-11T22:34:23.635Z'), +(17.001318585771873, 35.57535970527674, '2077-12-11T22:38:32.635Z'), +(2.5589874713567755, 45.28950378472128, '2077-12-11T22:44:56.635Z'), +(1.1713058892077468, 15.457848494076428, '2077-12-11T22:55:59.635Z'), +(16.35255825197124, 33.949488579844505, '2077-12-11T23:04:46.635Z'), +(10.753142717221653, 34.27794788486676, '2077-12-11T23:06:50.635Z'), +(5.518282502593037, 5.984562185608506, '2077-12-11T23:17:23.635Z'), +(10.195854517373178, 31.109503025140473, '2077-12-11T23:26:45.635Z'), +(11.498571501827401, 35.113843683758745, '2077-12-11T23:28:17.635Z'), +(13.276918747853069, 48.93494999579072, '2077-12-11T23:33:19.635Z'), +(1.2059340360717032, 3.944693763654479, '2077-12-11T23:50:24.635Z'), +(17.964169734138927, 49.73051333505084, '2077-12-12T00:08:10.635Z'), +(8.995569840575454, 11.867830786805806, '2077-12-12T00:22:10.635Z'), +(19.01761289497581, 41.630059698377416, '2077-12-12T00:33:28.635Z'), +(6.788305469312429, 34.88456877098105, '2077-12-12T00:38:36.635Z'), +(16.02240060123708, 24.13052192393752, '2077-12-12T00:43:47.635Z'), +(3.0299816083288964, 30.831812015241233, '2077-12-12T00:49:11.635Z'), +(7.878779677204642, 21.96862876721229, '2077-12-12T00:52:54.635Z'), +(20.041057001857318, 1.9301047194233125, '2077-12-12T01:01:23.635Z'), +(16.96001398671856, 24.67028090918305, '2077-12-12T01:09:27.635Z'), +(21.934242381494307, 14.599869379426728, '2077-12-12T01:13:25.635Z'), +(7.308606103379535, 49.259886792521705, '2077-12-12T01:26:55.635Z'), +(8.117777868716896, 41.56149421261474, '2077-12-12T01:29:45.635Z'), +(3.424627175981071, 2.3722294517274576, '2077-12-12T01:44:17.635Z'), +(7.064896523535179, 14.35016905411945, '2077-12-12T01:48:54.635Z'), +(3.92013631503061, 47.1309829096536, '2077-12-12T02:01:02.635Z'), +(2.3607438491318073, 28.58112436718593, '2077-12-12T02:07:55.635Z'), +(7.885129719849153, 35.406639027258635, '2077-12-12T02:11:09.635Z'), +(13.305487739675106, 8.491733246680914, '2077-12-12T02:21:09.635Z'), +(7.075966697431161, 44.48975251426352, '2077-12-12T02:34:28.635Z'), +(22.031143938358944, 47.92318299603404, '2077-12-12T02:40:08.635Z'), +(17.421204523273175, 43.02547990823809, '2077-12-12T02:42:32.635Z'), +(8.41906255877842, 16.491491064684585, '2077-12-12T02:52:40.635Z'), +(17.745867315359924, 37.04544338751966, '2077-12-12T03:00:50.635Z'), +(2.614752449377703, 33.5482062914027, '2077-12-12T03:06:35.635Z'), +(10.30100054051756, 16.208848780817785, '2077-12-12T03:13:34.635Z'), +(7.74670522753112, 27.804530360846414, '2077-12-12T03:17:54.635Z'), +(10.61641095780085, 4.584868154745024, '2077-12-12T03:26:27.635Z'), +(12.213800278070273, 16.585064338189586, '2077-12-12T03:30:50.635Z'), +(21.74626773161111, 38.83650837374239, '2077-12-12T03:39:27.635Z'), +(4.128447569133572, 9.849889362096848, '2077-12-12T03:51:44.635Z'), +(14.310419896143928, 9.163739558588311, '2077-12-12T03:55:30.635Z'), +(10.790013423524542, 24.229104218867747, '2077-12-12T04:01:06.635Z'), +(2.876962560619682, 11.180157092215289, '2077-12-12T04:06:43.635Z'), +(11.509968139196241, 25.68398994900773, '2077-12-12T04:12:55.635Z'), +(5.230142505951416, 29.784490658855248, '2077-12-12T04:15:41.635Z'), +(23.203267482103264, 46.978497417354916, '2077-12-12T04:24:44.635Z'), +(5.055840807163768, 7.70261393437934, '2077-12-12T04:40:17.635Z'), +(11.195666743139832, 24.943805229398418, '2077-12-12T04:47:00.635Z'), +(4.126276957847029, 28.230218918176032, '2077-12-12T04:49:53.635Z'), +(19.94773266820937, 15.040458029286036, '2077-12-12T04:57:26.635Z'), +(15.479658351480529, 45.031037943366535, '2077-12-12T05:08:08.635Z'), +(0.7435530429172363, 31.349912003289106, '2077-12-12T05:15:32.635Z'), +(3.6347616577530615, 44.6912589478492, '2077-12-12T05:20:35.635Z'), +(18.273668633721755, 46.33261196320652, '2077-12-12T05:26:02.635Z'), +(8.824095580336941, 28.30664980289867, '2077-12-12T05:33:24.635Z'), +(23.1891399337674, 32.24650513742149, '2077-12-12T05:38:54.635Z'), +(22.161490842530707, 8.673674045340501, '2077-12-12T05:46:57.635Z'), +(20.182820007819068, 37.937089517016325, '2077-12-12T05:57:04.635Z'), +(8.697439766194211, 13.24296634888032, '2077-12-12T06:06:52.635Z'), +(14.146980717577629, 34.69097213880082, '2077-12-12T06:14:54.635Z'), +(22.86965277392549, 29.160925306561772, '2077-12-12T06:18:40.635Z'), +(16.960961765823683, 17.41426796438756, '2077-12-12T06:23:18.635Z'), +(9.973933198889466, 2.6557299629704234, '2077-12-12T06:29:12.635Z'), +(17.913291433591677, 39.931897271800686, '2077-12-12T06:42:54.635Z'), +(13.446846385726905, 37.60837107044683, '2077-12-12T06:44:45.635Z'), +(13.882554375848526, 19.71723914752419, '2077-12-12T06:51:11.635Z'), +(5.932646318067488, 24.957976827954557, '2077-12-12T06:54:41.635Z'), +(17.230777494951344, 22.39830036604133, '2077-12-12T06:58:58.635Z'), +(12.266563306323533, 20.665578359948146, '2077-12-12T07:00:54.635Z'), +(20.945456620819712, 10.424027957712571, '2077-12-12T07:05:45.635Z'), +(5.961016363334365, 25.554573528766745, '2077-12-12T07:13:31.635Z'), +(0.13819890150495037, 16.94164989821548, '2077-12-12T07:17:21.635Z'), +(8.700152187981727, 35.08660165829499, '2077-12-12T07:24:45.635Z'), +(17.584123249960232, 26.654673581565653, '2077-12-12T07:29:13.635Z'), +(0.33117608923929126, 22.571154606743985, '2077-12-12T07:35:46.635Z'), +(19.669926140011434, 33.03849383782092, '2077-12-12T07:43:52.635Z'), +(21.68438747148711, 48.32535001984435, '2077-12-12T07:49:13.635Z'), +(11.381790707443798, 11.081622842734875, '2077-12-12T08:02:56.635Z'), +(19.991038361452937, 26.468203824187075, '2077-12-12T08:09:16.635Z'), +(19.351265437530586, 31.369063263686478, '2077-12-12T08:10:59.635Z'), +(3.907402880825897, 11.742805604410833, '2077-12-12T08:20:06.635Z'), +(4.313575144788843, 3.488240853503584, '2077-12-12T08:23:09.635Z'), +(10.938221567279248, 21.430407829713616, '2077-12-12T08:30:10.635Z'), +(19.512037164055606, 16.595278898203347, '2077-12-12T08:33:47.635Z'), +(7.688939707667227, 16.039787216712572, '2077-12-12T08:38:10.635Z'), +(12.628712321019963, 49.31834930220708, '2077-12-12T08:50:26.635Z'), +(12.948929993311754, 25.658468762003313, '2077-12-12T08:58:58.635Z'), +(7.236013909281278, 16.901309716395286, '2077-12-12T09:02:47.635Z'), +(2.7164470040324864, 18.265206895806678, '2077-12-12T09:04:31.635Z'), +(13.177325246854084, 38.09551492822735, '2077-12-12T09:12:45.635Z'), +(4.735805142491873, 8.310063813030832, '2077-12-12T09:24:04.635Z'), +(0.6864571791704521, 13.263349130561457, '2077-12-12T09:26:26.635Z'), +(16.943619275375518, 8.737496693516311, '2077-12-12T09:32:40.635Z'), +(16.763753199449994, 3.9450758693165517, '2077-12-12T09:34:22.635Z'), +(4.823699635054017, 11.513492855212553, '2077-12-12T09:39:34.635Z'), +(11.858178130456675, 1.9958392687626285, '2077-12-12T09:43:55.635Z'), +(4.929529845467776, 49.15278567365393, '2077-12-12T10:01:22.635Z'), +(4.987555565767104, 16.38932885385701, '2077-12-12T10:13:27.635Z'), +(12.630670961240261, 37.81611475278792, '2077-12-12T10:21:47.635Z'), +(6.092267779893021, 25.587057203821157, '2077-12-12T10:26:52.635Z'), +(16.642446313538624, 12.548514160058051, '2077-12-12T10:33:00.635Z'), +(8.60407884813824, 9.705916293946071, '2077-12-12T10:36:09.635Z'), +(2.9814588950303116, 0.7499568704425444, '2077-12-12T10:40:03.635Z'), +(16.056973718602652, 20.545623619971003, '2077-12-12T10:48:44.635Z'), +(11.993019615141003, 41.27763384703412, '2077-12-12T10:56:20.635Z'), +(0.16740857899693137, 44.21216246619943, '2077-12-12T11:00:50.635Z'), +(22.351062010570278, 35.4351641027089, '2077-12-12T11:09:38.635Z'), +(12.59185056450974, 2.898290040861969, '2077-12-12T11:21:39.635Z'), +(18.344063339672772, 34.75661737316561, '2077-12-12T11:33:12.635Z'), +(6.384901639098729, 47.20360376783969, '2077-12-12T11:39:30.635Z'), +(18.071685855067575, 41.577759658034836, '2077-12-12T11:44:17.635Z'), +(13.425152755513814, 0.5269309296568944, '2077-12-12T11:58:59.635Z'), +(7.2295081769658855, 13.019394401325103, '2077-12-12T12:04:04.635Z'), +(14.623957651869253, 35.717898492100346, '2077-12-12T12:12:45.635Z'), +(22.918294419168046, 22.25453773267028, '2077-12-12T12:18:22.635Z'), +(15.977350586522176, 24.541231441129526, '2077-12-12T12:21:03.635Z'), +(9.703055443043896, 43.93112744544726, '2077-12-12T12:28:25.635Z'), +(8.159145317254673, 10.306786227946942, '2077-12-12T12:40:44.635Z'), +(6.305764420941255, 26.64473247788394, '2077-12-12T12:46:46.635Z'), +(21.979089660204174, 25.405058451084965, '2077-12-12T12:52:35.635Z'), +(6.5658549389234775, 13.708137432234626, '2077-12-12T12:59:39.635Z'), +(0.7409853699110163, 4.108703777151852, '2077-12-12T13:03:48.635Z'), +(18.082589861320944, 11.488293550081634, '2077-12-12T13:10:46.635Z'), +(3.0997715603865816, 40.53345399132879, '2077-12-12T13:22:41.635Z'), +(15.121326691147116, 31.78444019020772, '2077-12-12T13:28:09.635Z'), +(15.68562584424224, 16.89575141344093, '2077-12-12T13:33:28.635Z'), +(1.5749227702283577, 10.59236605108193, '2077-12-12T13:39:10.635Z'), +(11.206114501931872, 1.6932785405608826, '2077-12-12T13:44:00.635Z'), +(17.046415210143085, 17.458882105418684, '2077-12-12T13:50:03.635Z'), +(22.252821084743175, 12.649420156458353, '2077-12-12T13:52:36.635Z'), +(4.32518683316096, 35.54166989347155, '2077-12-12T14:03:09.635Z'), +(4.395294621590673, 36.53520843581582, '2077-12-12T14:03:31.635Z'), +(0.9434905413944067, 7.239244623529519, '2077-12-12T14:14:26.635Z'), +(16.1680254667569, 28.1260005399793, '2077-12-12T14:23:55.635Z'), +(3.5857506883101022, 11.38036539484449, '2077-12-12T14:31:35.635Z'), +(10.85439170756351, 38.186991003161246, '2077-12-12T14:41:47.635Z'), +(13.671277962888905, 4.347116753158692, '2077-12-12T14:54:04.635Z'), +(21.012911021477926, 6.622145658369286, '2077-12-12T14:56:54.635Z'), +(1.9317204803945567, 13.46258225318126, '2077-12-12T15:04:23.635Z'), +(13.967322790949417, 33.110070253439055, '2077-12-12T15:12:51.635Z'), +(12.137210150570068, 2.306951505787833, '2077-12-12T15:23:59.635Z'), +(5.004952561757182, 8.889554321174513, '2077-12-12T15:27:33.635Z'), +(10.687835080410553, 12.659274919682325, '2077-12-12T15:30:04.635Z'), +(8.028003191363975, 43.57836491752054, '2077-12-12T15:41:24.635Z'), +(21.96715383667408, 29.248952673841263, '2077-12-12T15:48:40.635Z'), +(4.103042122132936, 26.077207939439447, '2077-12-12T15:55:23.635Z'), +(5.772038869100681, 30.973911867043494, '2077-12-12T15:57:17.635Z'), +(0.848150945478261, 39.37057221079447, '2077-12-12T16:00:53.635Z'), +(14.211411692308337, 42.761675928289705, '2077-12-12T16:05:59.635Z'), +(18.986013599135088, 17.585871539482024, '2077-12-12T16:15:05.635Z'), +(3.138147406475661, 31.223599748393323, '2077-12-12T16:22:45.635Z'), +(18.85687519149935, 25.96262852592254, '2077-12-12T16:28:52.635Z'), +(18.225806507120414, 30.79332219227343, '2077-12-12T16:30:34.635Z'), +(10.157921712317965, 11.961159327479951, '2077-12-12T16:37:57.635Z'), +(16.11358830207094, 46.278642999886415, '2077-12-12T16:50:30.635Z'), +(7.9856574805623985, 38.5482204542324, '2077-12-12T16:54:36.635Z'), +(3.4121656515447887, 28.86105310498383, '2077-12-12T16:58:33.635Z'), +(17.932903176830624, 15.49048477716976, '2077-12-12T17:05:47.635Z'), +(0.04858700990257021, 18.7971350846272, '2077-12-12T17:12:31.635Z'), +(8.534957606589993, 20.83575340217245, '2077-12-12T17:15:45.635Z'), +(7.772605775464885, 31.171905607647766, '2077-12-12T17:19:33.635Z'), +(15.884477475247287, 9.439650198962573, '2077-12-12T17:27:58.635Z'), +(8.247926594329682, 36.70567685516734, '2077-12-12T17:38:14.635Z'), +(6.253590921816762, 36.31746304055704, '2077-12-12T17:38:59.635Z'), +(3.1976895120041027, 37.74727160801465, '2077-12-12T17:40:13.635Z'), +(19.690982285318185, 11.299229900933195, '2077-12-12T17:51:34.635Z'), +(13.396227177172502, 33.21522879988446, '2077-12-12T17:59:41.635Z'), +(23.218794506346484, 2.9350530764620473, '2077-12-12T18:10:54.635Z'), +(12.214127710516095, 42.61911495706755, '2077-12-12T18:25:26.635Z'), +(10.983523481775153, 42.77785412658689, '2077-12-12T18:25:53.635Z'), +(9.96367127252485, 12.353376831237767, '2077-12-12T18:36:58.635Z'), +(1.5956088302012332, 11.25987267956692, '2077-12-12T18:40:05.635Z'), +(21.44139038986806, 14.796460529136285, '2077-12-12T18:47:32.635Z'), +(6.599045880318558, 7.917102402800162, '2077-12-12T18:53:33.635Z'), +(5.841898490584538, 44.33219300647653, '2077-12-12T19:06:58.635Z'), +(21.971734052011666, 49.82971702537559, '2077-12-12T19:13:15.635Z'), +(23.304141815271006, 28.952455008353194, '2077-12-12T19:20:24.635Z'), +(9.778750070685112, 11.473050088127463, '2077-12-12T19:28:21.635Z'), +(20.609145709180247, 15.921119749727803, '2077-12-12T19:32:40.635Z'), +(21.9944896327938, 24.57656011029234, '2077-12-12T19:35:41.635Z'), +(8.614127839563837, 10.237693056796012, '2077-12-12T19:42:48.635Z'), +(2.6149548969644285, 13.14997823616313, '2077-12-12T19:45:16.635Z'), +(22.677554505043087, 15.85428175824259, '2077-12-12T19:52:45.635Z'), +(18.796440306083944, 32.153330096206254, '2077-12-12T19:58:34.635Z'), +(16.298029619685703, 9.126195573030042, '2077-12-12T20:06:45.635Z'), +(5.084385762806791, 0.5577031740770764, '2077-12-12T20:11:56.635Z'), +(3.329867085965553, 26.745505496110855, '2077-12-12T20:21:38.635Z'), +(0.7773917493246506, 19.673159364288068, '2077-12-12T20:24:25.635Z'), +(0.06644074545484388, 4.852077926158027, '2077-12-12T20:29:54.635Z'), +(10.680381096412455, 45.674685084167265, '2077-12-12T20:45:26.635Z'), +(23.440456004518644, 4.694131657185303, '2077-12-12T21:00:38.635Z'), +(6.591223423564927, 5.4594915637922945, '2077-12-12T21:06:53.635Z'), +(11.648000359902603, 35.736257963180655, '2077-12-12T21:18:06.635Z'), +(14.399417381314938, 45.80223765822766, '2077-12-12T21:21:52.635Z'), +(0.5818753532975877, 19.907724196223395, '2077-12-12T21:32:39.635Z'), +(22.66055962841923, 50.241076129624474, '2077-12-12T21:46:18.635Z'), +(22.933635293445114, 6.131932526626956, '2077-12-12T22:01:18.635Z'), +(0.124784532039436, 10.64550916104106, '2077-12-12T22:09:54.635Z'), +(17.4598726767174, 43.387998624520634, '2077-12-12T22:23:27.635Z'), +(9.93304741036891, 13.022268300602722, '2077-12-12T22:34:43.635Z'), +(21.648665749917203, 29.69517823372399, '2077-12-12T22:42:04.635Z'), +(9.733206479888217, 13.872103865033809, '2077-12-12T22:49:13.635Z'), +(11.725924655703519, 7.534766849718958, '2077-12-12T22:51:38.635Z'), +(20.765667809223782, 46.95098668819744, '2077-12-12T23:06:00.635Z'), +(20.55148645396936, 4.4264493155257725, '2077-12-12T23:20:42.635Z'), +(15.865735873676178, 46.0351276690007, '2077-12-12T23:35:24.635Z'), +(6.750818709547903, 33.284288490837326, '2077-12-12T23:41:07.635Z'), +(22.463837481286486, 22.78276902091707, '2077-12-12T23:48:02.635Z'), +(21.526730715737834, 35.683799471167795, '2077-12-12T23:52:28.635Z'), +(7.8038080223165425, 31.70692806542714, '2077-12-12T23:57:44.635Z'), +(15.418201130833951, 9.906108778680258, '2077-12-13T00:06:07.635Z'), +(20.196414269741034, 18.2164225778457, '2077-12-13T00:09:32.635Z'), +(16.748415767868114, 16.173509767771733, '2077-12-13T00:10:59.635Z'), +(2.1139577628318813, 26.511767163847484, '2077-12-13T00:17:35.635Z'), +(0.827184775559624, 23.443123329071504, '2077-12-13T00:18:48.635Z'), +(8.652519096329945, 36.263846006548675, '2077-12-13T00:24:21.635Z'), +(2.0336831820625663, 1.7093155040581967, '2077-12-13T00:37:19.635Z'), +(19.04134598861272, 5.8987858264457165, '2077-12-13T00:43:48.635Z'), +(9.326822077423659, 5.392022939306847, '2077-12-13T00:47:24.635Z'), +(20.145490208887786, 46.46412001842815, '2077-12-13T01:02:36.635Z'), +(8.240379022257537, 21.376553719320302, '2077-12-13T01:12:36.635Z'), +(16.50792719456932, 5.046571932633528, '2077-12-13T01:19:15.635Z'), +(12.961338685603952, 23.27579105184055, '2077-12-13T01:25:54.635Z'), +(13.375176750110152, 7.047969955565287, '2077-12-13T01:31:45.635Z'), +(13.249369117761121, 18.470482138278644, '2077-12-13T01:35:52.635Z'), +(5.171255582601205, 23.728579541820036, '2077-12-13T01:39:25.635Z'), +(12.97047679140807, 10.870046039565652, '2077-12-13T01:44:56.635Z'), +(1.4396697819231588, 19.884049201290704, '2077-12-13T01:50:20.635Z'), +(2.5522425960195223, 32.738672577980374, '2077-12-13T01:55:06.635Z'), +(22.91925339852125, 37.89215049961139, '2077-12-13T02:02:52.635Z'), +(12.17166290806181, 18.926937062379398, '2077-12-13T02:10:39.635Z'), +(18.6219880706714, 0.5736871411935505, '2077-12-13T02:17:37.635Z'), +(15.281199353950406, 25.67423455951012, '2077-12-13T02:26:35.635Z'), +(21.02460409086484, 49.15982392405274, '2077-12-13T02:35:06.635Z'), +(16.54478169922744, 35.881297042782045, '2077-12-13T02:40:02.635Z'), +(19.359925073159726, 3.2600736195901363, '2077-12-13T02:51:33.635Z'), +(8.097072111522264, 38.89356596351915, '2077-12-13T03:05:00.635Z'), +(18.711410630445503, 33.800995862869, '2077-12-13T03:09:20.635Z'), +(5.5165256738507535, 43.19605651075142, '2077-12-13T03:15:17.635Z'), +(1.5980373361525566, 44.66725980544748, '2077-12-13T03:16:50.635Z'), +(8.290877845448774, 19.64174881534858, '2077-12-13T03:26:23.635Z'), +(10.684790221686857, 15.282731701082545, '2077-12-13T03:28:12.635Z'), +(20.47277932355691, 22.53771655398121, '2077-12-13T03:32:39.635Z'), +(17.731435866802784, 10.697990023943483, '2077-12-13T03:36:55.635Z'), +(19.357016235386403, 14.574154106475733, '2077-12-13T03:38:24.635Z'), +(19.705535060145863, 49.03766630376643, '2077-12-13T03:50:25.635Z'), +(21.125636920644578, 29.311968435505847, '2077-12-13T03:57:17.635Z'), +(5.635145514781442, 18.43537040922505, '2077-12-13T04:04:13.635Z'), +(20.390732077660775, 28.36420434129644, '2077-12-13T04:10:44.635Z'), +(5.384655152273197, 30.730919910917006, '2077-12-13T04:16:21.635Z'), +(13.812875019724713, 45.82005541576728, '2077-12-13T04:22:40.635Z'), +(3.4488614132312208, 36.04825371716131, '2077-12-13T04:27:54.635Z'), +(8.743636632146883, 3.6254653723969263, '2077-12-13T04:40:00.635Z'), +(6.9434584858928545, 36.43245783303327, '2077-12-13T04:52:03.635Z'), +(4.671416582888446, 32.4150631514693, '2077-12-13T04:53:45.635Z'), +(2.1791294262414618, 11.975854300575739, '2077-12-13T05:01:22.635Z'), +(17.142035206251013, 33.39594389304579, '2077-12-13T05:10:56.635Z'), +(6.848734736632896, 45.69820614944748, '2077-12-13T05:16:47.635Z'), +(19.40670630726444, 42.44389550690169, '2077-12-13T05:21:34.635Z'), +(1.496691403730563, 38.01918000336988, '2077-12-13T05:28:23.635Z'), +(7.424553987776506, 25.298385707574408, '2077-12-13T05:33:34.635Z'), +(17.88389253242234, 2.51582323862984, '2077-12-13T05:42:39.635Z'), +(21.226184781009774, 35.183407416944505, '2077-12-13T05:54:06.635Z'), +(11.058804426740721, 14.052912865107357, '2077-12-13T06:02:30.635Z'), +(13.178785376112694, 5.897087405478728, '2077-12-13T06:05:33.635Z'), +(14.082011533500884, 10.521441791460798, '2077-12-13T06:07:14.635Z'), +(19.21457490906151, 18.75563014346872, '2077-12-13T06:10:43.635Z'), +(22.634220554833632, 35.17012570823155, '2077-12-13T06:16:32.635Z'), +(1.8466502976180372, 6.3447358201898085, '2077-12-13T06:29:27.635Z'), +(7.595994475693903, 32.20123346413581, '2077-12-13T06:39:13.635Z'), +(23.422703186655983, 32.82122132640185, '2077-12-13T06:45:05.635Z'), +(6.666258267705961, 17.586546125889274, '2077-12-13T06:53:19.635Z'), +(6.261925929360893, 2.586657538116247, '2077-12-13T06:58:50.635Z'), +(11.199707664682377, 17.302677548515142, '2077-12-13T07:04:31.635Z'), +(13.689813381232492, 40.095742564318975, '2077-12-13T07:12:48.635Z'), +(14.245573508203613, 12.0868598922051, '2077-12-13T07:22:52.635Z'), +(3.6680539341772564, 6.954303159017472, '2077-12-13T07:27:12.635Z'), +(10.877683271952803, 33.5005461171266, '2077-12-13T07:37:18.635Z'), +(16.058075368214464, 1.5131031252243154, '2077-12-13T07:48:58.635Z'), +(13.14389580242402, 19.80042869867252, '2077-12-13T07:55:36.635Z'), +(23.165258369615355, 28.142107485032366, '2077-12-13T08:00:19.635Z'), +(1.7380402629183576, 15.178893251474797, '2077-12-13T08:09:31.635Z'), +(0.6471631070673145, 12.09871812656775, '2077-12-13T08:10:43.635Z'), +(18.061082243872434, 14.863300173083193, '2077-12-13T08:17:14.635Z'), +(7.002502343031851, 2.2788423701329013, '2077-12-13T08:23:21.635Z'), +(3.1022473867254377, 6.765954746174836, '2077-12-13T08:25:32.635Z'), +(9.343967525939254, 48.73606401825811, '2077-12-13T08:41:09.635Z'), +(0.9524301757894841, 30.578459719359493, '2077-12-13T08:48:32.635Z'), +(16.55493033766909, 16.82099775311913, '2077-12-13T08:56:11.635Z'), +(5.192319730795079, 8.243335261295247, '2077-12-13T09:01:25.635Z'), +(1.2285085314683797, 30.246702723713344, '2077-12-13T09:09:41.635Z'), +(9.603711800549888, 40.14319331597889, '2077-12-13T09:14:28.635Z'), +(13.053395251523916, 42.232442404544734, '2077-12-13T09:15:57.635Z'), +(9.806510482563544, 13.092804224177678, '2077-12-13T09:26:35.635Z'), +(22.28114492696065, 42.30832988062057, '2077-12-13T09:37:56.635Z'), +(20.755514958574228, 22.568936055779606, '2077-12-13T09:44:45.635Z'), +(1.3512332599711696, 18.832223324342173, '2077-12-13T09:52:04.635Z'), +(16.071847345896682, 3.7994636776224, '2077-12-13T09:59:48.635Z'), +(0.13684406668271787, 16.696193754393637, '2077-12-13T10:07:21.635Z'), +(8.366370461625024, 29.9946779992024, '2077-12-13T10:13:07.635Z'), +(18.06245571668937, 45.59954188909635, '2077-12-13T10:19:47.635Z'), +(15.363617114014422, 36.05071701100704, '2077-12-13T10:23:19.635Z'), +(14.516083185160227, 35.624206220862916, '2077-12-13T10:23:39.635Z'), +(11.396440008140841, 34.88352657926475, '2077-12-13T10:24:50.635Z'), +(1.662010696857378, 6.236659161876229, '2077-12-13T10:35:58.635Z'), +(5.635263155055087, 14.811449875636281, '2077-12-13T10:39:27.635Z'), +(22.94700008668154, 27.905165294442316, '2077-12-13T10:47:23.635Z'), +(9.546795982202076, 4.022815389187734, '2077-12-13T10:57:12.635Z'), +(0.2590862858821063, 30.071214504143242, '2077-12-13T11:07:24.635Z'), +(8.396800465883071, 17.077240808816338, '2077-12-13T11:13:04.635Z'), +(14.60899921420163, 16.01994948629516, '2077-12-13T11:15:24.635Z'), +(5.2381530741788955, 3.242256785272256, '2077-12-13T11:21:12.635Z'), +(10.121225107956942, 6.90481980814033, '2077-12-13T11:23:27.635Z'), +(3.7960711333990904, 0.042625308359069844, '2077-12-13T11:26:53.635Z'), +(9.838517157100304, 14.740282340238775, '2077-12-13T11:32:44.635Z'), +(5.510612937438761, 3.7622365011213446, '2077-12-13T11:37:04.635Z'), +(2.6456209648936575, 45.08130302491627, '2077-12-13T11:52:22.635Z'), +(22.635592735764682, 32.10368059743903, '2077-12-13T12:01:07.635Z'), +(16.576294438929995, 43.90804155165932, '2077-12-13T12:05:48.635Z'), +(0.11075996771350793, 40.16386608685925, '2077-12-13T12:12:03.635Z'), +(0.012256047425282296, 15.77501292532648, '2077-12-13T12:21:05.635Z'), +(8.332094608956764, 9.090447068945496, '2077-12-13T12:25:02.635Z'), +(2.2590863945791204, 19.489987626853843, '2077-12-13T12:29:28.635Z'), +(6.670979438377527, 38.58131679512902, '2077-12-13T12:36:42.635Z'), +(6.718861980243174, 0.14987819331433963, '2077-12-13T12:50:50.635Z'), +(7.028047017733311, 23.480301064405676, '2077-12-13T12:59:25.635Z'), +(19.889469998550453, 25.59610175869481, '2077-12-13T13:04:14.635Z'), +(11.20080848078959, 44.602994756126094, '2077-12-13T13:11:44.635Z'), +(19.63490511903778, 12.835502345653879, '2077-12-13T13:23:29.635Z'), +(21.85987509141628, 26.502306030297916, '2077-12-13T13:28:17.635Z'), +(15.0396632411485, 9.495747969978781, '2077-12-13T13:34:46.635Z'), +(22.416252705986587, 13.02893869219123, '2077-12-13T13:37:46.635Z'), +(2.0482167365471637, 17.47329132653551, '2077-12-13T13:45:29.635Z'), +(9.265366202033423, 42.6926905981073, '2077-12-13T13:55:09.635Z'), +(14.657548247037523, 40.358303056142766, '2077-12-13T13:57:19.635Z'), +(9.316754766299983, 41.04330839865592, '2077-12-13T13:59:18.635Z'), +(19.756758003891164, 41.941527548246846, '2077-12-13T14:03:10.635Z'), +(7.691715941978227, 21.45177062859752, '2077-12-13T14:11:46.635Z'), +(13.013189267532107, 32.32729907600945, '2077-12-13T14:16:11.635Z'), +(10.334738499736087, 18.671627097915636, '2077-12-13T14:21:14.635Z'), +(1.56685744600133, 41.55248172034767, '2077-12-13T14:30:15.635Z'), +(14.94222996744442, 21.862281919376233, '2077-12-13T14:38:59.635Z'), +(7.848600689115351, 46.681672079354406, '2077-12-13T14:48:22.635Z'), +(14.10083480914894, 43.754577404103856, '2077-12-13T14:50:55.635Z'), +(5.73040149003386, 38.264011255213276, '2077-12-13T14:54:36.635Z'), +(5.624432091316103, 13.936014492990363, '2077-12-13T15:03:34.635Z'), +(16.181925992833893, 21.29864682225883, '2077-12-13T15:08:18.635Z'), +(19.897303723186095, 35.73129028576727, '2077-12-13T15:13:34.635Z'), +(0.3040093513207745, 38.09129259105159, '2077-12-13T15:20:52.635Z'), +(20.122421875296634, 36.48930981567383, '2077-12-13T15:28:14.635Z'), +(6.3396807177676395, 45.28611213886851, '2077-12-13T15:34:14.635Z'), +(10.275066064672746, 37.26050719022119, '2077-12-13T15:37:31.635Z'), +(12.777172816180702, 3.1652440816387055, '2077-12-13T15:49:55.635Z'), +(23.251468380085672, 27.16475135750554, '2077-12-13T15:59:12.635Z'), +(19.699911598233204, 7.187288368863322, '2077-12-13T16:06:12.635Z'), +(14.734808435642213, 43.721474035433346, '2077-12-13T16:19:14.635Z'), +(23.532752671417352, 17.84714993861982, '2077-12-13T16:28:50.635Z'), +(4.372390259290255, 20.978647353609585, '2077-12-13T16:36:01.635Z'), +(9.528467420155092, 40.21342041969302, '2077-12-13T16:43:20.635Z'), +(9.335160989237881, 38.81804291510241, '2077-12-13T16:43:50.635Z'), +(21.497220661093692, 22.745720018149008, '2077-12-13T16:51:07.635Z'), +(20.107008876283004, 18.299633864354615, '2077-12-13T16:52:44.635Z'), +(5.055123365450786, 10.460223697068585, '2077-12-13T16:58:59.635Z'), +(17.37614132699442, 23.13486426141329, '2077-12-13T17:05:27.635Z'), +(15.972377300943739, 7.230293519210681, '2077-12-13T17:11:07.635Z'), +(20.82851154043217, 6.723628888150706, '2077-12-13T17:12:55.635Z'), +(13.527701530827231, 35.9725724180717, '2077-12-13T17:23:36.635Z'), +(18.75409694102154, 6.940303690507743, '2077-12-13T17:34:06.635Z'), +(3.3193875492944604, 24.526198089344412, '2077-12-13T17:42:39.635Z'), +(16.93063511251249, 50.29662603507547, '2077-12-13T17:53:17.635Z'), +(2.4267943032128554, 28.28797579942145, '2077-12-13T18:02:56.635Z'), +(0.8938181561778581, 26.52899748580472, '2077-12-13T18:03:47.635Z'), +(6.36797323585953, 46.735953134917764, '2077-12-13T18:11:31.635Z'), +(10.14001867375562, 5.077740073770548, '2077-12-13T18:26:51.635Z'), +(20.551547809349554, 34.93710327177443, '2077-12-13T18:38:10.635Z'), +(7.246057006918524, 29.59237019406662, '2077-12-13T18:43:27.635Z'), +(13.433007652537942, 44.635758977152285, '2077-12-13T18:49:23.635Z'), +(22.321286859349453, 22.213503744151172, '2077-12-13T18:57:56.635Z'), +(14.442306443806919, 19.50516549270014, '2077-12-13T19:01:00.635Z'), +(13.881772688279634, 6.231109306913579, '2077-12-13T19:05:46.635Z'), +(5.967167697164056, 10.442539036204298, '2077-12-13T19:09:04.635Z'), +(11.108605666116107, 18.889311029097534, '2077-12-13T19:12:42.635Z'), +(9.966678400308016, 12.695312101917454, '2077-12-13T19:14:59.635Z'), +(19.760101862983106, 31.617495003456035, '2077-12-13T19:22:39.635Z'), +(17.562594025980328, 49.80229811792556, '2077-12-13T19:29:05.635Z'), +(7.847029278436221, 3.4596923536773496, '2077-12-13T19:46:10.635Z'), +(11.609010353120858, 36.595754916135135, '2077-12-13T19:58:20.635Z'), +(10.889471542890718, 10.58980682329768, '2077-12-13T20:07:47.635Z'), +(5.175554292781554, 37.230367098585674, '2077-12-13T20:17:46.635Z'), +(18.380105747504434, 16.95757251304398, '2077-12-13T20:26:35.635Z'), +(11.949239042524642, 33.02472981992357, '2077-12-13T20:32:48.635Z'), +(5.458949293139683, 21.33079067471072, '2077-12-13T20:37:42.635Z'), +(0.8868494154501291, 36.22541142373863, '2077-12-13T20:43:27.635Z'), +(7.573594685351063, 21.1581514319312, '2077-12-13T20:49:32.635Z'), +(8.387882221658252, 6.668054715239586, '2077-12-13T20:54:51.635Z'), +(23.37430158666548, 37.06451570066019, '2077-12-13T21:06:59.635Z'), +(9.187821473951203, 41.18960418994512, '2077-12-13T21:12:26.635Z'), +(20.01397825311247, 42.831733208746314, '2077-12-13T21:16:29.635Z'), +(16.804681316331877, 5.474158960902903, '2077-12-13T21:29:38.635Z'), +(7.267387437550968, 17.633007817964337, '2077-12-13T21:35:16.635Z'), +(3.364174152533446, 25.12184807884324, '2077-12-13T21:38:23.635Z'), +(12.053545956227495, 48.96290365886944, '2077-12-13T21:47:42.635Z'), +(9.719452882354421, 45.91022986376544, '2077-12-13T21:49:06.635Z'), +(4.55297898129034, 29.318976171066797, '2077-12-13T21:55:29.635Z'), +(1.520924554918035, 46.612880077905615, '2077-12-13T22:01:58.635Z'), +(17.751311609014405, 22.115417402916286, '2077-12-13T22:12:43.635Z'), +(12.582625571502584, 15.847703266534777, '2077-12-13T22:15:39.635Z'), +(1.1591079540923315, 42.016988340017335, '2077-12-13T22:26:09.635Z'), +(9.797364128455484, 43.40081589279487, '2077-12-13T22:29:23.635Z'), +(22.0834678709927, 48.453795677537066, '2077-12-13T22:34:16.635Z'), +(3.153059586263439, 30.995612261472424, '2077-12-13T22:43:40.635Z'), +(20.171819858195597, 18.91206063963804, '2077-12-13T22:51:20.635Z'), +(5.5970113778030255, 1.6256897068608944, '2077-12-13T22:59:34.635Z'), +(3.2158447767096687, 24.970600892810616, '2077-12-13T23:08:14.635Z'), +(9.60384684766521, 48.85982401995423, '2077-12-13T23:17:20.635Z'), +(7.323631833344224, 42.92732071902459, '2077-12-13T23:19:39.635Z'), +(12.906504013845947, 16.604880992686898, '2077-12-13T23:29:28.635Z'), +(6.475935599090715, 4.829695630405728, '2077-12-13T23:34:22.635Z'), +(9.489040956263947, 33.8815483139038, '2077-12-13T23:45:05.635Z'), +(12.639848234532524, 19.970115780292595, '2077-12-13T23:50:16.635Z'), +(14.006060504880402, 23.146863526023804, '2077-12-13T23:51:31.635Z'), +(13.92704423706222, 11.499478975739654, '2077-12-13T23:55:42.635Z'), +(5.583353404119129, 28.247571827346263, '2077-12-14T00:02:32.635Z'), +(14.138888240731111, 42.67207665318323, '2077-12-14T00:08:40.635Z'), +(5.677386940696925, 4.556297652975078, '2077-12-14T00:22:54.635Z'), +(10.995783448221905, 42.10821652608351, '2077-12-14T00:36:48.635Z'), +(6.667516081194394, 0.9128510846292515, '2077-12-14T00:51:57.635Z'), +(4.911557033652922, 41.75757945708281, '2077-12-14T01:07:01.635Z'), +(17.44754254332932, 7.747089177241308, '2077-12-14T01:20:11.635Z'), +(9.733236992557986, 36.63967269520989, '2077-12-14T01:30:57.635Z'), +(11.645417991907577, 1.7922201733836558, '2077-12-14T01:43:39.635Z'), +(12.830408277859897, 33.36725304888299, '2077-12-14T01:55:05.635Z'), +(14.226163325701943, 43.58923355955851, '2077-12-14T01:58:48.635Z'), +(8.542998811006699, 8.83138729938614, '2077-12-14T02:11:35.635Z'), +(17.666960597544374, 20.284685192641668, '2077-12-14T02:16:55.635Z'), +(7.807255583554823, 18.979572891226304, '2077-12-14T02:20:36.635Z'), +(7.236208342861053, 29.91262112774346, '2077-12-14T02:24:37.635Z'), +(3.777614871522356, 49.806345249992226, '2077-12-14T02:32:03.635Z'), +(21.455437418246603, 9.176993948867675, '2077-12-14T02:48:03.635Z'), +(11.090408075095903, 39.56663230033334, '2077-12-14T02:59:29.635Z'), +(1.0526796852830351, 22.26222177090649, '2077-12-14T03:06:51.635Z'), +(19.282068196198548, 25.3780913155421, '2077-12-14T03:13:42.635Z'), +(9.412279873392672, 9.989148322202098, '2077-12-14T03:20:19.635Z'), +(9.681329803616821, 15.62994167245572, '2077-12-14T03:22:22.635Z'), +(10.805120688947909, 22.64906746380593, '2077-12-14T03:24:57.635Z'), +(19.486021458369997, 43.32346479827306, '2077-12-14T03:33:00.635Z'), +(15.214867185540953, 5.032041138638763, '2077-12-14T03:46:36.635Z'), +(13.281555154680364, 15.465098515372793, '2077-12-14T03:50:24.635Z'), +(10.361088886622442, 39.44680287632232, '2077-12-14T03:59:09.635Z'), +(19.441760019780272, 5.563505228417146, '2077-12-14T04:11:43.635Z'), +(16.4874778780778, 15.568430242162009, '2077-12-14T04:15:24.635Z'), +(8.502975321381312, 9.815385299964694, '2077-12-14T04:19:01.635Z'), +(14.546349478957021, 2.6652319999063216, '2077-12-14T04:22:26.635Z'), +(20.9973011697971, 1.095367270809713, '2077-12-14T04:24:53.635Z'), +(8.157378138746104, 26.264016587545907, '2077-12-14T04:35:03.635Z'), +(4.106487131362755, 42.05151776899402, '2077-12-14T04:41:03.635Z'), +(12.038842055134632, 15.841728506065417, '2077-12-14T04:51:05.635Z'), +(9.570322355770278, 49.06370709811801, '2077-12-14T05:03:12.635Z'), +(12.604557332352984, 37.86573454183138, '2077-12-14T05:07:25.635Z'), +(4.906790929177995, 29.465262886857982, '2077-12-14T05:11:36.635Z'), +(18.955489701287036, 7.404379416028222, '2077-12-14T05:21:07.635Z'), +(13.892762863060094, 39.97576726619393, '2077-12-14T05:32:49.635Z'), +(15.780098523137754, 6.596439967353443, '2077-12-14T05:44:47.635Z'), +(20.556661305475405, 43.062341398251256, '2077-12-14T05:57:43.635Z'), +(5.683652108820414, 37.15595876340128, '2077-12-14T06:03:37.635Z'), +(10.066664832798523, 25.322961283978497, '2077-12-14T06:08:15.635Z'), +(6.977042326390105, 29.706844874803444, '2077-12-14T06:10:13.635Z'), +(1.6513548520082972, 5.86355246993892, '2077-12-14T06:19:14.635Z'), +(12.573945116315965, 40.337752579296335, '2077-12-14T06:32:31.635Z'), +(3.5550872759525927, 40.148594055602615, '2077-12-14T06:35:51.635Z'), +(22.978213181548462, 12.26529123471364, '2077-12-14T06:48:10.635Z'), +(21.079156038597144, 29.738571771392074, '2077-12-14T06:54:12.635Z'), +(4.54563897568806, 28.742087881075797, '2077-12-14T07:00:20.635Z'), +(13.94929015933188, 26.150487704158454, '2077-12-14T07:03:56.635Z'), +(18.328923947336904, 44.979428541668, '2077-12-14T07:10:49.635Z'), +(8.324425623235635, 31.73762238804432, '2077-12-14T07:16:51.635Z'), +(18.089098450272104, 44.83433559031262, '2077-12-14T07:22:47.635Z'), +(5.788304791277501, 0.21011801626823723, '2077-12-14T07:39:32.635Z'), +(23.390625643877467, 20.16057047998403, '2077-12-14T07:49:11.635Z'), +(17.344242695798922, 45.28823727646881, '2077-12-14T07:58:11.635Z'), +(16.360691669641017, 38.2339791926767, '2077-12-14T08:00:42.635Z'), +(21.833334502589146, 21.986893397092814, '2077-12-14T08:06:44.635Z'), +(0.8961659361434512, 24.340237027886598, '2077-12-14T08:14:32.635Z'), +(3.9966562937324155, 18.47152695535867, '2077-12-14T08:16:59.635Z'), +(18.595690173213423, 27.357885670021293, '2077-12-14T08:23:16.635Z'), +(10.814312807159798, 43.486593771449655, '2077-12-14T08:29:43.635Z'), +(21.728132878031722, 23.32222911244445, '2077-12-14T08:37:56.635Z'), +(8.134808570958686, 33.72110385814881, '2077-12-14T08:44:11.635Z'), +(18.73328622909068, 31.56615370827475, '2077-12-14T08:48:11.635Z'), +(3.1547841961333756, 1.3518953919633308, '2077-12-14T09:00:33.635Z'), +(3.4538063267772237, 25.272398829808463, '2077-12-14T09:09:24.635Z'), +(4.228080249276333, 7.303538938136225, '2077-12-14T09:16:03.635Z'), +(5.349162492088183, 24.83155813336097, '2077-12-14T09:22:32.635Z'), +(17.772067735711556, 10.174433360406642, '2077-12-14T09:29:33.635Z'), +(14.52200614627177, 31.764980560005682, '2077-12-14T09:37:19.635Z'), +(7.550077232181472, 26.668823394092847, '2077-12-14T09:40:29.635Z'), +(18.301908995582625, 1.2054396698789063, '2077-12-14T09:50:29.635Z'), +(9.192858654549134, 20.594091118472697, '2077-12-14T09:58:13.635Z'), +(0.5481517446988471, 27.44722722950433, '2077-12-14T10:02:17.635Z'), +(5.629060456776812, 11.359798087292859, '2077-12-14T10:08:31.635Z'), +(17.146080048516367, 30.17778348294684, '2077-12-14T10:16:33.635Z'), +(22.997397911724317, 6.090071377736049, '2077-12-14T10:25:11.635Z'), +(15.145895978883035, 48.06389619621366, '2077-12-14T10:40:07.635Z'), +(12.690257389569744, 46.47007535216082, '2077-12-14T10:41:11.635Z'), +(3.2222825512704407, 39.314724981533686, '2077-12-14T10:45:33.635Z'), +(11.68950955736164, 47.20470352577111, '2077-12-14T10:49:49.635Z'), +(8.003530605064391, 38.155154756279565, '2077-12-14T10:53:23.635Z'), +(2.869288080715202, 4.686326273265779, '2077-12-14T11:05:52.635Z'), +(23.37567618252321, 17.17622217813936, '2077-12-14T11:14:41.635Z'), +(12.99485899483415, 7.357316642225139, '2077-12-14T11:19:51.635Z'), +(3.1718862959021332, 19.836953528065322, '2077-12-14T11:25:41.635Z'), +(21.96284061904132, 45.086040908889046, '2077-12-14T11:37:07.635Z'), +(20.782987757968886, 28.570932040157505, '2077-12-14T11:42:49.635Z'), +(8.325545376648758, 17.222399070898064, '2077-12-14T11:48:57.635Z'), +(6.630932654849459, 41.175566363638744, '2077-12-14T11:57:46.635Z'), +(2.2124727758505833, 1.8582908149483863, '2077-12-14T12:12:22.635Z'), +(21.41374344256586, 0.7675026399026788, '2077-12-14T12:19:29.635Z'), +(18.04999173213649, 25.18806468041317, '2077-12-14T12:28:05.635Z'), +(16.97533085068448, 30.873038077714483, '2077-12-14T12:30:07.635Z'), +(15.875074760041377, 33.3988388392761, '2077-12-14T12:31:06.635Z'), +(20.823895619006667, 30.417359501937277, '2077-12-14T12:33:12.635Z'), +(15.122856144105695, 33.61212011787369, '2077-12-14T12:35:35.635Z'), +(20.757964498198447, 47.77219632037501, '2077-12-14T12:40:59.635Z'), +(21.244468023334093, 17.796619863360057, '2077-12-14T12:51:20.635Z'), +(1.9050610856614996, 38.55035119771828, '2077-12-14T13:01:42.635Z'), +(4.406265709379112, 23.506089602895084, '2077-12-14T13:07:20.635Z'), +(18.256408863127774, 50.154253030335084, '2077-12-14T13:18:16.635Z'), +(7.406694016346176, 17.19594882389021, '2077-12-14T13:30:48.635Z'), +(15.475946364078697, 33.8826914855193, '2077-12-14T13:37:33.635Z'), +(12.000575391474108, 6.7296968190485655, '2077-12-14T13:47:24.635Z'), +(13.84562020610978, 3.6265795882791036, '2077-12-14T13:48:42.635Z'), +(12.829065982993574, 24.28593863441003, '2077-12-14T13:56:09.635Z'), +(8.95049284031694, 22.3426814310361, '2077-12-14T13:57:45.635Z'), +(15.195715661979245, 35.719716599231774, '2077-12-14T14:03:07.635Z'), +(9.73915050663731, 21.148689129024344, '2077-12-14T14:08:45.635Z'), +(21.969677434277937, 20.96276758803403, '2077-12-14T14:13:17.635Z'), +(16.06255144673257, 8.65463534522231, '2077-12-14T14:18:07.635Z'), +(11.39027420779472, 0.1410014438054461, '2077-12-14T14:21:38.635Z'), +(21.482077642435275, 24.590613360870428, '2077-12-14T14:31:04.635Z'), +(2.040773614752624, 46.05448800843592, '2077-12-14T14:41:38.635Z'), +(11.477667184227055, 25.017016096248998, '2077-12-14T14:50:07.635Z'), +(6.429268845594634, 9.670994808506865, '2077-12-14T14:56:02.635Z'), +(17.346460454161587, 46.65485684277408, '2077-12-14T15:10:00.635Z'), +(9.025948312398022, 5.612453347830213, '2077-12-14T15:25:05.635Z'), +(3.688954859415139, 33.39382211591555, '2077-12-14T15:35:30.635Z'), +(11.122370248615033, 34.614153171307365, '2077-12-14T15:38:17.635Z'), +(17.184924555868264, 4.9396900131365085, '2077-12-14T15:49:10.635Z'), +(12.049331076540433, 38.71231105996516, '2077-12-14T16:01:24.635Z'), +(15.321357546022979, 29.804010584028667, '2077-12-14T16:04:49.635Z'), +(4.224003818342047, 2.2580167814279823, '2077-12-14T16:15:40.635Z'), +(6.453950856159835, 2.3074744990420233, '2077-12-14T16:16:29.635Z'), +(18.157490762618757, 29.481855523188557, '2077-12-14T16:27:12.635Z'), +(9.095099492412238, 10.362907911986396, '2077-12-14T16:34:51.635Z'), +(6.061435425812192, 5.633551152028189, '2077-12-14T16:36:55.635Z'), +(1.7753883738321032, 23.03666693274115, '2077-12-14T16:43:32.635Z'), +(16.892665719467022, 36.64862327396402, '2077-12-14T16:51:01.635Z'), +(3.0967896999292086, 33.39237336445024, '2077-12-14T16:56:15.635Z'), +(8.427970192575643, 11.197478544529334, '2077-12-14T17:04:39.635Z'), +(16.81217079432747, 45.3592862451268, '2077-12-14T17:17:22.635Z'), +(0.629881948778914, 5.287039054786135, '2077-12-14T17:33:10.635Z'), +(4.460805839729364, 12.941887726652768, '2077-12-14T17:36:20.635Z'), +(9.638759892898662, 45.90313237172197, '2077-12-14T17:48:36.635Z'), +(5.509092426390502, 30.306697942103693, '2077-12-14T17:54:31.635Z'), +(3.395139538560675, 25.645556319854446, '2077-12-14T17:56:24.635Z'), +(17.318198706037617, 15.26614554987786, '2077-12-14T18:02:47.635Z'), +(2.0159497333558734, 45.27025533312233, '2077-12-14T18:15:05.635Z'), +(23.368778609038852, 45.08376989706956, '2077-12-14T18:22:59.635Z'), +(0.7530089236779984, 35.24242734527693, '2077-12-14T18:32:04.635Z'), +(5.814863754336925, 15.9824208592847, '2077-12-14T18:39:26.635Z'), +(4.758469958077659, 11.006956177116285, '2077-12-14T18:41:18.635Z'), +(5.581799292369055, 29.28090779160663, '2077-12-14T18:48:03.635Z'), +(20.031711635950753, 19.40273226478455, '2077-12-14T18:54:28.635Z'), +(6.796859301255493, 44.26577895944556, '2077-12-14T19:04:39.635Z'), +(21.880514701915526, 26.39972727500287, '2077-12-14T19:13:08.635Z'), +(17.14490922802153, 6.645004640006073, '2077-12-14T19:20:14.635Z'), +(19.592959125849767, 25.074995487732117, '2077-12-14T19:26:46.635Z'), +(19.76738592689787, 47.35839541650729, '2077-12-14T19:34:32.635Z'), +(19.632216319053086, 30.49827049042288, '2077-12-14T19:40:24.635Z'), +(13.50346227328964, 9.724938814212209, '2077-12-14T19:48:06.635Z'), +(15.72683698703378, 14.773802039894317, '2077-12-14T19:50:05.635Z'), +(5.715865445239903, 3.0487126939184077, '2077-12-14T19:55:44.635Z'), +(10.626835240792166, 17.716914356314348, '2077-12-14T20:01:24.635Z'), +(7.402897002925396, 31.690121778912726, '2077-12-14T20:06:39.635Z'), +(0.43903287460898416, 5.866661666082368, '2077-12-14T20:16:32.635Z'), +(16.376691482402066, 21.109514993263385, '2077-12-14T20:24:39.635Z'), +(20.658280722370026, 33.26947859755775, '2077-12-14T20:29:12.635Z'), +(4.587265388432646, 41.511054953796474, '2077-12-14T20:35:51.635Z'), +(0.253973094986863, 22.3998601557223, '2077-12-14T20:43:06.635Z'), +(14.200083474857992, 16.23841048481664, '2077-12-14T20:48:44.635Z'), +(15.729697088982041, 50.00391438490289, '2077-12-14T21:00:49.635Z'), +(6.237617072273907, 28.587484053946945, '2077-12-14T21:09:21.635Z'), +(13.709219330745452, 49.97043458015487, '2077-12-14T21:17:37.635Z'), +(14.957883277687694, 40.12132198907208, '2077-12-14T21:21:11.635Z'), +(7.859129008535173, 37.94125500247762, '2077-12-14T21:23:55.635Z'), +(16.732622977591923, 37.38833792428761, '2077-12-14T21:27:12.635Z'), +(15.085796474277359, 38.401276439768814, '2077-12-14T21:27:54.635Z'), +(2.733131211969803, 50.28368743758153, '2077-12-14T21:34:12.635Z'), +(12.963513317249564, 19.06803207025767, '2077-12-14T21:46:15.635Z'), +(11.572400465036402, 39.762128055867116, '2077-12-14T21:53:45.635Z'), +(12.194219825014201, 25.089413781349588, '2077-12-14T21:59:04.635Z'), +(16.20638714171245, 41.99792056256573, '2077-12-14T22:05:19.635Z'), +(11.985379286129591, 12.737839907089567, '2077-12-14T22:15:56.635Z'), +(1.9690436508282267, 34.12315524991649, '2077-12-14T22:24:37.635Z'), +(19.074848457544793, 35.51208489798584, '2077-12-14T22:30:58.635Z'), +(11.931381909068564, 32.818512443582144, '2077-12-14T22:33:47.635Z'), +(2.2448099340125918, 40.2508527676988, '2077-12-14T22:38:17.635Z'), +(0.2981382899515064, 48.90945524698937, '2077-12-14T22:41:34.635Z'), +(6.518905690112884, 0.2611378082033814, '2077-12-14T22:59:42.635Z'), +(23.317422976104535, 27.612455866536543, '2077-12-14T23:11:15.635Z'), +(11.215693614464522, 2.1632868845850535, '2077-12-14T23:21:17.635Z'), +(14.279633442416308, 23.181437459692518, '2077-12-14T23:28:57.635Z'), +(9.56228935534883, 16.835278849523995, '2077-12-14T23:31:50.635Z'), +(14.186949884261363, 11.657293823530045, '2077-12-14T23:34:22.635Z'), +(6.768130320761824, 7.673769179040886, '2077-12-14T23:37:28.635Z'), +(11.438991957710524, 9.384041664490622, '2077-12-14T23:39:18.635Z'), +(12.889548036365458, 34.14964415967899, '2077-12-14T23:48:17.635Z'), +(3.1398390272713472, 11.525186410607406, '2077-12-14T23:57:19.635Z'), +(3.9999475315173996, 24.7681818676425, '2077-12-15T00:02:13.635Z'), +(13.056736591858392, 42.755708643887, '2077-12-15T00:09:36.635Z'), +(6.52096530613305, 31.24105729323904, '2077-12-15T00:14:27.635Z'), +(18.436961901406058, 22.651323006163164, '2077-12-15T00:19:50.635Z'), +(3.288869050341825, 41.49247117370824, '2077-12-15T00:28:40.635Z'), +(4.85537520454974, 30.58899198801662, '2077-12-15T00:32:44.635Z'), +(0.578064717934279, 20.365344718564966, '2077-12-15T00:36:50.635Z'), +(17.950988067111812, 8.182942951496313, '2077-12-15T00:44:39.635Z'), +(0.23199611652298532, 27.894101869047237, '2077-12-15T00:54:22.635Z'), +(23.26230118273495, 14.080641422140445, '2077-12-15T01:04:14.635Z'), +(13.774748649740756, 3.1647436195686995, '2077-12-15T01:09:25.635Z'), +(5.02582998850901, 26.04731337567721, '2077-12-15T01:18:22.635Z'), +(21.52614913218711, 21.118013890682697, '2077-12-15T01:24:44.635Z'), +(16.202763816375516, 5.9461151558305785, '2077-12-15T01:30:24.635Z'), +(18.55616141463069, 31.319846039499676, '2077-12-15T01:39:24.635Z'), +(1.4671871613048295, 28.54242756226642, '2077-12-15T01:45:48.635Z'), +(2.328155069350657, 46.015984901327194, '2077-12-15T01:52:16.635Z'), +(19.446337164205765, 48.88459507424983, '2077-12-15T01:58:41.635Z'), +(1.3813959825502953, 42.24073301720979, '2077-12-15T02:05:47.635Z'), +(22.979128922221, 30.898080536703105, '2077-12-15T02:14:46.635Z'), +(14.105270320271112, 36.809655330592285, '2077-12-15T02:18:39.635Z'), +(20.535851635340425, 38.94717359278312, '2077-12-15T02:21:09.635Z'), +(7.210748258221086, 22.038506269034748, '2077-12-15T02:28:58.635Z'), +(22.851922138194894, 0.5163469255953923, '2077-12-15T02:38:34.635Z'), +(23.54872926061618, 5.903784834207706, '2077-12-15T02:40:25.635Z'), +(11.842991694650522, 42.89203390488273, '2077-12-15T02:54:07.635Z'), +(3.365233798929498, 34.40346982794459, '2077-12-15T02:58:32.635Z'), +(15.258881758017885, 46.51353657507501, '2077-12-15T03:04:46.635Z'), +(3.7403181277103945, 10.063999525669544, '2077-12-15T03:18:43.635Z'), +(13.920118498386513, 32.50631320750709, '2077-12-15T03:27:44.635Z'), +(12.811778283905998, 46.98046112628441, '2077-12-15T03:32:58.635Z'), +(17.814303364851412, 9.525897186255825, '2077-12-15T03:46:27.635Z'), +(3.8400489701080853, 26.65165553313565, '2077-12-15T03:54:32.635Z'), +(8.666774856798302, 6.529227101562399, '2077-12-15T04:02:09.635Z'), +(5.813450296920859, 22.530638642951182, '2077-12-15T04:08:07.635Z'), +(12.151654777754983, 45.24282670684149, '2077-12-15T04:16:45.635Z'), +(12.49127870741891, 14.432833533490747, '2077-12-15T04:27:54.635Z'), +(11.52249253735469, 32.48905772659196, '2077-12-15T04:34:27.635Z'), +(2.714292112877638, 21.07539361162174, '2077-12-15T04:39:45.635Z'), +(15.852354314552434, 20.778979573022262, '2077-12-15T04:44:37.635Z'), +(8.172468285710762, 2.401875936617916, '2077-12-15T04:51:51.635Z'), +(1.3691989436954906, 44.539376866055505, '2077-12-15T05:07:36.635Z'), +(13.94655539083805, 36.24220782086646, '2077-12-15T05:13:09.635Z'), +(4.376837514270185, 26.141459626374367, '2077-12-15T05:18:16.635Z'), +(10.134499347734156, 3.627037763526915, '2077-12-15T05:26:48.635Z'), +(22.836873094474342, 48.22019103525196, '2077-12-15T05:43:15.635Z'), +(19.76501652659935, 39.894162375699736, '2077-12-15T05:46:20.635Z'), +(5.90993624617464, 12.666702307105174, '2077-12-15T05:57:24.635Z'), +(13.835448614099285, 37.23211776508191, '2077-12-15T06:06:49.635Z'), +(6.5818167910312, 10.014106151581236, '2077-12-15T06:17:05.635Z'), +(1.2764743125284648, 14.250873183952825, '2077-12-15T06:19:35.635Z'), +(4.320074397948731, 45.51052269147947, '2077-12-15T06:31:12.635Z'), +(6.36004115345524, 28.629167135111476, '2077-12-15T06:37:28.635Z'), +(5.962333560648016, 47.14939210758815, '2077-12-15T06:44:17.635Z'), +(5.507648412946327, 7.04713100957728, '2077-12-15T06:59:04.635Z'), +(3.5780160512691617, 47.37873645178833, '2077-12-15T07:13:58.635Z'), +(20.37330013287275, 47.937452601624464, '2077-12-15T07:20:11.635Z'), +(20.430625610496886, 30.32994231503107, '2077-12-15T07:26:17.635Z'), +(15.354049319671427, 7.450122650230088, '2077-12-15T07:34:33.635Z'), +(22.79199476812194, 9.339229423427614, '2077-12-15T07:37:23.635Z'), +(7.006220377715425, 8.789144095965073, '2077-12-15T07:43:14.635Z'), +(1.2523991149369336, 20.23631312489844, '2077-12-15T07:47:58.635Z'), +(10.81035247361979, 3.774476246253794, '2077-12-15T07:54:59.635Z'), +(2.7926503914522187, 13.79195201222692, '2077-12-15T07:59:42.635Z'), +(2.4346272277183596, 36.05327917367871, '2077-12-15T08:07:56.635Z'), +(15.16901550294718, 27.76821279458976, '2077-12-15T08:13:32.635Z'), +(4.715138591857742, 19.09194480787681, '2077-12-15T08:18:32.635Z'), +(6.542243069859312, 20.813483073868433, '2077-12-15T08:19:27.635Z'), +(18.952932385633233, 10.014525061542011, '2077-12-15T08:25:28.635Z'), +(0.9421293592272947, 13.031855011498479, '2077-12-15T08:32:13.635Z'), +(5.804345515882971, 46.072443503284234, '2077-12-15T08:44:34.635Z'), +(14.297536370871276, 8.17460033730923, '2077-12-15T08:58:43.635Z'), +(16.043837784882427, 16.562686913626752, '2077-12-15T09:01:47.635Z'), +(6.011652492491417, 16.670431360702242, '2077-12-15T09:05:30.635Z'), +(8.277628716324626, 19.41925450758715, '2077-12-15T09:06:48.635Z'), +(10.891402731436122, 31.366991414266266, '2077-12-15T09:11:16.635Z'), +(3.912198116575414, 37.04931913975324, '2077-12-15T09:14:35.635Z'), +(13.004598987598673, 20.9737339357795, '2077-12-15T09:21:21.635Z'), +(8.464669527165656, 22.105065019787993, '2077-12-15T09:23:04.635Z'), +(18.970929734633934, 26.395770692663657, '2077-12-15T09:27:15.635Z'), +(1.976897882727201, 14.346597419255803, '2077-12-15T09:34:55.635Z'), +(12.218027095571621, 24.650431955935066, '2077-12-15T09:40:16.635Z'), +(18.586698509055466, 37.19445050429607, '2077-12-15T09:45:19.635Z'), +(9.178100890477875, 41.861097495906954, '2077-12-15T09:49:11.635Z'), +(0.6449424874456638, 21.074228794054072, '2077-12-15T09:57:28.635Z'), +(12.934479560076126, 43.65985503641159, '2077-12-15T10:06:55.635Z'), +(7.389790913568393, 44.60803754470913, '2077-12-15T10:09:00.635Z'), +(12.420666482639604, 6.201401783828672, '2077-12-15T10:23:08.635Z'), +(17.741436984237616, 16.849196735513825, '2077-12-15T10:27:25.635Z'), +(10.001812270441704, 12.690518355450989, '2077-12-15T10:30:39.635Z'), +(3.5224198145678534, 16.17515688120512, '2077-12-15T10:33:22.635Z'), +(21.67565853590177, 29.49459453781084, '2077-12-15T10:41:37.635Z'), +(0.09322629120268927, 23.019104436709746, '2077-12-15T10:49:57.635Z'), +(22.739014046795567, 46.18412094627806, '2077-12-15T11:01:47.635Z'), +(15.699188517903448, 43.16353299068738, '2077-12-15T11:04:35.635Z'), +(19.519925988894233, 9.980029242382441, '2077-12-15T11:16:22.635Z'), +(4.654969804109149, 28.38846935797307, '2077-12-15T11:25:00.635Z'), +(17.377549463474097, 34.30774912968084, '2077-12-15T11:30:10.635Z'), +(3.0917933263689834, 41.445332452717444, '2077-12-15T11:36:03.635Z'), +(16.17394272662789, 49.97118788935251, '2077-12-15T11:41:48.635Z'), +(10.877185330557909, 41.846715040740996, '2077-12-15T11:45:19.635Z'), +(11.580251271515436, 48.2387235365327, '2077-12-15T11:47:39.635Z'), +(5.669588154392655, 33.518161372828004, '2077-12-15T11:53:28.635Z'), +(9.553297440912, 26.861346234753835, '2077-12-15T11:56:18.635Z'), +(2.1818606645137457, 46.460263010829145, '2077-12-15T12:04:01.635Z'), +(1.878259669597389, 16.037832841563915, '2077-12-15T12:15:17.635Z'), +(15.108495977030055, 17.206724598933395, '2077-12-15T12:20:12.635Z'), +(0.6970731158560365, 4.753258314994778, '2077-12-15T12:27:13.635Z'), +(23.03160923554472, 12.532790536780436, '2077-12-15T12:35:57.635Z'), +(15.879177735482727, 28.108010148378135, '2077-12-15T12:41:59.635Z'), +(2.812573744089946, 22.960756821527198, '2077-12-15T12:47:10.635Z'), +(23.29194884885562, 7.091170583521143, '2077-12-15T12:56:39.635Z'), +(21.89054673871332, 29.584742699201815, '2077-12-15T13:04:21.635Z'), +(2.642633200696124, 19.154361458294304, '2077-12-15T13:12:24.635Z'), +(5.324331017853871, 34.21675377246217, '2077-12-15T13:18:03.635Z'), +(22.805149889418512, 7.375022516518013, '2077-12-15T13:29:37.635Z'), +(9.654877245125569, 8.60098941573007, '2077-12-15T13:34:30.635Z'), +(2.4290749369235236, 25.471266116080788, '2077-12-15T13:41:15.635Z'), +(23.402881235474563, 16.635156984908434, '2077-12-15T13:49:38.635Z'), +(7.79117215392679, 29.20285858392392, '2077-12-15T13:56:56.635Z'), +(17.365802248468416, 21.592484088288742, '2077-12-15T14:01:25.635Z'), +(1.345150619097056, 47.43273708184066, '2077-12-15T14:12:32.635Z'), +(11.458717783781188, 8.751723792512205, '2077-12-15T14:27:14.635Z'), +(2.1899614484579493, 41.889577560344414, '2077-12-15T14:39:53.635Z'), +(20.005630300906322, 46.75640272710295, '2077-12-15T14:46:43.635Z'), +(9.045579171276087, 12.676808106373374, '2077-12-15T14:59:34.635Z'), +(18.55858946830751, 46.14788080984651, '2077-12-15T15:12:05.635Z'), +(22.145875659033695, 47.97968187857285, '2077-12-15T15:13:33.635Z'), +(16.223520565176685, 12.122176166847732, '2077-12-15T15:26:15.635Z'), +(16.70351521569582, 6.091998252981842, '2077-12-15T15:28:24.635Z'), +(0.37167415095784256, 0.04640632770709027, '2077-12-15T15:34:50.635Z'), +(9.732041883630634, 42.714262942391855, '2077-12-15T15:50:56.635Z'), +(1.3149721622725414, 47.546465427383104, '2077-12-15T15:54:31.635Z'), +(12.750758525488887, 46.57413275171788, '2077-12-15T15:58:46.635Z'), +(22.846200644910557, 10.78391598018547, '2077-12-15T16:11:54.635Z'), +(14.890583323124277, 3.601050580927774, '2077-12-15T16:15:46.635Z'), +(11.517246421007279, 41.411981187794844, '2077-12-15T16:29:27.635Z'), +(2.9694080605376514, 12.545122190633643, '2077-12-15T16:40:30.635Z'), +(2.8874102634006253, 23.23919368943123, '2077-12-15T16:44:27.635Z'), +(18.86659903690921, 6.3566062803341445, '2077-12-15T16:52:58.635Z'), +(4.771696930031024, 44.703648507925266, '2077-12-15T17:07:46.635Z'), +(3.059075565771308, 3.204554598305848, '2077-12-15T17:23:07.635Z'), +(13.894027168790279, 0.37052264560038317, '2077-12-15T17:27:15.635Z'), +(12.456655113190653, 40.00225467030331, '2077-12-15T17:41:32.635Z'), +(20.18523133902464, 47.7607413874903, '2077-12-15T17:45:30.635Z'), +(1.7377196146591136, 44.296745382771356, '2077-12-15T17:52:27.635Z'), +(22.689753375450163, 16.781229794262984, '2077-12-15T18:05:01.635Z'), +(18.975259237150144, 44.18023892523524, '2077-12-15T18:14:35.635Z'), +(14.510483323152037, 26.9853789171041, '2077-12-15T18:20:54.635Z'), +(11.940230604296536, 32.94345381063142, '2077-12-15T18:23:15.635Z'), +(9.387884729959616, 10.17320553163251, '2077-12-15T18:31:35.635Z'), +(6.11601719249227, 48.18579570370459, '2077-12-15T18:45:35.635Z'), +(14.541954657850036, 11.758184714438663, '2077-12-15T18:59:12.635Z'), +(7.806897195581825, 20.03235585625782, '2077-12-15T19:03:06.635Z'), +(22.363848650261414, 46.535377638745345, '2077-12-15T19:13:58.635Z'), +(1.1093997490759195, 45.406653646303866, '2077-12-15T19:21:51.635Z'), +(6.248221024689449, 10.051503180156056, '2077-12-15T19:35:03.635Z'), +(7.138851367392185, 19.687394993879252, '2077-12-15T19:38:36.635Z'), +(9.246324483807811, 21.149305448736893, '2077-12-15T19:39:32.635Z'), +(2.276877758822833, 45.127394690019194, '2077-12-15T19:48:44.635Z'), +(13.006113739044082, 7.950834643291088, '2077-12-15T20:02:55.635Z'), +(14.763140450845096, 29.572157082423896, '2077-12-15T20:10:43.635Z'), +(0.04676049467212553, 49.00592728278716, '2077-12-15T20:19:41.635Z'), +(4.996859896429775, 25.323189284653726, '2077-12-15T20:28:38.635Z'), +(9.186840438422768, 32.885007608784065, '2077-12-15T20:31:49.635Z'), +(19.531402991726722, 11.139433936365412, '2077-12-15T20:40:30.635Z'), +(2.077598101176744, 1.4779501865356774, '2077-12-15T20:47:51.635Z'), +(4.806925609248898, 0.868429391322911, '2077-12-15T20:48:53.635Z'), +(13.334270495086987, 42.33974425335633, '2077-12-15T21:04:21.635Z'), +(21.20263343958032, 42.00300215285301, '2077-12-15T21:07:16.635Z'), +(7.6485989423522875, 45.05144490078657, '2077-12-15T21:12:24.635Z'), +(8.01243104369363, 45.41087419153434, '2077-12-15T21:12:35.635Z'), +(22.291099663186554, 36.538050150458155, '2077-12-15T21:18:44.635Z'), +(17.263669839679153, 1.475885004009741, '2077-12-15T21:31:04.635Z'), +(23.127545467185463, 34.60447324073389, '2077-12-15T21:42:46.635Z'), +(0.8278862539960208, 30.617543234718617, '2077-12-15T21:51:09.635Z'), +(2.992801039943734, 38.84741821517965, '2077-12-15T21:54:18.635Z'), +(9.970192146594412, 35.663287628855954, '2077-12-15T21:57:08.635Z'), +(15.481332342753232, 7.762739429322793, '2077-12-15T22:07:24.635Z'), +(5.344386545672187, 0.10821065404652996, '2077-12-15T22:12:04.635Z'), +(0.031313401498356735, 12.549925658200937, '2077-12-15T22:17:04.635Z'), +(11.386769933813051, 31.20554249697425, '2077-12-15T22:25:07.635Z'), +(8.508384903555266, 25.64478828840149, '2077-12-15T22:27:24.635Z'), +(8.86693553800573, 3.360557254736159, '2077-12-15T22:35:33.635Z'), +(23.553468829073328, 17.279439202166397, '2077-12-15T22:42:53.635Z'), +(1.1148904329710136, 22.653932380657128, '2077-12-15T22:51:25.635Z'), +(19.553266602956224, 12.751215005262734, '2077-12-15T22:59:08.635Z'), +(23.51003109053688, 26.90601732591529, '2077-12-15T23:04:13.635Z'), +(20.914061064446795, 12.304623485514039, '2077-12-15T23:09:18.635Z'), +(17.802938401249346, 0.5714087335668433, '2077-12-15T23:13:33.635Z'), +(11.050905487286428, 9.813201885562389, '2077-12-15T23:17:42.635Z'), +(21.57494603832203, 14.962069937622037, '2077-12-15T23:22:00.635Z'), +(7.553134428730774, 24.485456734809016, '2077-12-15T23:28:12.635Z'), +(22.571551174092896, 42.64722958070669, '2077-12-15T23:36:44.635Z'), +(10.63532865845405, 22.017651595752284, '2077-12-15T23:45:16.635Z'), +(11.12323085124478, 23.070535981991842, '2077-12-15T23:45:41.635Z'), +(0.08747027887978054, 40.52340170996075, '2077-12-15T23:53:18.635Z'), +(18.180064679607376, 16.20034993826464, '2077-12-16T00:04:24.635Z'), +(17.69675259888766, 17.95874629015724, '2077-12-16T00:05:02.635Z'), +(20.73593278578359, 18.47601482550794, '2077-12-16T00:06:10.635Z'), +(3.705860331243802, 14.344433346626948, '2077-12-16T00:12:39.635Z'), +(9.303629770059962, 34.48629674266756, '2077-12-16T00:20:20.635Z'), +(2.028711792417773, 1.846252440836107, '2077-12-16T00:32:39.635Z'), +(3.6338812591008773, 5.695666171406534, '2077-12-16T00:34:11.635Z'), +(12.723990702927649, 47.03222405107892, '2077-12-16T00:49:41.635Z'), +(4.4415703868194845, 32.40789374961504, '2077-12-16T00:55:51.635Z'), +(22.231179167810797, 21.90575378599449, '2077-12-16T01:03:26.635Z'), +(10.086423206812988, 17.524721711596538, '2077-12-16T01:08:11.635Z'), +(19.78264880663673, 11.59189347640203, '2077-12-16T01:12:21.635Z'), +(17.65077186262933, 11.081447474126614, '2077-12-16T01:13:09.635Z'), +(19.2277438940719, 43.08140692387957, '2077-12-16T01:24:24.635Z'), +(13.470859644391593, 19.927603258528702, '2077-12-16T01:32:53.635Z'), +(1.7688123465134156, 38.14028022574728, '2077-12-16T01:40:50.635Z'), +(5.608241167750468, 5.60188670364332, '2077-12-16T01:52:56.635Z'), +(2.2688450959405984, 1.874966201351204, '2077-12-16T01:54:47.635Z'), +(7.011221828375036, 2.38114878901213, '2077-12-16T01:56:33.635Z'), +(3.3791134750894947, 45.461345439558286, '2077-12-16T02:12:30.635Z'), +(13.926726451744008, 47.76310352168856, '2077-12-16T02:16:29.635Z'), +(3.491851920563361, 22.46436497424654, '2077-12-16T02:26:30.635Z'), +(23.1440132301921, 38.79281996783873, '2077-12-16T02:35:50.635Z'), +(12.285134758130196, 44.156697883702115, '2077-12-16T02:40:16.635Z'), +(18.230530753509004, 8.338629781649601, '2077-12-16T02:53:14.635Z'), +(1.415471651256541, 17.716022275298414, '2077-12-16T03:00:20.635Z'), +(4.124148917487258, 0.30726577468682187, '2077-12-16T03:06:51.635Z'), +(0.5269445137961041, 12.060226281240476, '2077-12-16T03:11:24.635Z'), +(7.669671768514651, 35.36064994783053, '2077-12-16T03:20:24.635Z'), +(13.299766668111351, 48.90054033287998, '2077-12-16T03:25:45.635Z'), +(6.09536597171339, 43.40544987070851, '2077-12-16T03:29:05.635Z'), +(10.639183585885922, 44.73043309667608, '2077-12-16T03:30:50.635Z'), +(1.8184527716873566, 42.30013102013566, '2077-12-16T03:34:13.635Z'), +(9.158459325146232, 7.93519821722361, '2077-12-16T03:47:10.635Z'), +(14.173163065045092, 49.172946066309635, '2077-12-16T04:02:13.635Z'), +(14.809978237225248, 14.1077533285234, '2077-12-16T04:14:47.635Z'), +(4.092688200169854, 31.294279829809, '2077-12-16T04:22:12.635Z'), +(9.975380518847947, 3.884785793690326, '2077-12-16T04:32:30.635Z'), +(3.281858190457069, 43.8886232502113, '2077-12-16T04:47:25.635Z'), +(12.071859659256356, 14.016694176306299, '2077-12-16T04:58:50.635Z'), +(2.252936851386181, 11.507085545450844, '2077-12-16T05:02:35.635Z'), +(13.423161965236355, 12.308591650951566, '2077-12-16T05:06:44.635Z'), +(11.064780133976265, 34.75165147690431, '2077-12-16T05:14:54.635Z'), +(3.457167989038334, 46.09119614175096, '2077-12-16T05:19:55.635Z'), +(8.566252274176072, 8.434145017465486, '2077-12-16T05:33:55.635Z'), +(11.265821038687049, 45.549085424144344, '2077-12-16T05:47:29.635Z'), +(7.102664549971442, 28.77197894372477, '2077-12-16T05:53:48.635Z'), +(13.364231424968473, 37.20784568110716, '2077-12-16T05:57:39.635Z'), +(21.897185522123397, 18.243267672171108, '2077-12-16T06:05:02.635Z'), +(12.573941485285816, 41.89302258022774, '2077-12-16T06:14:04.635Z'), +(1.2248017889267016, 2.8677548291098875, '2077-12-16T06:29:00.635Z'), +(6.552845947935769, 40.54699040179587, '2077-12-16T06:43:03.635Z'), +(5.254624563069044, 15.002943557149276, '2077-12-16T06:52:28.635Z'), +(16.63181390841731, 30.420765466726852, '2077-12-16T06:59:28.635Z'), +(22.641380630052694, 9.696711001222226, '2077-12-16T07:07:01.635Z'), +(15.174900442559851, 38.43501085737943, '2077-12-16T07:17:26.635Z'), +(3.6519882047589753, 39.44360319758316, '2077-12-16T07:21:43.635Z'), +(9.174459459020547, 26.775351168451962, '2077-12-16T07:26:48.635Z'), +(17.146702357174412, 35.51834807360153, '2077-12-16T07:31:07.635Z'), +(16.36936135705426, 8.719003550249683, '2077-12-16T07:40:37.635Z'), +(8.29045119414841, 42.20033130276234, '2077-12-16T07:53:05.635Z'), +(0.447948887957716, 26.896986649755657, '2077-12-16T07:59:26.635Z'), +(0.5237746987701944, 35.64919193871637, '2077-12-16T08:02:40.635Z'), +(23.006993198514582, 3.1987848947013844, '2077-12-16T08:17:00.635Z'), +(10.460630568818283, 3.632585397691167, '2077-12-16T08:21:39.635Z'), +(18.663265515585113, 20.403710237623883, '2077-12-16T08:28:23.635Z'), +(22.98607228325581, 47.613150117896, '2077-12-16T08:37:55.635Z'), +(22.576455321285994, 21.194600982726897, '2077-12-16T08:46:56.635Z'), +(0.6507250846226253, 24.928874418925023, '2077-12-16T08:55:10.635Z'), +(18.76825988801757, 44.03650267966789, '2077-12-16T09:04:49.635Z'), +(19.668847964068124, 32.256741858107354, '2077-12-16T09:08:57.635Z'), +(20.609025274216012, 8.301767278762274, '2077-12-16T09:17:17.635Z'), +(12.418645000244654, 49.25918670244894, '2077-12-16T09:32:06.635Z'), +(0.6810849885188063, 32.206491376348296, '2077-12-16T09:39:43.635Z'), +(5.728132522820917, 5.0360326406361455, '2077-12-16T09:49:56.635Z'), +(20.405328886141206, 11.224640234380445, '2077-12-16T09:55:48.635Z'), +(6.658233093900076, 46.01232556652058, '2077-12-16T10:09:17.635Z'), +(21.890204353310466, 19.52148126700098, '2077-12-16T10:20:18.635Z'), +(15.21000415742495, 38.192424673011196, '2077-12-16T10:27:18.635Z'), +(7.753681120315987, 45.255257014680005, '2077-12-16T10:31:04.635Z'), +(17.064769951742356, 6.403503413165269, '2077-12-16T10:45:31.635Z'), +(7.269923437560765, 17.883790364934057, '2077-12-16T10:51:01.635Z'), +(23.34565243525918, 30.93829038794075, '2077-12-16T10:58:34.635Z'), +(13.541847262643447, 15.078541275219177, '2077-12-16T11:05:12.635Z'), +(4.3790813850090915, 41.370045935373625, '2077-12-16T11:15:23.635Z'), +(23.213183646856525, 40.48944301416079, '2077-12-16T11:22:22.635Z'), +(9.274907387779988, 5.593484274726529, '2077-12-16T11:35:45.635Z'), +(3.816424604503895, 29.53621423243663, '2077-12-16T11:44:47.635Z'), +(9.965721709782873, 43.795849109972984, '2077-12-16T11:50:30.635Z'), +(22.342502087205336, 34.53977164604677, '2077-12-16T11:56:08.635Z'), +(15.459000275554533, 33.06205114593853, '2077-12-16T11:58:44.635Z'), +(3.8368508643706596, 25.291742223058176, '2077-12-16T12:03:53.635Z'), +(4.901048207719013, 33.26879409155055, '2077-12-16T12:06:51.635Z'), +(18.52431763608249, 48.206613544180435, '2077-12-16T12:14:14.635Z'), +(3.696141265193716, 6.6288377256999675, '2077-12-16T12:30:15.635Z'), +(7.179530819850902, 36.246072711227036, '2077-12-16T12:41:15.635Z'), +(6.73296094193293, 18.99694123567906, '2077-12-16T12:47:35.635Z'), +(1.3240281467750186, 43.931954991510814, '2077-12-16T12:57:00.635Z'), +(5.641604159502586, 39.07851444505198, '2077-12-16T12:59:24.635Z'), +(17.88986679311594, 27.49031232060294, '2077-12-16T13:05:34.635Z'), +(22.274609049564546, 27.831225254422222, '2077-12-16T13:07:11.635Z'), +(20.22734465417441, 42.433097225795876, '2077-12-16T13:12:16.635Z'), +(12.484480978417752, 15.16560284261529, '2077-12-16T13:22:21.635Z'), +(12.977917860843474, 17.8977081186715, '2077-12-16T13:23:21.635Z'), +(14.961907039690693, 9.605792432528515, '2077-12-16T13:26:25.635Z'), +(12.763558980319553, 42.503170081983725, '2077-12-16T13:38:16.635Z'), +(13.657163880841855, 21.222395975746554, '2077-12-16T13:45:57.635Z'), +(0.8145051146472119, 47.61799978917976, '2077-12-16T13:56:44.635Z'), +(6.078047082881148, 20.273612675991505, '2077-12-16T14:07:01.635Z'), +(17.194359043156435, 18.425610037726425, '2077-12-16T14:11:11.635Z'), +(11.689102275933584, 45.17706607368983, '2077-12-16T14:20:59.635Z'), +(19.040766063044085, 25.72151347729975, '2077-12-16T14:28:26.635Z'), +(23.174112806857902, 30.80539636167489, '2077-12-16T14:30:45.635Z'), +(12.08022749381597, 47.92013405517567, '2077-12-16T14:38:02.635Z'), +(22.57913898700916, 45.388889807200876, '2077-12-16T14:42:01.635Z'), +(22.98723947994977, 41.90067255051506, '2077-12-16T14:43:13.635Z'), +(2.160356170082135, 35.08168509158087, '2077-12-16T14:51:18.635Z'), +(4.416591546806214, 22.069795208912783, '2077-12-16T14:56:11.635Z'), +(0.4747533903669317, 16.7003935891304, '2077-12-16T14:58:39.635Z'), +(7.977745614346448, 42.242315480816096, '2077-12-16T15:08:29.635Z'), +(15.449493757163117, 29.080980196337826, '2077-12-16T15:14:00.635Z'), +(9.544681836189602, 6.4036854337895575, '2077-12-16T15:22:29.635Z'), +(17.65046069499453, 25.651208521812592, '2077-12-16T15:30:01.635Z'), +(17.0692987034508, 15.660236952310008, '2077-12-16T15:33:33.635Z'), +(14.021923243030841, 45.345858570775775, '2077-12-16T15:44:12.635Z'), +(9.146173125407453, 6.85884187931843, '2077-12-16T15:58:16.635Z'), +(21.555547328441097, 5.0096180679029025, '2077-12-16T16:02:54.635Z'), +(4.438822006009082, 4.362257236544151, '2077-12-16T16:09:14.635Z'), +(23.113290805409907, 5.240399248906376, '2077-12-16T16:16:09.635Z'), +(20.55157192463396, 21.37956509046554, '2077-12-16T16:21:46.635Z'), +(23.282160186219002, 14.558096476183996, '2077-12-16T16:24:19.635Z'), +(21.698513958262282, 43.49571738214102, '2077-12-16T16:34:13.635Z'), +(21.45082471892403, 9.098296132988061, '2077-12-16T16:46:02.635Z'), +(7.579168834279065, 15.12380636559101, '2077-12-16T16:51:36.635Z'), +(1.0884618720097057, 17.651683348981965, '2077-12-16T16:54:10.635Z'), +(2.3563133359836685, 42.97777119225969, '2077-12-16T17:03:33.635Z'), +(18.53231054979056, 1.3990076807714724, '2077-12-16T17:19:47.635Z'), +(9.717199226176165, 19.144106604110473, '2077-12-16T17:26:56.635Z'), +(1.5568669249763167, 13.327126310341143, '2077-12-16T17:30:38.635Z'), +(8.188242431720726, 2.5329368036139344, '2077-12-16T17:35:18.635Z'), +(10.818317619664445, 45.10568322250093, '2077-12-16T17:50:52.635Z'), +(11.976100240945444, 9.584402227675822, '2077-12-16T18:03:46.635Z'), +(4.3727246785560645, 20.24709808690717, '2077-12-16T18:08:35.635Z'), +(4.866162147192667, 39.593198618812025, '2077-12-16T18:15:43.635Z'), +(14.825632110787902, 34.316386152843485, '2077-12-16T18:19:52.635Z'), +(1.6659069394778616, 12.166259555691983, '2077-12-16T18:29:19.635Z'), +(7.6596959141502055, 41.95547330776025, '2077-12-16T18:40:32.635Z'), +(9.357534299383387, 30.991272882358956, '2077-12-16T18:44:36.635Z'), +(14.385970087095, 10.04950252210194, '2077-12-16T18:52:25.635Z'), +(21.567808422630105, 38.802876513263826, '2077-12-16T19:02:52.635Z'), +(20.688384618800498, 27.760765792670735, '2077-12-16T19:06:41.635Z'), +(17.897802300527047, 5.832741665629739, '2077-12-16T19:14:25.635Z'), +(2.3793756611167556, 46.89743832403782, '2077-12-16T19:30:24.635Z'), +(8.859278953060597, 21.23601669083865, '2077-12-16T19:40:09.635Z'), +(8.369148860278555, 27.89293219248466, '2077-12-16T19:42:35.635Z'), +(16.678171127489858, 42.208152414928215, '2077-12-16T19:48:36.635Z'), +(14.854839561257222, 14.453549474570783, '2077-12-16T19:58:30.635Z'), +(5.181500969147738, 36.686677518997264, '2077-12-16T20:07:21.635Z'), +(9.00888392377854, 47.14125452755868, '2077-12-16T20:11:26.635Z'), +(18.039718275481587, 45.864269982435424, '2077-12-16T20:14:48.635Z'), +(8.207249174476265, 19.92553688016706, '2077-12-16T20:24:49.635Z'), +(19.500522390716963, 0.7694279079998099, '2077-12-16T20:32:52.635Z'), +(22.74047630260299, 48.22710948616139, '2077-12-16T20:49:15.635Z'), +(4.583885921019883, 12.915069882816896, '2077-12-16T21:03:34.635Z'), +(2.5832432199351882, 30.57164485519627, '2077-12-16T21:10:08.635Z'), +(2.9052772519606016, 32.298127410049304, '2077-12-16T21:10:47.635Z'), +(15.38213741882568, 28.33052200247984, '2077-12-16T21:15:37.635Z'), +(12.472881987454212, 18.4389909879587, '2077-12-16T21:19:20.635Z'), +(23.269206613400403, 34.10986351932808, '2077-12-16T21:26:08.635Z'), +(22.751287890885582, 14.484051541665643, '2077-12-16T21:32:49.635Z'), +(13.78551947925464, 32.37677852011511, '2077-12-16T21:39:55.635Z'), +(2.090989869314648, 21.20981006147294, '2077-12-16T21:45:52.635Z'), +(19.118190972729085, 24.79847748077896, '2077-12-16T21:52:18.635Z'), +(22.361423463619815, 7.609182445565213, '2077-12-16T21:58:22.635Z'), +(21.70718650004394, 32.65815889279111, '2077-12-16T22:06:57.635Z'), +(18.698811880991045, 25.860456150118903, '2077-12-16T22:09:33.635Z'), +(2.7068650262422302, 7.0724178298566525, '2077-12-16T22:18:35.635Z'), +(14.63706261048899, 47.45261676961459, '2077-12-16T22:33:59.635Z'), +(13.793208824015881, 8.084561144538482, '2077-12-16T22:48:06.635Z'), +(2.4605991817514057, 6.1472289498912716, '2077-12-16T22:52:21.635Z'), +(6.331727123296281, 11.748715505039646, '2077-12-16T22:54:52.635Z'), +(5.295558330053268, 34.90462130034202, '2077-12-16T23:03:24.635Z'), +(7.548053434882665, 36.093812358863175, '2077-12-16T23:04:20.635Z'), +(22.624771359783907, 29.2519302701075, '2077-12-16T23:10:25.635Z'), +(6.296602832201792, 19.935053721280475, '2077-12-16T23:17:19.635Z'), +(3.1356963783880114, 18.376897554147703, '2077-12-16T23:18:37.635Z'), +(7.600077513303613, 49.88556228270636, '2077-12-16T23:30:21.635Z'), +(3.2183288640650933, 13.53347901082083, '2077-12-16T23:43:51.635Z'), +(21.71247027966512, 43.45689072396192, '2077-12-16T23:56:36.635Z'), +(7.024225843325252, 18.847259845074134, '2077-12-17T00:06:57.635Z'), +(14.88673350909478, 50.218293842000435, '2077-12-17T00:18:43.635Z'), +(12.567211059457028, 11.55830946855858, '2077-12-17T00:32:38.635Z'), +(13.21853382331914, 34.59086765548505, '2077-12-17T00:40:57.635Z'), +(15.2808064122629, 13.525327820060724, '2077-12-17T00:48:33.635Z'), +(17.287962317525256, 32.98096400914172, '2077-12-17T00:55:30.635Z'), +(12.492165406244107, 16.530729363741045, '2077-12-17T01:01:39.635Z'), +(9.798148053214009, 18.864372107908178, '2077-12-17T01:02:57.635Z'), +(22.614002418755085, 34.82875914154997, '2077-12-17T01:10:20.635Z'), +(12.955110668566851, 35.381205070191605, '2077-12-17T01:13:55.635Z'), +(0.8304388268902234, 4.850494557134838, '2077-12-17T01:25:59.635Z'), +(15.872471794219397, 25.844789260992698, '2077-12-17T01:35:28.635Z'), +(21.276482422493743, 21.35877387769358, '2077-12-17T01:38:00.635Z'), +(20.072561945871062, 45.967844840384736, '2077-12-17T01:46:32.635Z'), +(13.6756944840466, 37.666873944798795, '2077-12-17T01:50:18.635Z'), +(3.542821306552215, 1.586132577338506, '2077-12-17T02:04:01.635Z'), +(18.061424664512874, 17.515001443683726, '2077-12-17T02:11:54.635Z'), +(20.045857909321587, 0.1552247544162182, '2077-12-17T02:18:01.635Z'), +(14.269866199785923, 34.011094135507975, '2077-12-17T02:30:10.635Z'), +(4.9780991909625065, 41.12345664241985, '2077-12-17T02:34:28.635Z'), +(18.410334180283545, 13.375321307619876, '2077-12-17T02:45:40.635Z'), +(5.615393926357847, 33.126875048718034, '2077-12-17T02:54:14.635Z'), +(17.92506694228089, 45.43360129282344, '2077-12-17T03:00:36.635Z'), +(3.889677022740395, 16.096774314685604, '2077-12-17T03:12:26.635Z'), +(22.00536778306556, 17.221608736747044, '2077-12-17T03:19:09.635Z'), +(14.095376331003587, 38.8084919423674, '2077-12-17T03:27:17.635Z'), +(20.97232814678284, 23.122432233705833, '2077-12-17T03:33:22.635Z'), +(0.44395240496284144, 17.15296478145362, '2077-12-17T03:41:16.635Z'), +(9.333350603158122, 25.173262720978904, '2077-12-17T03:45:41.635Z'), +(6.470207592709051, 49.31161679820653, '2077-12-17T03:54:36.635Z'), +(13.898050490306419, 22.368129793560367, '2077-12-17T04:04:47.635Z'), +(17.061844349298084, 19.9053906083621, '2077-12-17T04:06:14.635Z'), +(14.772876268707936, 13.792025344342077, '2077-12-17T04:08:34.635Z'), +(16.849898204583734, 11.441052966007694, '2077-12-17T04:09:42.635Z'), +(7.632077512724295, 19.297083868928652, '2077-12-17T04:14:08.635Z'), +(16.209103620789975, 41.66613094688798, '2077-12-17T04:22:50.635Z'), +(22.906733736787817, 48.64305562155805, '2077-12-17T04:26:18.635Z'), +(22.03706334212069, 14.389111221939286, '2077-12-17T04:38:00.635Z'), +(0.1514371751833624, 35.034142451685156, '2077-12-17T04:49:01.635Z'), +(10.2443404729707, 22.526955611921778, '2077-12-17T04:54:57.635Z'), +(23.480057469020288, 16.674114890247736, '2077-12-17T05:00:16.635Z'), +(22.20220864768098, 27.582197189064278, '2077-12-17T05:04:01.635Z'), +(1.0617197307051631, 35.75974813817238, '2077-12-17T05:12:23.635Z'), +(4.040841395850052, 43.483029919838295, '2077-12-17T05:15:26.635Z'), +(7.106599127835286, 37.128647130395926, '2077-12-17T05:18:02.635Z'), +(13.726694593170771, 17.24649835685699, '2077-12-17T05:25:40.635Z'), +(23.25187237323009, 24.735064874880976, '2077-12-17T05:30:04.635Z'), +(12.135264583652129, 34.703561568638946, '2077-12-17T05:35:28.635Z'), +(2.2239560804408196, 7.630125270234651, '2077-12-17T05:46:03.635Z'), +(19.334749275013586, 17.679441287336584, '2077-12-17T05:53:21.635Z'), +(22.02125534412793, 35.71853819831303, '2077-12-17T05:59:40.635Z'), +(12.723300135353606, 22.514585260935505, '2077-12-17T06:05:27.635Z'), +(19.793240770719684, 38.61830550734639, '2077-12-17T06:11:44.635Z'), +(7.703138227445383, 25.993355073054705, '2077-12-17T06:18:06.635Z'), +(5.256445201642245, 32.67872842214235, '2077-12-17T06:20:43.635Z'), +(18.739105896194875, 16.01852508683646, '2077-12-17T06:28:32.635Z'), +(18.95885690862697, 6.490411299678096, '2077-12-17T06:31:52.635Z'), +(12.603912254169591, 40.604047117712206, '2077-12-17T06:44:14.635Z'), +(15.508543327838122, 41.233343394506925, '2077-12-17T06:45:20.635Z'), +(3.233300787128168, 20.235876850641617, '2077-12-17T06:54:14.635Z'), +(14.464381046324327, 31.467621000546433, '2077-12-17T07:00:04.635Z'), +(18.04541316707421, 45.3928782790756, '2077-12-17T07:05:11.635Z'), +(0.8261809022617909, 8.85337545344928, '2077-12-17T07:19:56.635Z'), +(18.017428358548177, 15.351564774990777, '2077-12-17T07:26:43.635Z'), +(9.644786515819211, 3.4597073016652926, '2077-12-17T07:31:59.635Z'), +(23.275650518935052, 2.1737280491604913, '2077-12-17T07:37:03.635Z'), +(21.201884776593307, 31.089960897490435, '2077-12-17T07:46:59.635Z'), +(15.378177733263497, 2.3028952660271074, '2077-12-17T07:57:19.635Z'), +(19.621430071753704, 28.812108050665966, '2077-12-17T08:06:48.635Z'), +(18.81665675912174, 25.25102466010388, '2077-12-17T08:08:04.635Z'), +(19.23749882415275, 17.814099849751056, '2077-12-17T08:10:40.635Z'), +(4.433982753030279, 5.104245557155185, '2077-12-17T08:17:49.635Z'), +(11.425433640487432, 50.2196126749446, '2077-12-17T08:34:33.635Z'), +(18.127188377126323, 14.896658164204979, '2077-12-17T08:47:25.635Z'), +(21.223455567884805, 35.59543427322412, '2077-12-17T08:54:43.635Z'), +(19.87769823843361, 3.089987227300431, '2077-12-17T09:05:59.635Z'), +(22.440804650062987, 22.091018446998767, '2077-12-17T09:12:36.635Z'), +(14.68925281852325, 13.571807726443028, '2077-12-17T09:16:44.635Z'), +(6.064478553511953, 16.410132687096475, '2077-12-17T09:20:05.635Z'), +(9.43560010927054, 2.0778222209809667, '2077-12-17T09:25:29.635Z'), +(10.212095687981824, 44.27833742271957, '2077-12-17T09:40:53.635Z'), +(1.9855264805752262, 5.691049657030838, '2077-12-17T09:55:24.635Z'), +(12.58832496806561, 47.93381922332273, '2077-12-17T10:11:23.635Z'), +(18.91032868270162, 28.0148421368138, '2077-12-17T10:18:51.635Z'), +(8.797735098747452, 46.441790241119634, '2077-12-17T10:26:27.635Z'), +(18.353051332669796, 0.42813600368498056, '2077-12-17T10:43:21.635Z'), +(0.7441022082445862, 31.952233196345844, '2077-12-17T10:56:32.635Z'), +(11.884038365334515, 0.9974083796401044, '2077-12-17T11:08:38.635Z'), +(14.637900899344706, 29.274543337884555, '2077-12-17T11:18:52.635Z'), +(14.692689020919222, 32.700941531672576, '2077-12-17T11:20:05.635Z'), +(14.764939561928719, 3.8557782282205935, '2077-12-17T11:30:24.635Z'), +(1.253947529373855, 28.47734407696206, '2077-12-17T11:40:42.635Z'), +(15.065003468400084, 41.6550283273097, '2077-12-17T11:47:43.635Z'), +(3.3761755375732028, 11.169658046397743, '2077-12-17T11:59:39.635Z'), +(1.5018075708023786, 8.390334107423511, '2077-12-17T12:00:53.635Z'), +(5.825237226952975, 28.03624118664275, '2077-12-17T12:08:19.635Z'), +(3.270166705308712, 28.714993635467742, '2077-12-17T12:09:17.635Z'), +(12.710199323075688, 7.409982849597678, '2077-12-17T12:17:50.635Z'), +(11.359994605688081, 22.432316836600684, '2077-12-17T12:23:18.635Z'), +(19.37032524549817, 6.696346059204721, '2077-12-17T12:29:39.635Z'), +(16.192962397532316, 35.14336218172406, '2077-12-17T12:39:44.635Z'), +(15.230643076256923, 23.250727865898817, '2077-12-17T12:43:59.635Z'), +(11.612703762127845, 36.25730565025225, '2077-12-17T12:48:51.635Z'), +(21.78610200601553, 33.76039626582323, '2077-12-17T12:52:43.635Z'), +(20.532530793345032, 7.0054383258700295, '2077-12-17T13:01:57.635Z'), +(21.806761052494487, 31.851889197927196, '2077-12-17T13:10:32.635Z'), +(16.87316906474121, 46.46650722178457, '2077-12-17T13:15:57.635Z'), +(22.60118390854372, 49.592995451804654, '2077-12-17T13:18:20.635Z'), +(3.4090353765113504, 41.67473658462273, '2077-12-17T13:25:59.635Z'), +(1.3913013417489208, 12.682069774355364, '2077-12-17T13:36:44.635Z'), +(11.444511155444173, 25.214357768401587, '2077-12-17T13:42:39.635Z'), +(21.340232278310683, 16.74267700265817, '2077-12-17T13:47:23.635Z'), +(12.57254563449146, 3.7674179004749693, '2077-12-17T13:53:00.635Z'), +(15.160126958255267, 14.032079731045402, '2077-12-17T13:56:48.635Z'), +(15.007739541238896, 30.683447564384696, '2077-12-17T14:02:45.635Z'), +(11.314921092301548, 45.287017667296475, '2077-12-17T14:08:11.635Z'), +(7.439114438620239, 1.5212865511651215, '2077-12-17T14:24:14.635Z'), +(8.127844152580298, 1.7414129650871741, '2077-12-17T14:24:30.635Z'), +(0.7383180796887163, 14.850179586085915, '2077-12-17T14:30:03.635Z'), +(5.282726539510802, 38.74350631488286, '2077-12-17T14:39:03.635Z'), +(13.61796369914881, 15.878790625055112, '2077-12-17T14:47:57.635Z'), +(14.590813129307234, 45.45405033429853, '2077-12-17T14:58:34.635Z'), +(21.43806171154002, 31.958648379221287, '2077-12-17T15:03:57.635Z'), +(15.00426841648999, 20.856660113476668, '2077-12-17T15:08:31.635Z'), +(19.305122142792435, 34.24145357583551, '2077-12-17T15:13:30.635Z'), +(7.747886957427117, 18.51132309533995, '2077-12-17T15:20:35.635Z'), +(11.458507002893928, 11.30854085618515, '2077-12-17T15:23:33.635Z'), +(10.17838205018486, 15.850928031874744, '2077-12-17T15:25:16.635Z'), +(5.122063809340809, 38.68225367536759, '2077-12-17T15:33:51.635Z'), +(11.43731099027335, 45.14853486396015, '2077-12-17T15:37:10.635Z'), +(15.94522912529849, 8.709481362804661, '2077-12-17T15:50:22.635Z'), +(16.348921823492823, 29.873724638188833, '2077-12-17T15:57:53.635Z'), +(10.796422544665784, 43.24665047348895, '2077-12-17T16:03:07.635Z'), +(14.832498220737671, 13.581802877689235, '2077-12-17T16:13:56.635Z'), +(16.478868034136912, 33.07932378400295, '2077-12-17T16:20:54.635Z'), +(0.8253886387617627, 4.785870358949104, '2077-12-17T16:32:44.635Z'), +(5.490273432820316, 38.48226591898595, '2077-12-17T16:45:19.635Z'), +(16.91136375775642, 1.2667828463156847, '2077-12-17T16:59:27.635Z'), +(0.9404239247396775, 31.890987179004803, '2077-12-17T17:12:05.635Z'), +(15.667320484898571, 2.1682918175465007, '2077-12-17T17:24:14.635Z'), +(17.250360481713646, 45.051306545509654, '2077-12-17T17:39:27.635Z'), +(21.559159243112273, 38.38518134574255, '2077-12-17T17:42:16.635Z'), +(11.430859065855405, 7.911344129852112, '2077-12-17T17:53:42.635Z'), +(6.135772667399425, 32.459576290194654, '2077-12-17T18:02:53.635Z'), +(22.233852062405848, 22.701977462687072, '2077-12-17T18:09:47.635Z'), +(3.2414829416891346, 20.32937017514603, '2077-12-17T18:16:52.635Z'), +(3.2791143476668316, 12.428220893329405, '2077-12-17T18:19:47.635Z'), +(6.976847667741808, 14.219756647493409, '2077-12-17T18:21:18.635Z'), +(6.031072430906192, 20.430974323542504, '2077-12-17T18:23:36.635Z'), +(7.099374598735429, 4.647772558845692, '2077-12-17T18:29:25.635Z'), +(3.103247468759078, 39.07898130388615, '2077-12-17T18:42:12.635Z'), +(17.381226560490234, 25.84056909271584, '2077-12-17T18:49:21.635Z'), +(11.928892853402962, 39.88428396402624, '2077-12-17T18:54:46.635Z'), +(22.84737204525417, 43.220508261945334, '2077-12-17T18:58:58.635Z'), +(14.668122895529809, 35.73786098340336, '2077-12-17T19:02:58.635Z'), +(9.771066486734336, 41.3818100565054, '2077-12-17T19:05:42.635Z'), +(10.786678145674527, 7.009838129207699, '2077-12-17T19:18:14.635Z'), +(19.51667890200393, 46.201426047424796, '2077-12-17T19:32:35.635Z'), +(9.586495874991993, 11.53002929181821, '2077-12-17T19:45:31.635Z'), +(20.505801496070276, 24.00567853787755, '2077-12-17T19:51:32.635Z'), +(15.772774043136373, 6.558133701069227, '2077-12-17T19:57:55.635Z'), +(16.446382127437218, 16.80095013090051, '2077-12-17T20:01:34.635Z'), +(13.352326337675434, 40.721298412059475, '2077-12-17T20:10:12.635Z'), +(18.707097322633008, 7.405505457029649, '2077-12-17T20:22:12.635Z'), +(3.4177240320006077, 44.74595520293687, '2077-12-17T20:36:52.635Z'), +(20.018544148019377, 21.331189122215708, '2077-12-17T20:47:19.635Z'), +(4.261626461027297, 1.4331619219550351, '2077-12-17T20:56:34.635Z'), +(20.48268251666294, 3.2402723275793734, '2077-12-17T21:02:36.635Z'), +(6.550785213394435, 3.6933564028875927, '2077-12-17T21:07:45.635Z'), +(23.02347221130201, 21.65142138971128, '2077-12-17T21:16:36.635Z'), +(15.71836131053193, 22.12740942502697, '2077-12-17T21:19:18.635Z'), +(4.9315553561702625, 8.033007343963229, '2077-12-17T21:25:48.635Z'), +(18.59949327200157, 46.123358604117584, '2077-12-17T21:40:28.635Z'), +(19.33275244236319, 17.462365470080428, '2077-12-17T21:50:30.635Z'), +(6.323673691360668, 34.31480142528479, '2077-12-17T21:58:15.635Z'), +(19.67752783311462, 16.908262374248196, '2077-12-17T22:06:14.635Z'), +(2.4910832890026833, 23.787725932001567, '2077-12-17T22:13:04.635Z'), +(22.19963380297643, 13.617884162053809, '2077-12-17T22:21:14.635Z'), +(3.525384347106968, 32.41571483324574, '2077-12-17T22:30:54.635Z'), +(12.617631109115989, 18.947905499824635, '2077-12-17T22:36:52.635Z'), +(22.072926398080384, 41.490441944165504, '2077-12-17T22:45:33.635Z'), +(20.757627266185064, 41.97265514951727, '2077-12-17T22:46:03.635Z'), +(11.97548134694478, 3.0174046904385468, '2077-12-17T23:00:14.635Z'), +(17.822020358478806, 22.481246326162562, '2077-12-17T23:07:31.635Z'), +(0.9775953369129975, 20.358186396806232, '2077-12-17T23:13:48.635Z'), +(15.483844306926732, 11.961352234769183, '2077-12-17T23:19:59.635Z'), +(18.252950684459005, 5.425529434865633, '2077-12-17T23:22:31.635Z'), +(17.314312425569696, 27.80114954262701, '2077-12-17T23:30:25.635Z'), +(19.8387669090162, 16.82809433999351, '2077-12-17T23:34:22.635Z'), +(17.5736161337325, 25.055552481598664, '2077-12-17T23:37:22.635Z'), +(9.629925710528216, 8.33431020566603, '2077-12-17T23:44:03.635Z'), +(5.139028756097973, 29.923169738675742, '2077-12-17T23:52:09.635Z'), +(14.066651934944627, 21.00489144690948, '2077-12-17T23:56:47.635Z'), +(4.723717793773889, 33.73817923545275, '2077-12-18T00:02:34.635Z'), +(2.9778931986377253, 20.554039485249536, '2077-12-18T00:07:29.635Z'), +(15.696088326943125, 48.95692791451937, '2077-12-18T00:18:52.635Z'), +(15.511197568691276, 48.60255966024209, '2077-12-18T00:19:00.635Z'), +(4.589356664524186, 40.43091464252643, '2077-12-18T00:24:01.635Z'), +(18.46252872273335, 0.8753712685486604, '2077-12-18T00:39:13.635Z'), +(20.57156566454269, 15.134340504937997, '2077-12-18T00:44:15.635Z'), +(15.777546248990776, 50.049822444939046, '2077-12-18T00:56:38.635Z'), +(16.83455095925053, 9.439406931269872, '2077-12-18T01:11:03.635Z'), +(16.613750414778114, 48.3006242952649, '2077-12-18T01:24:49.635Z'), +(10.552983701788579, 0.5061211027031987, '2077-12-18T01:42:08.635Z'), +(23.347789966657057, 19.977933236775502, '2077-12-18T01:50:29.635Z'), +(18.728085049348074, 16.90868723602972, '2077-12-18T01:52:29.635Z'), +(9.245009162029694, 22.270620477138838, '2077-12-18T01:56:29.635Z'), +(3.716548791586923, 29.580472608209767, '2077-12-18T01:59:51.635Z'), +(16.356400686000786, 23.794129949734337, '2077-12-18T02:04:59.635Z'), +(8.18277559785404, 12.842210939687078, '2077-12-18T02:09:58.635Z'), +(8.365522841172252, 18.622399295454226, '2077-12-18T02:12:05.635Z'), +(5.669665441533591, 26.490398451355134, '2077-12-18T02:15:08.635Z'), +(13.230383085229798, 12.524289210974304, '2077-12-18T02:20:57.635Z'), +(1.242943544566506, 35.523508923792136, '2077-12-18T02:30:29.635Z'), +(15.619150844169363, 18.45991624004148, '2077-12-18T02:38:41.635Z'), +(0.7253947388310874, 23.722848712573857, '2077-12-18T02:44:31.635Z'), +(0.5916773355271083, 9.735243049858857, '2077-12-18T02:49:42.635Z'), +(1.7150092689318097, 33.903636371615626, '2077-12-18T02:58:39.635Z'), +(13.048438226439174, 14.868837405719795, '2077-12-18T03:06:48.635Z'), +(20.172521217461902, 34.22311548698982, '2077-12-18T03:14:09.635Z'), +(21.093177620931858, 26.981897163199346, '2077-12-18T03:16:41.635Z'), +(9.223748426244535, 9.31652627868569, '2077-12-18T03:24:22.635Z'), +(4.579828315162488, 1.2997622141997065, '2077-12-18T03:27:46.635Z'), +(9.746949615096833, 22.661296439555432, '2077-12-18T03:35:50.635Z'), +(18.78297439148394, 44.188675663781545, '2077-12-18T03:44:14.635Z'), +(0.1934829593072347, 8.123600579726947, '2077-12-18T03:59:02.635Z'), +(6.518239183395233, 39.98628205778207, '2077-12-18T04:11:02.635Z'), +(9.349125485620066, 44.94702698508102, '2077-12-18T04:13:08.635Z'), +(15.027964643349415, 15.75780485179794, '2077-12-18T04:23:54.635Z'), +(5.44890210149352, 47.79518535004202, '2077-12-18T04:36:05.635Z'), +(13.965442718347289, 46.41147541543563, '2077-12-18T04:39:16.635Z'), +(9.239122802377032, 26.113758877853023, '2077-12-18T04:46:50.635Z'), +(9.737608776691523, 1.260922719622295, '2077-12-18T04:55:55.635Z'), +(11.589879613229888, 24.055423121247046, '2077-12-18T05:04:14.635Z'), +(10.668717192045543, 25.001098757212628, '2077-12-18T05:04:43.635Z'), +(20.506144906981834, 17.27898455703861, '2077-12-18T05:09:17.635Z'), +(9.735991998446048, 36.579095999008096, '2077-12-18T05:17:14.635Z'), +(17.825443365856632, 3.846322593124699, '2077-12-18T05:29:22.635Z'), +(3.8977794957291945, 10.317458107632685, '2077-12-18T05:35:02.635Z'), +(21.801548021301443, 39.85399867634515, '2077-12-18T05:47:33.635Z'), +(2.246601791133855, 48.345245963635996, '2077-12-18T05:55:25.635Z'), +(4.2169954281636235, 9.608547628360062, '2077-12-18T06:09:46.635Z'), +(7.514941641630563, 41.01013023570726, '2077-12-18T06:21:24.635Z'), +(5.042608443222828, 4.832973820007852, '2077-12-18T06:34:45.635Z'), +(15.064425771258017, 22.180614805474015, '2077-12-18T06:42:04.635Z'), +(18.436203706478477, 5.644300303717337, '2077-12-18T06:48:03.635Z'), +(19.698327439945146, 47.87030360308491, '2077-12-18T07:02:48.635Z'), +(12.569920888850156, 17.558397958306756, '2077-12-18T07:13:53.635Z'), +(1.2815224057826748, 19.948030781895103, '2077-12-18T07:18:09.635Z'), +(21.234024620249475, 26.108501873863712, '2077-12-18T07:25:52.635Z'), +(5.064986055460106, 29.370619836219685, '2077-12-18T07:31:58.635Z'), +(21.896127664909258, 45.11943754478405, '2077-12-18T07:40:23.635Z'), +(23.141300931960004, 22.70202709946949, '2077-12-18T07:48:03.635Z'), +(19.044037900897237, 9.051611228588365, '2077-12-18T07:53:00.635Z'), +(8.554027017586115, 47.42951420461939, '2077-12-18T08:07:18.635Z'), +(4.784854379044618, 4.757162402041351, '2077-12-18T08:23:03.635Z'), +(0.6961328605009366, 47.09170871514599, '2077-12-18T08:38:47.635Z'), +(22.3584768202923, 15.523521492007758, '2077-12-18T08:52:42.635Z'), +(23.32609451105651, 3.665994008048357, '2077-12-18T08:56:45.635Z'), +(2.3368010693819214, 11.761220451635527, '2077-12-18T09:05:03.635Z'), +(1.2381155230234326, 17.921470205302544, '2077-12-18T09:07:22.635Z'), +(8.00198069805338, 16.181746983590035, '2077-12-18T09:09:57.635Z'), +(5.481419694966086, 47.43507621663559, '2077-12-18T09:21:29.635Z'), +(11.222736570638771, 2.8215512827120333, '2077-12-18T09:37:57.635Z'), +(11.381601546475808, 49.01624367112797, '2077-12-18T09:54:43.635Z'), +(6.393809247999006, 26.08868774696592, '2077-12-18T10:03:18.635Z'), +(8.816066349965196, 31.990890520549716, '2077-12-18T10:05:38.635Z'), +(17.437453844637794, 49.13419533422474, '2077-12-18T10:12:35.635Z'), +(0.6843623969803926, 44.921977713451334, '2077-12-18T10:18:58.635Z'), +(8.25672011604343, 23.739433280717577, '2077-12-18T10:27:16.635Z'), +(13.5639443803606, 16.53729022599283, '2077-12-18T10:30:32.635Z'), +(11.200579881724076, 34.13844297553186, '2077-12-18T10:36:57.635Z'), +(18.641836068478167, 19.09787470432671, '2077-12-18T10:42:59.635Z'), +(11.504723089666875, 48.94725229303853, '2077-12-18T10:53:58.635Z'), +(3.666599465852033, 11.66514273882618, '2077-12-18T11:07:57.635Z'), +(4.687252517882167, 38.42918435729996, '2077-12-18T11:17:51.635Z'), +(6.510291736642366, 48.025712702437346, '2077-12-18T11:21:27.635Z'), +(6.639127238684688, 21.90763569085552, '2077-12-18T11:31:03.635Z'), +(20.700051333241205, 8.277063143147435, '2077-12-18T11:38:11.635Z'), +(4.638385591540152, 6.59568966170151, '2077-12-18T11:44:10.635Z'), +(18.248281554497126, 45.460846781762655, '2077-12-18T11:59:06.635Z'), +(21.7459238628352, 1.2702610577794013, '2077-12-18T12:14:29.635Z'), +(9.623642514525752, 3.8616856354340094, '2077-12-18T12:19:04.635Z'), +(21.32956674618921, 15.936457923452657, '2077-12-18T12:25:10.635Z'), +(18.951218015254437, 25.906959005540713, '2077-12-18T12:28:44.635Z'), +(5.743475280923255, 6.529464992334777, '2077-12-18T12:37:16.635Z'), +(5.546374548650532, 5.028720438584408, '2077-12-18T12:37:49.635Z'), +(10.54085949434225, 43.59067248929693, '2077-12-18T12:52:04.635Z'), +(4.898517196616206, 44.13347647479401, '2077-12-18T12:54:10.635Z'), +(5.683424593467998, 45.74615361801617, '2077-12-18T12:54:49.635Z'), +(19.643436699730678, 11.112637842363254, '2077-12-18T13:08:19.635Z'), +(20.348983939064272, 27.21281955251889, '2077-12-18T13:13:55.635Z'), +(8.92754862487818, 34.246243479893124, '2077-12-18T13:18:50.635Z'), +(3.735115314376341, 22.186994859487896, '2077-12-18T13:23:40.635Z'), +(8.18412213585878, 19.426112778031307, '2077-12-18T13:25:36.635Z'), +(5.7609097095780255, 30.638615986410144, '2077-12-18T13:29:49.635Z'), +(11.985315388242658, 6.870337253220038, '2077-12-18T13:38:48.635Z'), +(9.218638896789159, 15.555793118224619, '2077-12-18T13:42:07.635Z'), +(23.00948870339955, 6.6062115295591575, '2077-12-18T13:48:08.635Z'), +(20.40988664530401, 40.08739807198808, '2077-12-18T13:59:40.635Z'), +(18.844572012576194, 2.6183486565939873, '2077-12-18T14:12:43.635Z'), +(10.294051666223417, 16.49016706961738, '2077-12-18T14:18:36.635Z'), +(14.610254814668878, 39.96935553698687, '2077-12-18T14:27:14.635Z'), +(20.653156430851077, 34.7749572305817, '2077-12-18T14:30:07.635Z'), +(21.34824403128703, 8.585897420244184, '2077-12-18T14:39:10.635Z'), +(7.809982842894336, 27.885858281895583, '2077-12-18T14:47:41.635Z'), +(7.3128039886504235, 36.16418081411051, '2077-12-18T14:50:43.635Z'), +(23.351483330019644, 35.18840999972315, '2077-12-18T14:56:40.635Z'), +(23.23305904092104, 37.816723587868466, '2077-12-18T14:57:33.635Z'), +(0.3794357318810876, 1.2114315470305244, '2077-12-18T15:13:12.635Z'), +(5.794503640052348, 35.81727585971667, '2077-12-18T15:26:09.635Z'), +(9.746439886780793, 49.34228733922927, '2077-12-18T15:31:19.635Z'), +(22.987502087258814, 40.7175283049904, '2077-12-18T15:37:05.635Z'), +(16.295234139213836, 8.7017276498955, '2077-12-18T15:48:30.635Z'), +(1.160087411538647, 47.798205249925886, '2077-12-18T16:03:50.635Z'), +(8.085279132253834, 23.688935447733833, '2077-12-18T16:13:05.635Z'), +(11.873367237609306, 43.88072722864758, '2077-12-18T16:20:35.635Z'), +(19.72017396832271, 0.2999719774956372, '2077-12-18T16:36:21.635Z'), +(14.511361256807835, 14.313381748314919, '2077-12-18T16:41:40.635Z'), +(18.944939779872712, 23.06147180324022, '2077-12-18T16:45:10.635Z'), +(19.9189447827984, 45.715916365591475, '2077-12-18T16:53:05.635Z'), +(23.347421527525157, 33.52504069265677, '2077-12-18T16:57:28.635Z'), +(1.0432446624802003, 40.56342656152037, '2077-12-18T17:06:06.635Z'), +(20.264917535529936, 25.863286445966136, '2077-12-18T17:14:59.635Z'), +(7.254167995602418, 25.316786179787098, '2077-12-18T17:19:48.635Z'), +(14.609869141357168, 43.55030409064162, '2077-12-18T17:26:58.635Z'), +(23.117713907051975, 31.5223150650903, '2077-12-18T17:32:13.635Z'), +(13.736952650711695, 25.056084843834295, '2077-12-18T17:36:22.635Z'), +(17.900735776685906, 26.363785468624094, '2077-12-18T17:37:58.635Z'), +(19.10542558149335, 1.7710693540695857, '2077-12-18T17:46:36.635Z'), +(14.519163652340634, 39.499539598677835, '2077-12-18T18:00:04.635Z'), +(12.282570765073219, 23.15796350201343, '2077-12-18T18:06:00.635Z'), +(6.258607247949191, 14.308794834018608, '2077-12-18T18:09:55.635Z'), +(2.324761064227014, 47.45748552605162, '2077-12-18T18:22:15.635Z'), +(2.3985727254843785, 41.01980107211297, '2077-12-18T18:24:38.635Z'), +(9.81774036159812, 21.730504332458786, '2077-12-18T18:32:15.635Z'), +(11.407076555192038, 15.129664287513462, '2077-12-18T18:34:43.635Z'), +(15.612776947140695, 29.993567235678526, '2077-12-18T18:40:17.635Z'), +(11.074218182648103, 10.909671097783695, '2077-12-18T18:47:21.635Z'), +(17.881034757225553, 10.579705821180703, '2077-12-18T18:49:52.635Z'), +(2.9293166805390825, 35.14809306118531, '2077-12-18T19:00:22.635Z'), +(14.6669333482235, 8.644320337341677, '2077-12-18T19:10:59.635Z'), +(16.13639984799889, 48.78375872416198, '2077-12-18T19:25:18.635Z'), +(3.2766036264763163, 38.16807913439375, '2077-12-18T19:31:26.635Z'), +(18.00043154437557, 48.39790358565106, '2077-12-18T19:38:02.635Z'), +(2.408366888091226, 42.87883137503009, '2077-12-18T19:44:09.635Z'), +(12.470136857819508, 4.457997412202532, '2077-12-18T19:58:43.635Z'), +(12.590017389051704, 45.945803757777824, '2077-12-18T20:13:42.635Z'), +(16.874255584745864, 1.5179479378042697, '2077-12-18T20:29:40.635Z'), +(18.881835109691806, 1.385700722828345, '2077-12-18T20:30:24.635Z'), +(16.068104628296826, 22.44290669215722, '2077-12-18T20:37:54.635Z'), +(3.8472027193866474, 6.780155757583949, '2077-12-18T20:45:11.635Z'), +(8.891333894467989, 10.644381335353126, '2077-12-18T20:47:31.635Z'), +(14.666356446679512, 36.584932327682985, '2077-12-18T20:57:09.635Z'), +(6.083267319893385, 11.351859947042863, '2077-12-18T21:06:52.635Z'), +(21.671069170366405, 21.745512251249558, '2077-12-18T21:13:44.635Z'), +(12.209497904469833, 38.1563475306921, '2077-12-18T21:20:31.635Z'), +(18.29833488245321, 10.044539815599293, '2077-12-18T21:30:48.635Z'), +(2.6176889072532084, 44.16134376165495, '2077-12-18T21:44:28.635Z'), +(13.01047265372015, 22.630727428071907, '2077-12-18T21:53:15.635Z'), +(5.011767705484068, 42.15411131528856, '2077-12-18T22:00:58.635Z'), +(15.86457003850283, 5.031843177861947, '2077-12-18T22:15:03.635Z'), +(3.8924731327185045, 26.14287370466838, '2077-12-18T22:23:55.635Z'), +(1.4485558913397816, 30.069507346517554, '2077-12-18T22:25:37.635Z'), +(4.822691500020923, 42.444414919881496, '2077-12-18T22:30:21.635Z'), +(6.449775267418819, 35.26310537664682, '2077-12-18T22:33:03.635Z'), +(3.0733849100383144, 14.853075403810227, '2077-12-18T22:40:41.635Z'), +(5.727432423554218, 46.40648309324757, '2077-12-18T22:52:23.635Z'), +(0.1407454317552513, 9.37831260837617, '2077-12-18T23:06:14.635Z'), +(17.612442744055542, 31.125430419669016, '2077-12-18T23:16:28.635Z'), +(2.55698253843555, 8.81242405352186, '2077-12-18T23:26:18.635Z'), +(19.927458864778473, 9.104895721460228, '2077-12-18T23:32:44.635Z'), +(4.814080765491776, 27.579139226300285, '2077-12-18T23:41:26.635Z'), +(0.6132563478817908, 27.601009490367687, '2077-12-18T23:42:59.635Z'), +(8.847927619516899, 39.3446765996367, '2077-12-18T23:48:17.635Z'), +(2.773993734876366, 6.0387165939396406, '2077-12-19T00:00:45.635Z'), +(1.9624104884599056, 23.641579132526168, '2077-12-19T00:07:16.635Z'), +(15.03703448325078, 19.156880716516405, '2077-12-19T00:12:22.635Z'), +(22.13155579600034, 2.361395464825197, '2077-12-19T00:18:49.635Z'), +(10.00596780326709, 15.948223161612493, '2077-12-19T00:25:24.635Z'), +(14.953661550671525, 40.26708427567172, '2077-12-19T00:34:23.635Z'), +(17.897524220869617, 36.819305011374624, '2077-12-19T00:36:01.635Z'), +(6.230424712532664, 36.636956070623526, '2077-12-19T00:40:20.635Z'), +(19.41066000954234, 22.475439572494167, '2077-12-19T00:47:23.635Z'), +(11.346226634840347, 33.74859772327314, '2077-12-19T00:52:23.635Z'), +(7.630795775092457, 48.92188675378419, '2077-12-19T00:58:05.635Z'), +(12.460660453649217, 24.683517337508153, '2077-12-19T01:07:06.635Z'), +(3.0483100754902637, 8.355783109858343, '2077-12-19T01:14:01.635Z'), +(8.319004633027896, 37.62703362665026, '2077-12-19T01:24:58.635Z'), +(4.283749664768727, 16.116848478920843, '2077-12-19T01:33:01.635Z'), +(9.694302158264886, 45.60546571877535, '2077-12-19T01:44:02.635Z'), +(21.417724374310957, 31.306393483913844, '2077-12-19T01:50:43.635Z'), +(11.727785956596634, 41.57706532596098, '2077-12-19T01:55:49.635Z'), +(10.117008000383363, 33.76727288643028, '2077-12-19T01:58:43.635Z'), +(2.69660958825249, 39.311174838789256, '2077-12-19T02:02:08.635Z'), +(8.078425923865932, 39.17892428665003, '2077-12-19T02:04:07.635Z'), +(10.365496641154156, 48.79487151342598, '2077-12-19T02:07:44.635Z'), +(7.626266519396439, 49.85981438152532, '2077-12-19T02:08:49.635Z'), +(12.77925622156644, 46.94679463464339, '2077-12-19T02:11:00.635Z'), +(7.649334333531017, 42.44878324988557, '2077-12-19T02:13:30.635Z'), +(22.83263768802377, 49.663620732734465, '2077-12-19T02:19:41.635Z'), +(19.878002431004777, 32.51042119416921, '2077-12-19T02:25:42.635Z'), +(10.172335027331329, 19.055553554484728, '2077-12-19T02:31:42.635Z'), +(23.099795878818057, 8.885876564534682, '2077-12-19T02:37:41.635Z'), +(1.3070045449056467, 10.714328137295443, '2077-12-19T02:45:47.635Z'), +(10.995631624413488, 16.28005951804353, '2077-12-19T02:49:55.635Z'), +(11.944468905531556, 2.5915651786435863, '2077-12-19T02:54:54.635Z'), +(14.794021115556253, 32.035625450854305, '2077-12-19T03:05:33.635Z'), +(20.702276017562497, 17.450823922216653, '2077-12-19T03:11:08.635Z'), +(22.115679181466817, 4.4540574416883585, '2077-12-19T03:15:38.635Z'), +(1.5689939801717185, 0.9686267835155485, '2077-12-19T03:23:21.635Z'), +(23.12171671189515, 44.41158711023383, '2077-12-19T03:40:52.635Z'), +(17.610440456150595, 31.699785361796664, '2077-12-19T03:45:43.635Z'), +(5.14884950038125, 14.002794149485082, '2077-12-19T03:53:37.635Z'), +(20.556100578472968, 17.095767231714305, '2077-12-19T03:59:26.635Z'), +(19.91076018126318, 19.172142505887418, '2077-12-19T04:00:11.635Z'), +(10.36028274150088, 17.81210607400913, '2077-12-19T04:03:45.635Z'), +(7.928608138985568, 15.292116676846343, '2077-12-19T04:05:02.635Z'), +(16.741367613920982, 35.95039444605179, '2077-12-19T04:13:11.635Z'), +(22.95740112652395, 22.72204429128397, '2077-12-19T04:18:20.635Z'), +(23.35397016685596, 20.323631393132963, '2077-12-19T04:19:09.635Z'), +(2.0426189595996607, 27.580713899334178, '2077-12-19T04:27:28.635Z'), +(23.55777391729214, 38.13178869299158, '2077-12-19T04:36:17.635Z'), +(12.980070591298, 19.422655529261778, '2077-12-19T04:43:56.635Z'), +(7.408863178060372, 6.158786871999456, '2077-12-19T04:49:11.635Z'), +(9.82909968082869, 45.944610414506045, '2077-12-19T05:03:46.635Z'), +(8.148514670887254, 49.46090389738101, '2077-12-19T05:05:11.635Z'), +(20.11564024365427, 16.85766362009208, '2077-12-19T05:17:40.635Z'), +(1.1787698720517077, 14.915523099146107, '2077-12-19T05:24:43.635Z'), +(4.244453867322651, 24.160171186406977, '2077-12-19T05:28:19.635Z'), +(4.903046800495781, 16.717316223351094, '2077-12-19T05:31:04.635Z'), +(4.644700241665314, 16.951607626098948, '2077-12-19T05:31:11.635Z'), +(4.550700216366952, 45.53478377754002, '2077-12-19T05:41:44.635Z'), +(2.9870385853887287, 43.84827353411938, '2077-12-19T05:42:35.635Z'), +(0.9202730864039359, 3.844482451768882, '2077-12-19T05:57:25.635Z'), +(15.558274049671533, 0.902182137822448, '2077-12-19T06:02:56.635Z'), +(5.728635180900009, 2.0646977023317143, '2077-12-19T06:06:36.635Z'), +(4.010805245560709, 7.571126313123951, '2077-12-19T06:08:43.635Z'), +(8.079391517953598, 9.617353170642717, '2077-12-19T06:10:24.635Z'), +(18.818468633777698, 30.734185433935636, '2077-12-19T06:18:58.635Z'), +(2.0568464088012424, 23.57824186069197, '2077-12-19T06:25:42.635Z'), +(2.589936232508675, 20.855122153081826, '2077-12-19T06:26:43.635Z'), +(1.747583770834663, 8.312959156532598, '2077-12-19T06:31:22.635Z'), +(3.3938239776611883, 36.35459992922864, '2077-12-19T06:41:46.635Z'), +(21.816746583537658, 30.618650831947438, '2077-12-19T06:48:54.635Z'), +(20.515536309518208, 2.3020617888432775, '2077-12-19T06:58:41.635Z'), +(1.2461933559883631, 38.27049013444236, '2077-12-19T07:13:31.635Z'), +(3.5108731580785735, 44.337682049386494, '2077-12-19T07:15:54.635Z'), +(9.512207170320034, 17.047765313944424, '2077-12-19T07:26:11.635Z'), +(12.96163760095573, 31.623144456873423, '2077-12-19T07:31:37.635Z'), +(6.267678091738573, 35.43594113913063, '2077-12-19T07:34:27.635Z'), +(1.2245087812508215, 7.9786751761957015, '2077-12-19T07:44:46.635Z'), +(21.120595422835077, 35.782421540915514, '2077-12-19T07:57:13.635Z'), +(5.274151784770013, 30.390056589234977, '2077-12-19T08:03:24.635Z'), +(15.504395394377944, 19.64826978050484, '2077-12-19T08:08:50.635Z'), +(12.49241730346023, 35.77521944634006, '2077-12-19T08:14:44.635Z'), +(12.608960170701293, 32.05189149160611, '2077-12-19T08:16:04.635Z'), +(17.751981954209928, 37.31416610692004, '2077-12-19T08:18:44.635Z'), +(17.795112665389695, 29.388003299192683, '2077-12-19T08:21:31.635Z'), +(5.737184018968891, 28.36112083030339, '2077-12-19T08:26:00.635Z'), +(11.725467250251125, 16.96457877859531, '2077-12-19T08:30:43.635Z'), +(1.2747713995996128, 6.209183772066803, '2077-12-19T08:36:15.635Z'), +(14.556770954276415, 42.80896257565619, '2077-12-19T08:50:31.635Z'), +(17.07062288016692, 45.41561613254705, '2077-12-19T08:51:49.635Z'), +(3.1632778908096357, 21.464167132461135, '2077-12-19T09:01:56.635Z'), +(17.876734833964402, 3.7094118829308553, '2077-12-19T09:10:22.635Z'), +(1.7951563813667133, 0.7602901998351426, '2077-12-19T09:16:25.635Z'), +(6.309317751666802, 26.15111336460064, '2077-12-19T09:25:56.635Z'), +(3.325996376524296, 21.502706369801338, '2077-12-19T09:27:58.635Z'), +(8.35477443951002, 46.81947526588521, '2077-12-19T09:37:28.635Z'), +(16.730577995944202, 6.229533158188104, '2077-12-19T09:52:26.635Z'), +(5.663866775326721, 24.92525757160959, '2077-12-19T10:00:21.635Z'), +(14.011178846027049, 45.728343210403004, '2077-12-19T10:08:32.635Z'), +(14.561976312714403, 49.910866068934574, '2077-12-19T10:10:02.635Z'), +(3.577802666952156, 30.135021303850262, '2077-12-19T10:18:19.635Z'), +(21.29712419563406, 44.89067950566178, '2077-12-19T10:26:45.635Z'), +(13.066960597955205, 47.533219864938935, '2077-12-19T10:29:56.635Z'), +(4.478418745874203, 44.964771070384685, '2077-12-19T10:33:15.635Z'), +(1.096505032396079, 43.59118548567583, '2077-12-19T10:34:36.635Z'), +(19.164187855327654, 37.96138503734143, '2077-12-19T10:41:36.635Z'), +(4.414152872230096, 39.65656041287915, '2077-12-19T10:47:06.635Z'), +(0.6277966912290787, 26.765492384298252, '2077-12-19T10:52:04.635Z'), +(0.09196821284305878, 45.55182019234059, '2077-12-19T10:59:01.635Z'), +(21.355892735848396, 22.022660076867158, '2077-12-19T11:10:37.635Z'), +(2.45044890863174, 18.99355976635638, '2077-12-19T11:17:42.635Z'), +(2.567745409309708, 20.870551076733058, '2077-12-19T11:18:23.635Z'), +(14.494070666567609, 46.91222589663394, '2077-12-19T11:28:53.635Z'), +(15.128860811985579, 6.822288341820704, '2077-12-19T11:43:13.635Z'), +(20.738724299560985, 32.88852495363514, '2077-12-19T11:52:37.635Z'), +(15.76189326340742, 30.25676546660318, '2077-12-19T11:54:40.635Z'), +(10.952149224988933, 23.465954877425066, '2077-12-19T11:57:41.635Z'), +(17.108835536288474, 13.212347400956537, '2077-12-19T12:02:01.635Z'), +(20.92164566373396, 9.350544738622876, '2077-12-19T12:03:58.635Z'), +(4.008133674831707, 11.979884938408505, '2077-12-19T12:10:18.635Z'), +(14.134552907524025, 19.14463891838387, '2077-12-19T12:14:52.635Z'), +(2.31289709486591, 39.562810092404064, '2077-12-19T12:23:31.635Z'), +(13.559014119006646, 1.361382038171989, '2077-12-19T12:38:07.635Z'), +(21.379224747669493, 18.486287233131844, '2077-12-19T12:44:49.635Z'), +(12.823738625370238, 24.21651189373753, '2077-12-19T12:48:34.635Z'), +(13.393367754888102, 45.71623292963579, '2077-12-19T12:56:19.635Z'), +(8.763620596798008, 29.724672433859233, '2077-12-19T13:02:22.635Z'), +(11.625982782101401, 37.4498334091271, '2077-12-19T13:05:22.635Z'), +(19.8280499347238, 6.757842972277962, '2077-12-19T13:16:42.635Z'), +(16.559050911933305, 22.112990097368133, '2077-12-19T13:22:14.635Z'), +(7.187243922110658, 37.93799432598703, '2077-12-19T13:28:56.635Z'), +(18.434866100605404, 37.59017602625074, '2077-12-19T13:33:06.635Z'), +(13.837603613026028, 19.225895507214116, '2077-12-19T13:39:51.635Z'), +(5.643848304122408, 26.105846382846984, '2077-12-19T13:43:47.635Z'), +(9.806756600081794, 48.66260229075972, '2077-12-19T13:52:12.635Z'), +(10.433472616709196, 23.541641499057988, '2077-12-19T14:01:22.635Z'), +(12.080687062552373, 13.79061621811401, '2077-12-19T14:04:57.635Z'), +(0.46837062257241785, 43.9721491702745, '2077-12-19T14:16:51.635Z'), +(16.802467349594412, 0.7551497924206938, '2077-12-19T14:33:44.635Z'), +(23.4261808558125, 4.131474906545876, '2077-12-19T14:36:27.635Z'), +(22.57029085958493, 20.68215862668137, '2077-12-19T14:42:06.635Z'), +(9.027981159168913, 40.58808318929869, '2077-12-19T14:50:46.635Z'), +(10.398848378445052, 19.22562899289102, '2077-12-19T14:58:35.635Z'), +(13.452044780483678, 20.642216422213895, '2077-12-19T14:59:49.635Z'), +(0.23474307750367554, 44.10034200601164, '2077-12-19T15:09:43.635Z'), +(17.62655524104218, 46.98592767290284, '2077-12-19T15:16:14.635Z'), +(20.990249525810487, 11.634497467181864, '2077-12-19T15:28:38.635Z'), +(8.520441508053693, 49.144173309109, '2077-12-19T15:42:48.635Z'), +(17.19306850385123, 50.00751327696424, '2077-12-19T15:46:01.635Z'), +(13.252387079903189, 38.98659464747928, '2077-12-19T15:50:13.635Z'), +(11.975804560017767, 44.56842033558272, '2077-12-19T15:52:17.635Z'), +(17.524894823479123, 43.08785996795471, '2077-12-19T15:54:24.635Z'), +(6.338026401882786, 35.04788593550739, '2077-12-19T15:59:27.635Z'), +(20.691570310886828, 45.6686913533728, '2077-12-19T16:05:59.635Z'), +(22.83075721943905, 17.68922058121678, '2077-12-19T16:15:37.635Z'), +(15.649303610040768, 4.477228197545336, '2077-12-19T16:20:56.635Z'), +(0.8922372082581093, 40.22076006737144, '2077-12-19T16:35:05.635Z'), +(18.293665672200362, 26.514058290393113, '2077-12-19T16:43:14.635Z'), +(10.66591914917423, 12.26516970437077, '2077-12-19T16:49:04.635Z'), +(18.115263906379482, 8.808578468857684, '2077-12-19T16:52:05.635Z'), +(9.127317582337133, 6.758443877123138, '2077-12-19T16:55:29.635Z'), +(21.375984131475896, 15.89415665638484, '2077-12-19T17:01:04.635Z'), +(7.766476198055705, 33.47108533796944, '2077-12-19T17:09:07.635Z'), +(5.223371033141766, 28.36316584927224, '2077-12-19T17:11:13.635Z'), +(10.131635021541515, 10.313842369940192, '2077-12-19T17:18:05.635Z'), +(16.244534904780355, 23.27059455338225, '2077-12-19T17:23:16.635Z'), +(12.3419423776031, 16.48871150589221, '2077-12-19T17:26:05.635Z'), +(4.826531502070798, 33.70863545991888, '2077-12-19T17:32:58.635Z'), +(2.92730460834552, 21.826712427104546, '2077-12-19T17:37:24.635Z'), +(20.60520562292431, 45.34171877832312, '2077-12-19T17:48:07.635Z'), +(5.924953992592669, 41.055742403293735, '2077-12-19T17:53:46.635Z'), +(6.264157335398536, 21.861681016056348, '2077-12-19T18:00:50.635Z'), +(3.199788040870785, 28.264237925315378, '2077-12-19T18:03:27.635Z'), +(0.7355609624077284, 47.105999874310676, '2077-12-19T18:10:29.635Z'), +(4.1668652998649796, 36.646624933774085, '2077-12-19T18:14:33.635Z'), +(4.727854499564401, 46.50820463897962, '2077-12-19T18:18:12.635Z'), +(4.48062806569239, 0.5993246645519199, '2077-12-19T18:35:09.635Z'), +(14.279548467558348, 41.43965507608921, '2077-12-19T18:50:29.635Z'), +(5.275120818444569, 32.39375436509788, '2077-12-19T18:55:10.635Z'), +(8.153404146720508, 6.147857331870975, '2077-12-19T19:04:53.635Z'), +(16.302686497135454, 30.764831422329408, '2077-12-19T19:14:17.635Z'), +(4.32169968779093, 9.879586157091424, '2077-12-19T19:23:05.635Z'), +(11.624681495166728, 21.843540930965656, '2077-12-19T19:28:14.635Z'), +(20.737928163175706, 8.266363337689361, '2077-12-19T19:34:07.635Z'), +(12.84441817327626, 14.520446558114031, '2077-12-19T19:37:47.635Z'), +(7.043021013449357, 6.939456230735994, '2077-12-19T19:41:17.635Z'), +(9.751616488998195, 35.910797934368446, '2077-12-19T19:51:57.635Z'), +(4.368493072757628, 23.414534348585885, '2077-12-19T19:56:57.635Z'), +(12.435022965337238, 41.83241935190715, '2077-12-19T20:04:19.635Z'), +(20.550763913437375, 8.401604705461555, '2077-12-19T20:16:32.635Z'), +(20.377316710725584, 34.461199603805255, '2077-12-19T20:25:34.635Z'), +(11.715004197034618, 17.472982177461162, '2077-12-19T20:32:24.635Z'), +(19.01781605512292, 24.600096963414433, '2077-12-19T20:36:06.635Z'), +(15.512543228001203, 18.583220435205654, '2077-12-19T20:38:35.635Z'), +(4.734078657113793, 16.234572995417327, '2077-12-19T20:42:40.635Z'), +(22.567565032568464, 12.087221040971185, '2077-12-19T20:49:26.635Z'), +(10.091729213211472, 48.84200336519921, '2077-12-19T21:03:15.635Z'), +(4.086989418108632, 5.807792304111842, '2077-12-19T21:19:13.635Z'), +(18.737459083954565, 47.09835952290317, '2077-12-19T21:35:06.635Z'), +(16.478032949558045, 15.4412583097355, '2077-12-19T21:46:18.635Z'), +(17.780787552635886, 15.069194728997289, '2077-12-19T21:46:48.635Z'), +(6.343507764679698, 1.3959339614206656, '2077-12-19T21:53:18.635Z'), +(20.783594670365108, 23.928937831201917, '2077-12-19T22:03:00.635Z'), +(16.30507152580666, 37.90276871244549, '2077-12-19T22:08:10.635Z'), +(6.868548867305149, 35.77465492676507, '2077-12-19T22:11:44.635Z'), +(3.635276073477979, 25.421532181403613, '2077-12-19T22:15:44.635Z'), +(8.54879252208187, 30.3488309154575, '2077-12-19T22:18:18.635Z'), +(1.4223888835512621, 10.462205555419114, '2077-12-19T22:26:05.635Z'), +(18.96940484160812, 38.853015644444646, '2077-12-19T22:38:16.635Z'), +(3.448307647840767, 1.1043806072848061, '2077-12-19T22:53:05.635Z'), +(12.813977248155858, 42.106348014317696, '2077-12-19T23:08:29.635Z'), +(15.374824592448086, 18.942011113009222, '2077-12-19T23:16:51.635Z'), +(13.675145896887468, 43.155105059016215, '2077-12-19T23:25:33.635Z'), +(15.364379330897334, 36.998921095960625, '2077-12-19T23:27:50.635Z'), +(22.410606169091793, 8.148646366730599, '2077-12-19T23:38:15.635Z'), +(23.2753208669194, 48.31474874089123, '2077-12-19T23:51:55.635Z'), +(14.393390867147307, 25.209420022202277, '2077-12-20T00:00:38.635Z'), +(17.867327012059466, 32.17793798960822, '2077-12-20T00:03:25.635Z'), +(4.137497569035767, 25.305364831263464, '2077-12-20T00:09:05.635Z'), +(18.96769843725395, 21.58686634631156, '2077-12-20T00:14:44.635Z'), +(18.421518575592497, 30.141298218933795, '2077-12-20T00:17:44.635Z'), +(18.447908402880277, 15.432503168183446, '2077-12-20T00:22:54.635Z'), +(15.845190524817088, 14.37960176374649, '2077-12-20T00:23:56.635Z'), +(20.86294072046679, 3.389018653465739, '2077-12-20T00:28:13.635Z'), +(6.960401738861986, 7.0215517979411795, '2077-12-20T00:33:31.635Z'), +(12.941416772962285, 4.232638619954142, '2077-12-20T00:35:57.635Z'), +(14.976732860684518, 0.4698041964576346, '2077-12-20T00:37:29.635Z'), +(10.657829402077548, 43.583909116938926, '2077-12-20T00:53:07.635Z'), +(18.207677096986817, 30.647594938121863, '2077-12-20T00:58:32.635Z'), +(21.25773504527196, 9.784415151957544, '2077-12-20T01:05:53.635Z'), +(20.387651923737778, 29.82921792440644, '2077-12-20T01:12:49.635Z'), +(18.109570993776583, 47.580962053028216, '2077-12-20T01:19:04.635Z'), +(7.854941829703543, 9.312870396119074, '2077-12-20T01:33:22.635Z'), +(7.425932041478645, 10.662138705049435, '2077-12-20T01:33:53.635Z'), +(1.7067922540672458, 38.41966970986711, '2077-12-20T01:44:21.635Z'), +(20.40292214110018, 14.24274707277182, '2077-12-20T01:55:30.635Z'), +(18.56759778942701, 29.39164690944653, '2077-12-20T02:00:50.635Z'), +(6.693066120271218, 0.23364194232632357, '2077-12-20T02:12:14.635Z'), +(4.892565511421631, 12.959086830888332, '2077-12-20T02:16:58.635Z'), +(19.820906469028706, 25.23284296339205, '2077-12-20T02:24:03.635Z'), +(9.257659586514242, 44.529866187522124, '2077-12-20T02:31:59.635Z'), +(21.150300651808568, 23.30532528042922, '2077-12-20T02:40:44.635Z'), +(3.3309530112631007, 11.071539406144142, '2077-12-20T02:48:40.635Z'), +(0.8383136999601928, 26.660585589201002, '2077-12-20T02:54:30.635Z'), +(6.118628342436504, 30.66643412903528, '2077-12-20T02:56:57.635Z'), +(8.478855021126078, 39.151641737717206, '2077-12-20T03:00:11.635Z'), +(16.996403989172705, 6.396133425206533, '2077-12-20T03:12:25.635Z'), +(1.9207045188997556, 15.39502307705176, '2077-12-20T03:18:53.635Z'), +(15.923506968500833, 9.50381774332129, '2077-12-20T03:24:30.635Z'), +(4.997966068825237, 11.916460452835267, '2077-12-20T03:28:38.635Z'), +(14.926974609403507, 38.74451231923533, '2077-12-20T03:39:04.635Z'), +(16.373417192655236, 47.036035485519314, '2077-12-20T03:42:04.635Z'), +(3.330297951168294, 36.73320714006199, '2077-12-20T03:48:11.635Z'), +(20.632161759135652, 16.64266354832421, '2077-12-20T03:57:51.635Z'), +(9.156207384231335, 21.51264132739505, '2077-12-20T04:02:26.635Z'), +(19.3336958753859, 14.586577835703691, '2077-12-20T04:06:57.635Z'), +(15.426312076529385, 14.219351048460702, '2077-12-20T04:08:24.635Z'), +(2.872044397533688, 36.06911554403966, '2077-12-20T04:17:38.635Z'), +(11.309229664022151, 8.976336534070477, '2077-12-20T04:28:04.635Z'), +(12.04472980773235, 38.70200764121146, '2077-12-20T04:38:51.635Z'), +(8.146084947564374, 35.21552685936039, '2077-12-20T04:40:46.635Z'), +(21.25718830053776, 4.835880145268311, '2077-12-20T04:52:39.635Z'), +(13.305807892468437, 14.429938629543162, '2077-12-20T04:57:08.635Z'), +(10.20929471152846, 2.5963557675540696, '2077-12-20T05:01:34.635Z'), +(17.34569396753407, 13.220913188222868, '2077-12-20T05:06:12.635Z'), +(6.812434959818309, 0.4158332526945556, '2077-12-20T05:12:15.635Z'), +(11.403579051498726, 39.15733513649625, '2077-12-20T05:26:31.635Z'), +(22.28905795433779, 31.47537562857375, '2077-12-20T05:31:22.635Z'), +(1.0745601942042096, 1.0707257428794013, '2077-12-20T05:44:51.635Z'), +(23.220050435579942, 12.141074953226772, '2077-12-20T05:53:58.635Z'), +(12.326054328587263, 48.50666167887375, '2077-12-20T06:07:22.635Z'), +(13.246995164913175, 35.85396744862745, '2077-12-20T06:11:57.635Z'), +(18.514913437104315, 6.597100762683414, '2077-12-20T06:22:32.635Z'), +(0.3059935753567102, 47.75729637418761, '2077-12-20T06:38:57.635Z'), +(1.8115559639014038, 49.81128294146633, '2077-12-20T06:39:53.635Z'), +(20.889360994622713, 21.37034629029209, '2077-12-20T06:52:21.635Z'), +(18.23797527211813, 11.546555090498257, '2077-12-20T06:55:55.635Z'), +(1.9520126751755127, 42.537763326378986, '2077-12-20T07:08:41.635Z'), +(14.49296237149047, 27.46414946654183, '2077-12-20T07:15:53.635Z'), +(4.473261786010971, 42.55420857351879, '2077-12-20T07:22:31.635Z'), +(10.849800245509767, 22.628445542524698, '2077-12-20T07:30:12.635Z'), +(22.20383933982067, 24.37029517286705, '2077-12-20T07:34:27.635Z'), +(18.849931946739805, 50.310014733499635, '2077-12-20T07:43:31.635Z'), +(16.218532017879863, 17.772507172844527, '2077-12-20T07:55:02.635Z'), +(9.238823495966725, 31.949622486608746, '2077-12-20T08:00:46.635Z'), +(21.400142112442502, 32.963450587427886, '2077-12-20T08:05:17.635Z'), +(22.13131861306372, 11.234184484841307, '2077-12-20T08:12:45.635Z'), +(17.609749023900505, 2.349063054728335, '2077-12-20T08:16:16.635Z'), +(3.2227412366216828, 48.965482872179436, '2077-12-20T08:34:00.635Z'), +(10.754867936592774, 18.302813546545167, '2077-12-20T08:45:36.635Z'), +(6.1547679596586455, 41.59193938507257, '2077-12-20T08:54:18.635Z'), +(2.301173137605376, 18.080595192856755, '2077-12-20T09:03:06.635Z'), +(18.658736043992857, 35.82274577374379, '2077-12-20T09:11:56.635Z'), +(20.122850334201207, 19.404933839092642, '2077-12-20T09:17:41.635Z'), +(13.535163470186676, 38.12324022955408, '2077-12-20T09:24:45.635Z'), +(8.97484211447047, 40.64091140748083, '2077-12-20T09:26:40.635Z'), +(11.201731657000762, 32.94690066834395, '2077-12-20T09:29:35.635Z'), +(7.523486047764561, 42.683948875555885, '2077-12-20T09:33:23.635Z'), +(12.970921159100081, 46.00318687945435, '2077-12-20T09:35:44.635Z'), +(3.7939952964330756, 13.659385387727351, '2077-12-20T09:48:03.635Z'), +(17.51244428741367, 20.440751036750548, '2077-12-20T09:53:42.635Z'), +(13.908560547090042, 20.92195882589841, '2077-12-20T09:55:02.635Z'), +(15.080125163557005, 16.50878461832363, '2077-12-20T09:56:40.635Z'), +(9.437563679639524, 25.49592431250936, '2077-12-20T10:00:32.635Z'), +(12.110943435539193, 5.831564265727105, '2077-12-20T10:07:45.635Z'), +(16.38813504048863, 14.8064959390177, '2077-12-20T10:11:20.635Z'), +(9.710273038363127, 6.028991696475774, '2077-12-20T10:15:21.635Z'), +(17.071175635900325, 30.465171966643183, '2077-12-20T10:24:33.635Z'), +(8.002217898657221, 9.986640874441214, '2077-12-20T10:32:40.635Z'), +(12.67454646805182, 0.35945801260058097, '2077-12-20T10:36:34.635Z'), +(17.675070264686383, 49.76507003744835, '2077-12-20T10:54:17.635Z'), +(21.387230134769194, 45.92485740502519, '2077-12-20T10:56:12.635Z'), +(7.442036809166234, 1.699378117766544, '2077-12-20T11:12:49.635Z'), +(18.948347946196154, 24.04168527627288, '2077-12-20T11:21:55.635Z'), +(21.636242319722037, 24.908422224778853, '2077-12-20T11:22:57.635Z'), +(19.706978547395668, 42.55674131124952, '2077-12-20T11:29:06.635Z'), +(20.88527979604771, 43.58963545324576, '2077-12-20T11:29:39.635Z'), +(14.66306996029479, 1.7188309150918593, '2077-12-20T11:44:33.635Z'), +(11.286191248748128, 41.84572060871289, '2077-12-20T11:59:04.635Z'), +(14.651722119145965, 20.261138615268727, '2077-12-20T12:06:57.635Z'), +(18.78475885841954, 12.534067033781747, '2077-12-20T12:10:05.635Z'), +(2.3472600492186335, 5.669207969148941, '2077-12-20T12:16:39.635Z'), +(11.92966458277817, 23.446189491127363, '2077-12-20T12:24:04.635Z'), +(17.494102811461705, 17.54510231636943, '2077-12-20T12:27:01.635Z'), +(16.879458233293214, 35.05112767877055, '2077-12-20T12:33:13.635Z'), +(22.669983411406825, 43.1965145563165, '2077-12-20T12:36:46.635Z'), +(18.21617970461873, 23.974718118121316, '2077-12-20T12:43:38.635Z'), +(6.560181127482044, 31.546277621760712, '2077-12-20T12:48:44.635Z'), +(14.942836326781721, 39.24287948877393, '2077-12-20T12:52:54.635Z'), +(9.859319659930305, 34.41013510140855, '2077-12-20T12:55:28.635Z'), +(20.289832372940094, 3.98761600198156, '2077-12-20T13:06:59.635Z'), +(22.960002739022265, 31.60498345658026, '2077-12-20T13:16:32.635Z'), +(16.370735197553895, 11.873120950833817, '2077-12-20T13:23:49.635Z'), +(2.774046720013666, 26.37116914054677, '2077-12-20T13:31:07.635Z'), +(1.190880615135018, 42.161893323763024, '2077-12-20T13:36:59.635Z'), +(22.21914100723689, 38.63611951979773, '2077-12-20T13:44:52.635Z'), +(11.331800694142364, 17.69107256419006, '2077-12-20T13:53:18.635Z'), +(3.9833596474190838, 12.101399621439977, '2077-12-20T13:56:42.635Z'), +(5.777671647465541, 6.882122615127892, '2077-12-20T13:58:44.635Z'), +(9.926751789335778, 21.41541795633796, '2077-12-20T14:04:17.635Z'), +(22.182151539116816, 19.130261857622667, '2077-12-20T14:08:53.635Z'), +(2.4968940487436564, 34.90024112144163, '2077-12-20T14:18:07.635Z'), +(7.955001684089364, 47.510855141025615, '2077-12-20T14:23:11.635Z'), +(19.704055334115935, 38.988479940176774, '2077-12-20T14:28:30.635Z'), +(10.582359060973975, 13.675374559076662, '2077-12-20T14:38:09.635Z'), +(5.205792992567662, 18.598424531566128, '2077-12-20T14:40:50.635Z'), +(8.327935662947267, 42.32460111548267, '2077-12-20T14:49:38.635Z'), +(3.975955166642103, 50.01630034899051, '2077-12-20T14:52:53.635Z'), +(7.196391589255531, 32.153725149040355, '2077-12-20T14:59:34.635Z'), +(18.661206878675646, 0.18528321843976037, '2077-12-20T15:11:50.635Z'), +(8.094218697601555, 48.234842533107546, '2077-12-20T15:29:32.635Z'), +(22.533055438352594, 28.150703878573864, '2077-12-20T15:38:28.635Z'), +(14.298456381960778, 16.232880889813924, '2077-12-20T15:43:38.635Z'), +(0.9400897966824449, 13.236378725665194, '2077-12-20T15:48:42.635Z'), +(3.2190559081965118, 40.31531683407688, '2077-12-20T15:58:45.635Z'), +(20.48450591417081, 22.77607307544024, '2077-12-20T16:07:45.635Z'), +(5.321790151874662, 0.4934145214083052, '2077-12-20T16:17:32.635Z'), +(0.7818533266586007, 50.03582726540211, '2077-12-20T16:35:56.635Z'), +(16.066276115598672, 0.36242603368183957, '2077-12-20T16:54:56.635Z'), +(20.408899900958552, 45.45244248374451, '2077-12-20T17:10:50.635Z'), +(13.612979116200108, 42.72295831041582, '2077-12-20T17:13:31.635Z'), +(3.969166094851737, 8.956563247996467, '2077-12-20T17:26:22.635Z'), +(9.597323179895586, 18.0315523612636, '2077-12-20T17:30:18.635Z'), +(6.2540032473526885, 7.317699532695552, '2077-12-20T17:34:25.635Z'), +(16.283062652413456, 37.71653460443863, '2077-12-20T17:46:03.635Z'), +(15.626477246373836, 26.938977220071976, '2077-12-20T17:49:53.635Z'), +(17.77871942815084, 18.709418651430745, '2077-12-20T17:52:54.635Z'), +(10.43874152567095, 34.53883544547011, '2077-12-20T17:59:12.635Z'), +(13.69601628053332, 12.565232827608257, '2077-12-20T18:07:15.635Z'), +(18.693233634242212, 2.7799671088004727, '2077-12-20T18:11:11.635Z'), +(1.3660882957942735, 7.400716741304522, '2077-12-20T18:17:49.635Z'), +(23.469229320679524, 47.17209365526799, '2077-12-20T18:34:16.635Z'), +(13.629552097020865, 11.26814908247914, '2077-12-20T18:47:21.635Z'), +(6.41380102077399, 21.996547935099752, '2077-12-20T18:52:05.635Z'), +(11.802026681228124, 45.18656122203658, '2077-12-20T19:00:47.635Z'), +(22.168253665091118, 9.266498785765492, '2077-12-20T19:14:02.635Z'), +(9.637264660340469, 35.82407129688827, '2077-12-20T19:24:33.635Z'), +(4.757626150514932, 41.81099084068672, '2077-12-20T19:27:23.635Z'), +(23.123964067227195, 44.134597315419, '2077-12-20T19:34:14.635Z'), +(21.961139473973624, 49.38789379938761, '2077-12-20T19:36:04.635Z'), +(0.9224361257186643, 38.88798921690374, '2077-12-20T19:44:44.635Z'), +(9.1229534330631, 25.95847763529233, '2077-12-20T19:50:23.635Z'), +(17.237332247091285, 22.48007351670902, '2077-12-20T19:53:38.635Z'), +(4.05832536822172, 2.178137460366486, '2077-12-20T20:02:28.635Z'), +(21.218187652874505, 39.182697876498914, '2077-12-20T20:17:13.635Z'), +(3.167113058093793, 13.162311714885227, '2077-12-20T20:28:44.635Z'), +(13.439219259975088, 19.711690640469854, '2077-12-20T20:33:13.635Z'), +(22.490138388229337, 25.302469323643773, '2077-12-20T20:37:06.635Z'), +(16.970555757946588, 32.47911436864933, '2077-12-20T20:40:19.635Z'), +(7.506900705543676, 0.37671225058930136, '2077-12-20T20:52:26.635Z'), +(14.886346622325359, 27.070552296773574, '2077-12-20T21:02:30.635Z'), +(4.5672055356191255, 34.34520480525055, '2077-12-20T21:07:09.635Z'), +(21.934656008881124, 27.611233824317644, '2077-12-20T21:14:01.635Z'), +(3.411428569634106, 39.9495784108374, '2077-12-20T21:22:11.635Z'), +(17.81103290901664, 18.161571257551152, '2077-12-20T21:31:43.635Z'), +(9.641349000189491, 4.536519494958313, '2077-12-20T21:37:28.635Z'), +(1.3769508520176343, 1.5012937918616358, '2077-12-20T21:40:43.635Z'), +(4.8395249609367745, 10.015487730932923, '2077-12-20T21:44:07.635Z'), +(1.3219803512186614, 27.067339035096797, '2077-12-20T21:50:33.635Z'), +(1.3541651816667757, 2.806146791650197, '2077-12-20T21:59:32.635Z'), +(10.062371946693732, 7.751793718866152, '2077-12-20T22:03:14.635Z'), +(15.561386469202697, 24.34686118962029, '2077-12-20T22:09:33.635Z'), +(21.617449770727482, 28.88430433699215, '2077-12-20T22:12:18.635Z'), +(18.495418449574885, 41.1836541226129, '2077-12-20T22:16:44.635Z'), +(0.010144838210178858, 45.29034949556691, '2077-12-20T22:23:44.635Z'), +(22.951357759124026, 1.4856250627065397, '2077-12-20T22:41:39.635Z'), +(10.107374090138892, 49.64539427625493, '2077-12-20T22:59:19.635Z'), +(19.599121019818895, 36.42535081129141, '2077-12-20T23:05:12.635Z'), +(8.476882484523982, 4.656838308914326, '2077-12-20T23:17:18.635Z'), +(13.637377769833817, 38.74705624726094, '2077-12-20T23:29:50.635Z'), +(15.116436021838268, 6.560896032086972, '2077-12-20T23:41:23.635Z'), +(20.14577031055553, 36.048264635124106, '2077-12-20T23:51:56.635Z'), +(19.336237320965388, 48.02610350626019, '2077-12-20T23:56:07.635Z'), +(16.36837792714435, 11.08969285282202, '2077-12-21T00:09:10.635Z'), +(9.502731918716133, 33.37426696468347, '2077-12-21T00:17:36.635Z'), +(15.457557881801225, 40.30760607103056, '2077-12-21T00:20:56.635Z'), +(0.15227626516247098, 23.80322346176129, '2077-12-21T00:29:13.635Z'), +(3.299880782980552, 39.432953822991166, '2077-12-21T00:35:07.635Z'), +(4.102610843876383, 7.722253791510907, '2077-12-21T00:46:50.635Z'), +(22.071762336756745, 37.94947931108464, '2077-12-21T00:59:34.635Z'), +(20.14421600589633, 20.524139874808828, '2077-12-21T01:05:37.635Z'), +(1.7776024463538787, 36.07908273752017, '2077-12-21T01:14:27.635Z'), +(3.6033585334999683, 26.014922653474702, '2077-12-21T01:18:14.635Z'), +(18.79037103160105, 21.115704165386294, '2077-12-21T01:24:08.635Z'), +(7.296621898788538, 5.925108405576109, '2077-12-21T01:31:04.635Z'), +(22.55704148942784, 14.023724742445275, '2077-12-21T01:37:25.635Z'), +(1.5591518135113962, 38.56318755037648, '2077-12-21T01:49:11.635Z'), +(6.498908195139185, 47.928118494482945, '2077-12-21T01:53:05.635Z'), +(17.76603754651293, 46.308740270772894, '2077-12-21T01:57:18.635Z'), +(14.132764253107895, 19.228432672815778, '2077-12-21T02:07:02.635Z'), +(7.58985286914455, 37.81738006555565, '2077-12-21T02:14:12.635Z'), +(8.104363742371461, 29.634038986606356, '2077-12-21T02:17:12.635Z'), +(17.480492946049118, 33.892360308757645, '2077-12-21T02:21:00.635Z'), +(19.375481519567156, 22.82574731345164, '2077-12-21T02:24:57.635Z'), +(22.436704594366727, 25.97853823425377, '2077-12-21T02:26:31.635Z'), +(11.67616723435604, 49.15381327273975, '2077-12-21T02:35:37.635Z'), +(11.205501201127497, 40.85314189250172, '2077-12-21T02:38:38.635Z'), +(19.266218680279803, 3.104945553169529, '2077-12-21T02:52:25.635Z'), +(17.527592477337492, 20.318806167103197, '2077-12-21T02:58:30.635Z'), +(17.0462118489923, 18.39225058263866, '2077-12-21T02:59:12.635Z'), +(6.456681509489669, 24.86321948777122, '2077-12-21T03:03:46.635Z'), +(6.283777039434308, 6.991448566796357, '2077-12-21T03:10:20.635Z'), +(1.1721610367057347, 37.790033416669964, '2077-12-21T03:21:52.635Z'), +(10.098532861801809, 38.09069823070497, '2077-12-21T03:25:10.635Z'), +(1.98625986117111, 18.133535757163752, '2077-12-21T03:33:06.635Z'), +(19.514845203162306, 38.643725248242966, '2077-12-21T03:42:58.635Z'), +(23.172770873539925, 23.987877528927754, '2077-12-21T03:48:12.635Z'), +(17.856857732221485, 20.62615307024298, '2077-12-21T03:50:29.635Z'), +(8.065170696671498, 4.577428386996307, '2077-12-21T03:57:18.635Z'), +(8.797671630161338, 5.635885039391483, '2077-12-21T03:57:46.635Z'), +(13.826526475852017, 49.24663324354301, '2077-12-21T04:13:42.635Z'), +(22.929954825489574, 22.311261815847743, '2077-12-21T04:23:44.635Z'), +(14.504235334962928, 1.1344696868042885, '2077-12-21T04:31:47.635Z'), +(5.528103404102817, 45.20157463193134, '2077-12-21T04:48:10.635Z'), +(13.471617103241268, 2.593633186849224, '2077-12-21T05:03:59.635Z'), +(1.1936779391077816, 40.726379834572775, '2077-12-21T05:18:41.635Z'), +(6.528041353696732, 7.6516275993996, '2077-12-21T05:31:04.635Z'), +(8.239255005391708, 14.638211897065599, '2077-12-21T05:33:42.635Z'), +(14.8319017865123, 11.529735840551611, '2077-12-21T05:36:23.635Z'), +(13.818432795834964, 24.5996282814324, '2077-12-21T05:41:05.635Z'), +(10.23629575140254, 25.723541236014857, '2077-12-21T05:42:28.635Z'), +(17.804342859464693, 24.06725239480698, '2077-12-21T05:45:20.635Z'), +(5.4894121414081205, 1.779704980346471, '2077-12-21T05:54:36.635Z'), +(6.193520694002952, 26.90590656775788, '2077-12-21T06:03:52.635Z'), +(2.9451795249899466, 50.06370418180528, '2077-12-21T06:12:30.635Z'), +(22.638205050611308, 2.1526531873521235, '2077-12-21T06:31:10.635Z'), +(10.861464020369846, 47.282622038347924, '2077-12-21T06:47:41.635Z'), +(22.779226976268895, 9.366156901405013, '2077-12-21T07:01:47.635Z'), +(21.94999016150832, 48.74923335710792, '2077-12-21T07:15:14.635Z'), +(21.246585795033564, 38.73629981975108, '2077-12-21T07:18:41.635Z'), +(7.71390073104182, 34.9723649482701, '2077-12-21T07:23:52.635Z'), +(2.0580335338189926, 48.08114317492577, '2077-12-21T07:29:08.635Z'), +(6.991239682187187, 49.12858666775715, '2077-12-21T07:31:00.635Z'), +(8.692484472870996, 3.883944620263972, '2077-12-21T07:47:36.635Z'), +(15.796814953727711, 25.677865642295032, '2077-12-21T07:55:54.635Z'), +(22.320801966335733, 41.88320278215333, '2077-12-21T08:02:03.635Z'), +(5.114051047281478, 5.138532386241788, '2077-12-21T08:16:40.635Z'), +(19.542137098195912, 10.925676557455821, '2077-12-21T08:22:24.635Z'), +(7.973989656276084, 7.194733325698969, '2077-12-21T08:26:53.635Z'), +(8.810829938969329, 43.34862797102808, '2077-12-21T08:40:08.635Z'), +(13.47736561218002, 1.4802013059340773, '2077-12-21T08:55:26.635Z'), +(14.095647156805267, 48.78250400071634, '2077-12-21T09:12:25.635Z'), +(6.079978918071238, 24.54570939894137, '2077-12-21T09:21:44.635Z'), +(11.471768502070981, 37.6730248964893, '2077-12-21T09:26:56.635Z'), +(15.533479201519382, 12.740337825321102, '2077-12-21T09:36:02.635Z'), +(7.140402841398005, 20.73220606600471, '2077-12-21T09:40:17.635Z'), +(9.821845593695638, 12.142704073183216, '2077-12-21T09:43:35.635Z'), +(17.8721429085388, 10.240193747418964, '2077-12-21T09:46:38.635Z'), +(11.350655324270136, 15.097899001785752, '2077-12-21T09:49:36.635Z'), +(0.3783347207200558, 22.626917473911053, '2077-12-21T09:54:31.635Z'), +(9.505307743268567, 33.860664206099024, '2077-12-21T09:59:51.635Z'), +(6.552939414114737, 4.330366388934212, '2077-12-21T10:10:44.635Z'), +(12.364934991008695, 21.035727950185606, '2077-12-21T10:17:12.635Z'), +(7.164014451405154, 33.52889215931113, '2077-12-21T10:22:09.635Z'), +(5.784335525325373, 35.14478384562549, '2077-12-21T10:22:56.635Z'), +(20.025535282273797, 48.4898307315229, '2077-12-21T10:30:04.635Z'), +(18.351103452349303, 8.792305433472103, '2077-12-21T10:43:56.635Z'), +(14.315312192546745, 21.735593293685056, '2077-12-21T10:48:46.635Z'), +(22.578311804450408, 14.274633282231168, '2077-12-21T10:52:47.635Z'), +(9.036472479137377, 27.637349257007795, '2077-12-21T10:59:41.635Z'), +(2.0574718698021517, 7.8911454285760785, '2077-12-21T11:07:24.635Z'), +(11.14583390824868, 13.227389013388544, '2077-12-21T11:11:17.635Z'), +(12.299475372800181, 17.618932926483193, '2077-12-21T11:12:56.635Z'), +(0.6170847358528271, 23.02325281881967, '2077-12-21T11:17:41.635Z'), +(3.5166237493930868, 45.583081011376464, '2077-12-21T11:26:06.635Z'), +(0.594618769380286, 36.62647892089493, '2077-12-21T11:29:35.635Z'), +(16.63374978846477, 34.8994247151258, '2077-12-21T11:35:33.635Z'), +(14.682030558754894, 29.615835938837485, '2077-12-21T11:37:34.635Z'), +(5.052257376488831, 3.435406123438415, '2077-12-21T11:47:45.635Z'), +(19.619344632166296, 32.221100287790705, '2077-12-21T11:59:27.635Z'), +(11.218423612866426, 0.5874905519455607, '2077-12-21T12:11:09.635Z'), +(6.068827970193336, 8.557152182631738, '2077-12-21T12:14:38.635Z'), +(4.749437551076542, 32.5038692128773, '2077-12-21T12:23:28.635Z'), +(7.897793277106881, 7.837809430085392, '2077-12-21T12:32:37.635Z'), +(9.780247904893637, 1.3841549845698626, '2077-12-21T12:35:04.635Z'), +(6.564725908523145, 13.47227732386315, '2077-12-21T12:39:39.635Z'), +(17.93400216168031, 37.24087808975144, '2077-12-21T12:49:13.635Z'), +(7.681700187016003, 30.139049220307367, '2077-12-21T12:53:48.635Z'), +(9.361881393847382, 47.92908235788621, '2077-12-21T13:00:20.635Z'), +(3.0700452036829446, 28.134302014875594, '2077-12-21T13:07:59.635Z'), +(6.280115873523479, 50.04862291492515, '2077-12-21T13:16:09.635Z'), +(4.2726046535092825, 20.61753500936987, '2077-12-21T13:27:02.635Z'), +(12.460934514778513, 33.20200427782632, '2077-12-21T13:32:33.635Z'), +(10.925380949220667, 34.61474158186002, '2077-12-21T13:33:18.635Z'), +(1.4256664862463624, 40.73000222131703, '2077-12-21T13:37:28.635Z'), +(0.459756781630251, 8.365789264343164, '2077-12-21T13:49:27.635Z'), +(9.784143227546988, 3.1823058795976764, '2077-12-21T13:53:23.635Z'), +(13.661160906381442, 22.293218450250507, '2077-12-21T14:00:27.635Z'), +(17.867195805687626, 7.545931454718941, '2077-12-21T14:05:56.635Z'), +(10.022864075793082, 47.30250440834758, '2077-12-21T14:20:29.635Z'), +(15.635792031742273, 49.265051494243004, '2077-12-21T14:22:40.635Z'), +(0.7456119701481057, 7.138621417610338, '2077-12-21T14:39:01.635Z'), +(14.136401373315016, 3.571898744898747, '2077-12-21T14:44:08.635Z'), +(20.000999573331043, 24.458934317439226, '2077-12-21T14:51:50.635Z'), +(5.917975883442202, 43.81231429751399, '2077-12-21T15:00:32.635Z'), +(20.20866795993493, 27.276232822265637, '2077-12-21T15:08:30.635Z'), +(2.705401656577769, 21.537969270340895, '2077-12-21T15:15:18.635Z'), +(2.1580901350295276, 37.65449395464778, '2077-12-21T15:21:16.635Z'), +(23.406043518594085, 26.74190545740585, '2077-12-21T15:30:03.635Z'), +(3.7848225514326255, 32.80735931634798, '2077-12-21T15:37:38.635Z'), +(13.905271121231479, 48.72939742395303, '2077-12-21T15:44:33.635Z'), +(8.305509207390543, 29.50492262062872, '2077-12-21T15:51:50.635Z'), +(23.359771913605424, 24.484920884809956, '2077-12-21T15:57:41.635Z'), +(23.102996309062217, 49.343759650779056, '2077-12-21T16:06:08.635Z'), +(11.876119135029652, 37.71546403801091, '2077-12-21T16:11:58.635Z'), +(3.5357775343427766, 46.12690769839824, '2077-12-21T16:16:20.635Z'), +(9.107031591437318, 50.17911595308854, '2077-12-21T16:18:52.635Z'), +(3.284139829643176, 15.988389986242165, '2077-12-21T16:31:38.635Z'), +(19.57566770885542, 36.902860080454786, '2077-12-21T16:41:18.635Z'), +(7.161111808353817, 30.439026740938306, '2077-12-21T16:46:27.635Z'), +(21.23233565487668, 22.501009512918134, '2077-12-21T16:52:23.635Z'), +(19.752297634762062, 32.8467437509367, '2077-12-21T16:56:00.635Z'), +(5.531228393295073, 10.070292721412986, '2077-12-21T17:05:45.635Z'), +(17.262205919476205, 44.66094230209568, '2077-12-21T17:19:01.635Z'), +(15.473180640951885, 41.080011311123535, '2077-12-21T17:20:27.635Z'), +(14.837359268363313, 8.025607628970919, '2077-12-21T17:32:15.635Z'), +(1.3557800882297106, 0.20477889823544812, '2077-12-21T17:38:00.635Z'), +(18.1818305555296, 0.586433948490406, '2077-12-21T17:44:14.635Z'), +(13.93138581871588, 30.388160107549574, '2077-12-21T17:54:57.635Z'), +(10.370070716085243, 3.951769604150896, '2077-12-21T18:04:36.635Z'), +(5.899032766376548, 37.673457992621316, '2077-12-21T18:17:04.635Z'), +(22.301103200488743, 23.429256570198202, '2077-12-21T18:25:00.635Z'), +(22.0259766111453, 45.2709499446465, '2077-12-21T18:32:29.635Z'), +(20.487215203429475, 21.605710645841082, '2077-12-21T18:40:40.635Z'), +(1.5714533493454215, 4.09560995038307, '2077-12-21T18:50:07.635Z'), +(20.4109147598724, 20.396722149841416, '2077-12-21T18:59:15.635Z'), +(17.83554694986992, 41.16370633662407, '2077-12-21T19:06:34.635Z'), +(6.260226739252524, 47.02315656633268, '2077-12-21T19:11:21.635Z'), +(5.453100300878114, 3.15940278622221, '2077-12-21T19:27:31.635Z'), +(13.674057355979304, 38.142695951989815, '2077-12-21T19:40:38.635Z'), +(2.0324707901246857, 15.958750903777805, '2077-12-21T19:49:50.635Z'), +(3.7073596975257783, 47.885199975014785, '2077-12-21T20:01:40.635Z'), +(9.385554998626667, 0.9120767663560586, '2077-12-21T20:19:04.635Z'), +(10.96423679696135, 46.09755773644275, '2077-12-21T20:35:32.635Z'), +(20.781667578050513, 48.97410707011662, '2077-12-21T20:39:18.635Z'), +(2.922037201536662, 33.474377598065274, '2077-12-21T20:47:58.635Z'), +(1.0310144136037513, 9.056147873850998, '2077-12-21T20:57:02.635Z'), +(10.04869379416708, 16.57193603011519, '2077-12-21T21:01:22.635Z'), +(3.300346390574233, 1.4371446626046478, '2077-12-21T21:07:28.635Z'), +(17.040190948959427, 37.013553040503595, '2077-12-21T21:21:22.635Z'), +(16.252637046333586, 2.108846025498202, '2077-12-21T21:33:44.635Z'), +(17.75434834727365, 47.5926915093785, '2077-12-21T21:49:49.635Z'), +(7.723624297085643, 42.536422147439886, '2077-12-21T21:53:57.635Z'), +(22.3396042652407, 20.372187801693013, '2077-12-21T22:03:31.635Z'), +(20.542871095823134, 18.074686130263274, '2077-12-21T22:04:33.635Z'), +(19.520551375603738, 16.080717188979754, '2077-12-21T22:05:20.635Z'), +(12.108445579970567, 25.26223722943706, '2077-12-21T22:09:36.635Z'), +(17.53284546973603, 36.61847479087044, '2077-12-21T22:14:08.635Z'), +(0.22473068061468007, 10.116313679023596, '2077-12-21T22:25:43.635Z'), +(15.330116680684547, 3.8895484661610618, '2077-12-21T22:31:45.635Z'), +(5.054805493623566, 20.644993072276538, '2077-12-21T22:38:56.635Z'), +(16.54930700322167, 41.220293183576764, '2077-12-21T22:47:32.635Z'), +(23.54200440584713, 37.08954703433549, '2077-12-21T22:50:29.635Z'), +(10.336167643668194, 3.5355817781458976, '2077-12-21T23:03:18.635Z'), +(16.715315727979085, 39.33733306640079, '2077-12-21T23:16:23.635Z'), +(14.808532133501034, 14.138520849543841, '2077-12-21T23:25:23.635Z'), +(13.649591057021246, 24.070747602356455, '2077-12-21T23:28:58.635Z'), +(16.52709805262636, 16.94488910335289, '2077-12-21T23:31:43.635Z'), +(10.271116480090546, 38.129263915180836, '2077-12-21T23:39:41.635Z'), +(10.010728879165072, 5.807953748462943, '2077-12-21T23:51:28.635Z'), +(17.975658720982292, 49.45109140157044, '2077-12-22T00:07:24.635Z'), +(5.653838568452292, 32.083191352858734, '2077-12-22T00:15:10.635Z'), +(15.191956451019076, 18.93423581431582, '2077-12-22T00:21:07.635Z'), +(12.91876394272732, 21.556095446588568, '2077-12-22T00:22:22.635Z'), +(4.4298487801575925, 21.821775691647147, '2077-12-22T00:25:30.635Z'), +(21.209447283345174, 1.0894360555830325, '2077-12-22T00:35:12.635Z'), +(14.531100459774871, 0.6184002396388973, '2077-12-22T00:37:40.635Z'), +(11.655554686905225, 41.1826347381492, '2077-12-22T00:52:19.635Z'), +(3.6607713938793864, 46.64988641286957, '2077-12-22T00:55:53.635Z'), +(20.206317027272572, 48.09776083098932, '2077-12-22T01:02:02.635Z'), +(14.224188870517668, 45.40945317459845, '2077-12-22T01:04:26.635Z'), +(16.57772371174334, 33.80861908796438, '2077-12-22T01:08:40.635Z'), +(12.032803999120517, 11.417458742432993, '2077-12-22T01:16:52.635Z'), +(3.782976909836844, 27.273872051682297, '2077-12-22T01:23:26.635Z'), +(1.0725107987697293, 15.879725551749969, '2077-12-22T01:27:46.635Z'), +(14.540630736021264, 23.975728094289224, '2077-12-22T01:33:34.635Z'), +(0.3675349359683059, 29.486653805953903, '2077-12-22T01:39:11.635Z'), +(12.023289869013066, 9.174299482519675, '2077-12-22T01:47:48.635Z'), +(14.093946525269159, 20.628035279507724, '2077-12-22T01:52:00.635Z'), +(6.855004539279775, 31.068689148031385, '2077-12-22T01:56:39.635Z'), +(20.389637575804837, 34.02082602149924, '2077-12-22T02:01:46.635Z'), +(19.40683042742869, 1.0149152681933038, '2077-12-22T02:13:15.635Z'), +(16.26537586522829, 5.146986064260186, '2077-12-22T02:15:06.635Z'), +(17.33325822071695, 46.3079688436434, '2077-12-22T02:29:40.635Z'), +(15.315187301938584, 39.51476510401545, '2077-12-22T02:32:11.635Z'), +(20.0166163353545, 8.331099629629382, '2077-12-22T02:43:19.635Z'), +(0.8165385712436286, 34.95727927693445, '2077-12-22T02:55:18.635Z'), +(1.5181411348965657, 24.23992282186841, '2077-12-22T02:59:16.635Z'), +(20.34480063025266, 4.430269178204859, '2077-12-22T03:09:16.635Z'), +(22.916433393430573, 9.087294228918255, '2077-12-22T03:11:07.635Z'), +(11.65493900852554, 3.258572135612734, '2077-12-22T03:15:46.635Z'), +(16.24470609380456, 17.303540672592135, '2077-12-22T03:21:05.635Z'), +(10.57762717788147, 24.43613433674897, '2077-12-22T03:24:24.635Z'), +(16.93524616395197, 7.840246124135759, '2077-12-22T03:30:49.635Z'), +(9.867264821669787, 35.435525004543585, '2077-12-22T03:41:05.635Z'), +(12.609405621870275, 4.735044470142431, '2077-12-22T03:52:17.635Z'), +(20.953341364680035, 39.504129404954085, '2077-12-22T04:04:58.635Z'), +(21.517797577704926, 37.45967673681708, '2077-12-22T04:05:42.635Z'), +(11.302470429797431, 24.05026669941523, '2077-12-22T04:11:46.635Z'), +(6.09344915920499, 31.122719108135964, '2077-12-22T04:14:59.635Z'), +(9.696679953783391, 17.897283404208714, '2077-12-22T04:20:01.635Z'), +(3.295139105002835, 29.886596145120638, '2077-12-22T04:25:01.635Z'), +(16.498887821104915, 31.338703864536583, '2077-12-22T04:29:56.635Z'), +(0.9188580759659379, 30.498014302451796, '2077-12-22T04:35:42.635Z'), +(16.804317411763254, 35.499631394446055, '2077-12-22T04:41:51.635Z'), +(6.279945556902922, 42.01567176453955, '2077-12-22T04:46:24.635Z'), +(11.44984948912621, 38.65548796427206, '2077-12-22T04:48:40.635Z'), +(21.84009112439067, 3.745414787615318, '2077-12-22T05:01:36.635Z'), +(9.357848070902515, 1.8433348307786592, '2077-12-22T05:06:16.635Z'), +(13.381402141836883, 7.551897410674996, '2077-12-22T05:08:49.635Z'), +(22.640131967330205, 2.6617168118833963, '2077-12-22T05:12:39.635Z'), +(12.921095571207989, 10.23074766521042, '2077-12-22T05:17:07.635Z'), +(2.2186210785987535, 0.7433924592607958, '2077-12-22T05:22:23.635Z'), +(19.991929118262778, 24.80924200943988, '2077-12-22T05:33:18.635Z'), +(8.259549093135861, 34.941748767394444, '2077-12-22T05:38:58.635Z'), +(22.303872588183093, 20.365831786710718, '2077-12-22T05:46:19.635Z'), +(1.3598499238591317, 31.056280338975746, '2077-12-22T05:54:58.635Z'), +(0.15442245055613615, 34.548843278135564, '2077-12-22T05:56:20.635Z'), +(0.698369856202904, 5.652234005212192, '2077-12-22T06:07:02.635Z'), +(0.7648386556811453, 34.30637620441131, '2077-12-22T06:17:39.635Z'), +(11.017823572842353, 23.44511992321386, '2077-12-22T06:23:09.635Z'), +(6.199791727178041, 26.43513407334735, '2077-12-22T06:25:14.635Z'), +(18.542075430315094, 17.291083379996714, '2077-12-22T06:30:52.635Z'), +(5.578382414896217, 50.32402283192106, '2077-12-22T06:43:44.635Z'), +(19.663133457254958, 30.41036758481712, '2077-12-22T06:52:36.635Z'), +(21.632811028198674, 42.73202570586217, '2077-12-22T06:56:56.635Z'), +(17.44119031166847, 34.39007082176827, '2077-12-22T07:00:14.635Z'), +(15.662314812466644, 8.551239869325054, '2077-12-22T07:09:25.635Z'), +(17.244971184235368, 17.00146139327903, '2077-12-22T07:12:28.635Z'), +(15.984433807412374, 33.13263570834044, '2077-12-22T07:18:12.635Z'), +(10.463652199663661, 20.92072320557669, '2077-12-22T07:23:03.635Z'), +(11.755445766762318, 13.55476279803548, '2077-12-22T07:25:46.635Z'), +(8.727803580943357, 36.93922844806074, '2077-12-22T07:34:21.635Z'), +(11.734061901962022, 9.89920616209729, '2077-12-22T07:44:16.635Z'), +(10.886358342933693, 23.535834083826515, '2077-12-22T07:49:13.635Z'), +(5.050549668215188, 42.39357512814946, '2077-12-22T07:56:27.635Z'), +(19.53647005266269, 16.945313442860606, '2077-12-22T08:07:05.635Z'), +(6.227505277605745, 28.063479699697666, '2077-12-22T08:13:26.635Z'), +(6.788474510708814, 5.361060624472254, '2077-12-22T08:21:47.635Z'); diff --git a/rushs/data-clash/step-2/geo_filter.sql b/rushs/data-clash/step-2/geo_filter.sql new file mode 100644 index 0000000..e3711da --- /dev/null +++ b/rushs/data-clash/step-2/geo_filter.sql @@ -0,0 +1,10 @@ +SELECT t.* +FROM geo_data.points_of_interest AS p, +geo_data.population_tracking AS t +WHERE p.name = 'Family Business, Pizza Place' +AND 300 >= 6371 * acos( + cos(radians(p.latitude)) * cos(radians(t.latitude)) * + cos(radians(t.longitude) - radians(p.longitude)) + + sin(radians(p.latitude)) * sin(radians(t.latitude)) +) +ORDER BY t.timestamp; diff --git a/rushs/data-clash/step-2/geo_pattern.sql b/rushs/data-clash/step-2/geo_pattern.sql new file mode 100644 index 0000000..b4a298f --- /dev/null +++ b/rushs/data-clash/step-2/geo_pattern.sql @@ -0,0 +1,36 @@ +CREATE TABLE geo_data.movement_pattern ( + start_lat DOUBLE PRECISION, + start_lon DOUBLE PRECISION, + end_lat DOUBLE PRECISION, + end_lon DOUBLE PRECISION, + distance DOUBLE PRECISION, + duration DOUBLE PRECISION, + "timestamp" TIMESTAMP +); + +INSERT INTO geo_data.movement_pattern +SELECT res.* +FROM + (SELECT + t.latitude::DOUBLE PRECISION AS start_lat, + t.longitude::DOUBLE PRECISION AS start_lon, + lead(t.latitude) OVER(ORDER BY t.timestamp)::double precision AS end_lat, + lead(t.longitude) OVER(ORDER BY t.timestamp)::double precision AS end_lon, + 6371 * acos( + cos(radians(t.latitude)) * cos(radians(lead(t.latitude) OVER(ORDER BY t.timestamp))) * + cos(radians(lead(t.longitude) OVER(ORDER BY t.timestamp)) - radians(t.longitude)) + + sin(radians(t.latitude)) * sin(radians(lead(t.latitude) OVER(ORDER BY t.timestamp))) + )::double precision AS distance, + extract(second from (lead(t.timestamp) OVER(ORDER BY t.timestamp) - t.timestamp))::DOUBLE PRECISION AS duration, + t.timestamp + FROM geo_data.population_tracking AS t + ) AS res, +geo_data.points_of_interest AS p +WHERE p.name = 'Family Business, Pizza Place' +AND 300 >= 6371 * acos( + cos(radians(p.latitude)) * cos(radians(res.start_lat)) * + cos(radians(res.start_lon) - radians(p.longitude)) + + sin(radians(p.latitude)) * sin(radians(res.start_lat)) +) +AND duration < 10 +ORDER BY res.timestamp diff --git a/rushs/data-clash/step-3/napoleon_analysis.sql b/rushs/data-clash/step-3/napoleon_analysis.sql new file mode 100644 index 0000000..cdbb4bd --- /dev/null +++ b/rushs/data-clash/step-3/napoleon_analysis.sql @@ -0,0 +1,46 @@ +SELECT + id, + right(location, 7) AS location, + end_time - start_time AS duration, + left(details, 10) AS details, + CASE + WHEN + NOT regexp_like(details, '^([[:ascii:]])*$') + THEN 'invalid_characters' + WHEN + start_time > end_time OR location NOT LIKE '%MMT' + THEN 'improbable_values' + WHEN start_time IS NULL OR end_time IS NULL THEN 'missing_timestamp' + WHEN + location IS NULL OR latitude IS NULL OR longitude IS NULL + THEN 'missing_location' + WHEN + EXISTS ( + SELECT * + FROM napoleon_data.public_reports AS t + WHERE + r.id > t.id + AND r.location = t.location + AND r.start_time = t.start_time + AND r.end_time = t.end_time + AND r.details = t.details + ) + THEN 'duplicate_report' + END AS issue +FROM napoleon_data.public_reports AS r +WHERE + NOT regexp_like(details, '^([[:ascii:]])*$') + OR start_time IS NULL OR end_time IS NULL + OR start_time > end_time + OR location NOT LIKE '%MMT' + OR location IS NULL OR latitude IS NULL OR longitude IS NULL + OR EXISTS ( + SELECT * + FROM napoleon_data.public_reports AS t + WHERE + r.id > t.id + AND r.location = t.location + AND r.start_time = t.start_time + AND r.end_time = t.end_time + AND r.details = t.details + ) diff --git a/rushs/data-clash/step-3/napoleon_connections.sql b/rushs/data-clash/step-3/napoleon_connections.sql new file mode 100644 index 0000000..170f635 --- /dev/null +++ b/rushs/data-clash/step-3/napoleon_connections.sql @@ -0,0 +1,29 @@ +SELECT + t.id AS individual_id, + t.name, + t.role, + t.affiliation AS current_affiliation, + p.affiliation AS historical_affiliation +FROM surveillance_data.current_targets AS t +INNER JOIN napoleon_data.historical_people AS p + ON + t.name = p.name + OR t.affiliation != 'N/A' +WHERE + EXISTS ( + SELECT 1 FROM (SELECT + a1.group_name_1, + a2.group_name_2 + FROM surveillance_data.group_affinities AS a1, + surveillance_data.group_affinities AS a2 + WHERE a1.group_name_2 = a2.group_name_1 + UNION + SELECT + group_name_1, + group_name_2 + FROM surveillance_data.group_affinities) AS test + WHERE + (group_name_1 = p.affiliation AND t.affiliation = group_name_2) + OR (group_name_1 = t.affiliation AND group_name_2 = p.affiliation) + ) + OR t.affiliation = p.affiliation diff --git a/rushs/data-clash/step-3/napoleon_filter.sql b/rushs/data-clash/step-3/napoleon_filter.sql new file mode 100644 index 0000000..797f085 --- /dev/null +++ b/rushs/data-clash/step-3/napoleon_filter.sql @@ -0,0 +1,30 @@ +WITH proximity_filtered AS ( + SELECT DISTINCT ON (r.id) + r.id, + r.location, + r.details, + r.start_time, + MIN(6371 * ACOS( + COS(RADIANS(r.latitude)) * COS(RADIANS(l.latitude)) + * COS(RADIANS(l.longitude) - RADIANS(r.longitude)) + + SIN(RADIANS(r.latitude)) * SIN(RADIANS(l.latitude)) + )) AS distance + FROM napoleon_data.public_reports AS r, + napoleon_data.critical_locations AS l + WHERE + 300 >= (6371 * ACOS( + COS(RADIANS(r.latitude)) * COS(RADIANS(l.latitude)) + * COS(RADIANS(l.longitude) - RADIANS(r.longitude)) + + SIN(RADIANS(r.latitude)) * SIN(RADIANS(l.latitude)) + )) + AND details ILIKE '%Napoleon%' + AND start_time BETWEEN '2069-01-01' AND '2070-12-31' + GROUP BY r.id, r.location, r.details, r.start_time +) + +SELECT + id, + location, + distance +FROM proximity_filtered +ORDER BY distance, id diff --git a/rushs/data-clash/step-3/napoleon_synthesis.sql b/rushs/data-clash/step-3/napoleon_synthesis.sql new file mode 100644 index 0000000..f71dd09 --- /dev/null +++ b/rushs/data-clash/step-3/napoleon_synthesis.sql @@ -0,0 +1,43 @@ +CREATE VIEW napoleon_affair_view AS +WITH count_report AS ( + SELECT + location, + COUNT(*) AS total_reports + FROM napoleon_data.public_reports + GROUP BY location +), +persons_mention AS ( + SELECT + location, + name AS person, + count(*) AS occ + FROM napoleon_data.public_reports + INNER JOIN napoleon_data.historical_people + ON details LIKE concat('%', name, '%') + GROUP BY location, name +), +most_mentioned AS ( + SELECT + location, + person AS most_mentioned_person, + occ AS occurrences_most_mentioned_person, + row_number() OVER (PARTITION BY location ORDER BY occ DESC) AS rn + FROM persons_mention +), +unique_people_count AS ( + SELECT + location, + COUNT(DISTINCT person) AS total_people_mentioned + FROM persons_mention + GROUP BY location +) + +SELECT + rc.location, + total_reports, + total_people_mentioned, + most_mentioned_person, + occurrences_most_mentioned_person +FROM count_report AS rc +INNER JOIN unique_people_count AS uc ON rc.location = uc.location +INNER JOIN most_mentioned AS mmmm ON mmmm.location = rc.location AND mmmm.rn = 1; diff --git a/rushs/data-clash/step-3/napoleon_timeline.sql b/rushs/data-clash/step-3/napoleon_timeline.sql new file mode 100644 index 0000000..eff8be1 --- /dev/null +++ b/rushs/data-clash/step-3/napoleon_timeline.sql @@ -0,0 +1,85 @@ +WITH rapports_valides AS ( + SELECT + id, + location, + start_time, + end_time, + latitude, + longitude + FROM napoleon_data.public_reports + WHERE location IS NOT NULL + AND start_time IS NOT NULL + AND end_time IS NOT NULL + AND latitude IS NOT NULL + AND longitude IS NOT NULL +), +rapports_ordonnes AS ( + SELECT + id, + location, + start_time, + end_time, + latitude, + longitude, + LAG(id) OVER (ORDER BY start_time) AS pid, + LAG(location) OVER (ORDER BY start_time) AS ploc, + LAG(start_time) OVER (ORDER BY start_time) AS pstart, + LAG(end_time) OVER (ORDER BY start_time) AS pend, + LAG(latitude) OVER (ORDER BY start_time) AS plat, + LAG(longitude) OVER (ORDER BY start_time) AS plong + FROM rapports_valides +), +diffrapports AS ( + SELECT + id, + location, + start_time, + end_time, + latitude, + longitude, + pid, + ploc, + pstart, + pend, + plat, + plong, + extract(EPOCH from (start_time - pend)) AS tdiff, + (6371 * ACOS( + COS(RADIANS(latitude)) * COS(RADIANS(plat)) + * COS(RADIANS(plong) - RADIANS(longitude)) + + SIN(RADIANS(latitude)) * SIN(RADIANS(plat)) + )) AS d + FROM rapports_ordonnes +), +analyse_rapports AS ( + SELECT + id, + location, + start_time, + end_time, + latitude, + longitude, + pid, + ploc, + pstart, + pend, + plat, + plong, + tdiff, + d, + CASE + WHEN start_time < pend THEN 'overlapping_timeframes' + WHEN tdiff < 7200 AND d > 500 THEN 'moving_fast' + WHEN extract(EPOCH from (end_time - start_time)) > 86400 THEN 'long_duration' + WHEN d IS NULL OR tdiff IS NULL THEN 'missing_data' + WHEN d > 500 THEN 'long_distance' + ELSE 'clear' + END AS issue + FROM diffrapports +) +SELECT + tdiff AS time_difference, + d AS distance, + issue +FROM analyse_rapports +ORDER BY start_time diff --git a/rushs/eplace/.env b/rushs/eplace/.env new file mode 100644 index 0000000..f372047 --- /dev/null +++ b/rushs/eplace/.env @@ -0,0 +1,8 @@ +VITE_HOST="localhost" +VITE_PORT="8080" +VITE_URL="http://${VITE_HOST}:${VITE_PORT}" + +#VITE_API_URL="http://localhost:3333" +VITE_API_URL="https://eplace.assistants.epita.fr" +VITE_AUTH_URL="https://cri.epita.fr" +VITE_CLIENT_ID="assistants-atelier-js" diff --git a/rushs/eplace/.gitignore b/rushs/eplace/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/rushs/eplace/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/rushs/eplace/.prettierrc.js b/rushs/eplace/.prettierrc.js new file mode 100644 index 0000000..fcc77f6 --- /dev/null +++ b/rushs/eplace/.prettierrc.js @@ -0,0 +1,6 @@ +module.exports = { + tabWidth: 4, + useTabs: false, // Use spaces instead of defaults tabs + semi: true, // Force semilicons + printWidth: 80, // Max width +}; diff --git a/rushs/eplace/eslint.config.mjs b/rushs/eplace/eslint.config.mjs new file mode 100644 index 0000000..a315e71 --- /dev/null +++ b/rushs/eplace/eslint.config.mjs @@ -0,0 +1,71 @@ +import jestPlugin from "eslint-plugin-jest"; +import globals from "globals"; +import prettierPlugin from "eslint-plugin-prettier"; // Import the Prettier plugin +import eslintComments from "eslint-plugin-eslint-comments"; +import js from "@eslint/js"; + +const cleanGlobals = (obj) => + Object.fromEntries( + Object.entries(obj).map(([key, val]) => [key.trim(), val]), + ); + +export default [ + js.configs.recommended, // Nice defaults rules + { + files: ["**/*.js", "**/*.mjs"], // Apply to .js and .mjs files + languageOptions: { + sourceType: "module", + globals: { + AudioWorkletGlobalScope: "readonly", + ...cleanGlobals(globals.node), + ...cleanGlobals(jestPlugin.environments.globals.globals), + ...cleanGlobals(globals.browser), + }, + }, + plugins: { + prettier: prettierPlugin, // Add Prettier plugin correctly + jest: jestPlugin, // Jest plugin + "eslint-comments": eslintComments, // Add plugin to detect cheats + }, + rules: { + "eslint-comments/no-use": ["error", { allow: [] }], // Disallow disable rules + curly: ["error", "all"], // Enforce curlies in conditionnal blocks + "brace-style": ["error", "1tbs"], + "max-statements-per-line": ["error", { max: 1 }], + semi: ["error", "always"], // Enforce semicolons + "prefer-const": "error", // Prefer const over let + "no-undef": "error", // Detect definition + "no-unused-vars": [ + "error", + { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }, + ], + // Detect error of line width (but can't fix them without the prettier) + "max-len": [ + "error", + { + code: 80, + tabWidth: 4, + ignoreComments: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + ignoreRegExpLiterals: true, + }, + ], // More rules to complete with the existants in .prettierrc.js file + "prettier/prettier": ["error"], // Enforce Prettier formatting + "padding-line-between-statements": [ + // Create nice looking paddings between statements + "error", + { + blankLine: "always", + prev: ["const", "let", "var", "if", "for", "while", "do"], + next: "*", + }, + { + blankLine: "any", + prev: ["const", "let", "var"], + next: ["const", "let", "var"], + }, + ], // Requires blank lines between the given 2 kinds of statements + }, + }, +]; diff --git a/rushs/eplace/package.json b/rushs/eplace/package.json new file mode 100644 index 0000000..fb69f09 --- /dev/null +++ b/rushs/eplace/package.json @@ -0,0 +1,31 @@ +{ + "name": "eplace-client", + "private": true, + "version": "1.0.0", + "scripts": { + "dev": "vite", + "debug": "vite --mode debug" + }, + "devDependencies": { + "eslint": "^9.25.1", + "eslint-config-prettier": "^8.8.0", + "eslint-config-standard": "^17.0.0", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0", + "less": "^4.1.3", + "vite": "^4.2.0" + }, + "dependencies": { + "axios": "^1.4.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-jest": "^28.11.0", + "eslint-plugin-prettier": "^5.2.6", + "jquery": "^3.6.4", + "jwt-decode": "^3.1.2", + "node-fetch": "^3.3.1", + "prettier": "^3.5.3", + "socket.io-client": "^4.6.1", + "uuid": "^9.0.0" + } +} diff --git a/rushs/eplace/public/default-avatar.png b/rushs/eplace/public/default-avatar.png Binary files differnew file mode 100644 index 0000000..7c0db88 --- /dev/null +++ b/rushs/eplace/public/default-avatar.png diff --git a/rushs/eplace/public/default-icon.png b/rushs/eplace/public/default-icon.png Binary files differnew file mode 100644 index 0000000..5dc5a4f --- /dev/null +++ b/rushs/eplace/public/default-icon.png diff --git a/rushs/eplace/public/favicon.ico b/rushs/eplace/public/favicon.ico Binary files differnew file mode 100644 index 0000000..10b730f --- /dev/null +++ b/rushs/eplace/public/favicon.ico diff --git a/rushs/eplace/public/selector.svg b/rushs/eplace/public/selector.svg new file mode 100644 index 0000000..2076e95 --- /dev/null +++ b/rushs/eplace/public/selector.svg @@ -0,0 +1,14 @@ +<svg fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" height="120%" width="120%"> + <g stroke-opacity=".6" stroke-width="2"> + <g stroke="#000"> + <path d="m3 9v-6h6"></path> + <path d="m14.9999 3h6v6"></path> + <path d="m20.9999 15.0001v6h-6"></path> + <path d="m9 21.0001h-6v-6"></path> + </g> + <path d="m1 9v-8h8" stroke="#fff"></path> + <path d="m15 1h8v8" stroke="#fff"></path> + <path d="m23 15v8h-8" stroke="#fff"></path> + <path d="m9 23h-8v-8" stroke="#fff"></path> + </g> +</svg> diff --git a/rushs/eplace/server/.env b/rushs/eplace/server/.env new file mode 100644 index 0000000..7ff72e7 --- /dev/null +++ b/rushs/eplace/server/.env @@ -0,0 +1,36 @@ +# Environment variables declared in this file are automatically made available to Prisma. +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema + +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. +# See the documentation for all the connection string options: https://pris.ly/d/connection-strings + +SERVER_PORT=3333 +WSS_PORT=3334 + +POSTGRES_USER="postgres" +POSTGRES_PASSWORD="postgres" +POSTGRES_HOST="postgres" +POSTGRES_PORT=5432 +POSTGRES_DB="eplace" +POSTGRES_SCHEMA="public" +DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?schema=${POSTGRES_SCHEMA}" + + +REDIS_HOST="redis" +REDIS_PORT=6379 + +PUBLIC_API_URL="http://localhost:3333/api" +JWKS_URI="https://cri.epita.fr/jwks" +# DO NOT ERASE THIS UID, IT IS USE AS DEFAULT USER TO SETUP ROOMs, PIXELS +# CHECK README FOR MORE DETAILS +# You can add more admin uids by separating them with a comma +# Example: 9361,9362,9363 +ADMIN_UID_LIST="9361" + + +RATE_LIMITS_CONFIG_PATH="./config/rate-limits.config.json" +ROOMS_CONFIG_PATH="./config/rooms.config.json" + +DISABLE_ADMIN_PREVILEGES="true" +DISABLE_AUTH="false" +DISABLE_RATE_LIMITING="false" diff --git a/rushs/eplace/server/config/default-canvas-250.txt b/rushs/eplace/server/config/default-canvas-250.txt new file mode 100644 index 0000000..9e52292 --- /dev/null +++ b/rushs/eplace/server/config/default-canvas-250.txt @@ -0,0 +1 @@ +B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BcB„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BˆcÆ0„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„CÆ1ŒaB„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BcÆ1ŒcÆ!!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!†1ŒcÆ1ŒcÆ1ŒcÆ!!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„"Æ1ŒcÆ1ŒcÆ1ŒcÆ1Œc‚„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„CÆ1ŒcÆ1ŒcÆ1ŒcÆ1ŒcÆ1ŒaB„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BˆcÆ1ŒcÆ1Œb‚„"„1ŒcÆ1ŒcÆ „!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BˆcÆ1ŒcÆ „!B„!B„!D1ŒcÆ1ŒcB„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BˆcÆ1Œc‚„!B„C„!B„!Æ1ŒcÆ0„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BˆcÆ1ŒcB„!B„#Æ1ˆ!B„!BˆcÆ1ŒcB„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„cÆ1ŒbB„!B„!Æ1ŒcB„!B„!F1ŒcÆ „!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„CÆ1ŒaB„!B„!Æ1ŒcÆ„!B„!B„CÆ1ŒaB„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„#Æ1ŒaB„!B„!B1ŒaÆ1ˆ!B„!B„!D1ŒcÄ„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„"Æ1ŒbB„!B„!BŒcBŒcB„!B„!B„cÆ1Œ!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!Æ1ŒbB„!B„!B„!„c„!B„!B„!F1Œc‚„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!Æ1ŒcB„!B„!B„!B„!Æ„!B„!B„!BˆcÆ1„!B„!B„!BˆBB„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BˆcÆ1ŒcB„!B„!B„!B„!B„!B„!B„!B„!Æ1ŒcÆ0„!B„!BˆcÆ„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„cÆ1ŒcB„!B„!B„!B„!B„!B„!B„!B„!BŒcÆ1ŒbB„!BˆcÆ1Œ!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„"Æ1Œc„!BŒcÄ„!B„!B„!B„!B„!B„!B„"Æ1Œc„!B„cÆ1ŒcB„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!Æ1ŒcÄ„!B„cÆ1Œ!B„!B„!B„!B„!B1„!B„!B1ŒcÆ1!B„#Æ1ŒcÆ„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B1ŒcÆ „!B„"Æ1ŒcB„!B„!B„!B„!F1ŒcB„!B„cÆ1ŒAB„"Æ1ŒaÆ1!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!B„!BŒcÆ1!B„!Æ1ˆCÆ„!B„!B„!B„!B1ŒcÆ0„!B„!Æ1ŒcB„!Æ1Œb diff --git a/rushs/eplace/server/config/default-canvas-50.txt b/rushs/eplace/server/config/default-canvas-50.txt Binary files differnew file mode 100644 index 0000000..ff61da9 --- /dev/null +++ b/rushs/eplace/server/config/default-canvas-50.txt diff --git a/rushs/eplace/server/config/rate-limits.config.json b/rushs/eplace/server/config/rate-limits.config.json new file mode 100644 index 0000000..aeb1cd2 --- /dev/null +++ b/rushs/eplace/server/config/rate-limits.config.json @@ -0,0 +1,54 @@ +{ + "testsLimiter": { + "limit": 10, + "interval": 1 + }, + "getCanvasLimiter": { + "limit": 10, + "interval": 1 + }, + "getPixelLimiter": { + "limit": 10, + "interval": 1 + }, + "placePixelLimiter": { + "limit": 1, + "interval": 30 + }, + "getRoomsLimiter": { + "limit": 10, + "interval": 1 + }, + "getRoomConfigLimiter": { + "limit": 10, + "interval": 1 + }, + "createRoomLimiter": { + "limit": 1, + "interval": 300 + }, + "updateRoomLimiter": { + "limit": 1, + "interval": 1 + }, + "deleteRoomLimiter": { + "limit": 2, + "interval": 1 + }, + "getStudentLimiter": { + "limit": 10, + "interval": 1 + }, + "updateStudentLimiter": { + "limit": 1, + "interval": 1 + }, + "sendMessageLimiter": { + "limit": 1, + "interval": 1 + }, + "reportRoomLimiter": { + "limit": 1, + "interval": 5 + } +} diff --git a/rushs/eplace/server/config/rooms.config.json b/rushs/eplace/server/config/rooms.config.json new file mode 100644 index 0000000..b50080e --- /dev/null +++ b/rushs/eplace/server/config/rooms.config.json @@ -0,0 +1,39 @@ +{ + "maxRoomsCreatedPerUser": 3, + "rooms": { + "default": { + "metadata": { + "canvasDimensions": 50 + }, + "settings": { + "roomColors": "#ffffff,#d4d7d9,#898d90,#515252,#000000,#fe4500,#fea800,#fed634,#01a268,#7eed56,#2350a4,#3690ea,#51e9f4,#811f9f,#b44bc0,#ff99aa,#9c6925", + "defaultCanvas": "config/default-canvas-50.txt" + } + }, + "epi-place": { + "metadata": { + "name": "epi/place", + "slug": "epi-place", + "description": "Le Roi de la malice est passé par là ", + "canvasDimensions": 250, + "iconURL": "https://media.tenor.com/XUHq8pN_maQAAAAi/puffer-fish-fish.gif", + "isPublic": true + }, + "settings": { + "roomColors": "#ffffff,#d4d7d9,#898d90,#515252,#6c001a,#be0039,#fe4500,#fea800,#fed634,#fff8b8,#01a268,#00cc78,#7eed56,#02756f,#019eaa,#00ccbf,#2350a4,#3690ea,#51e9f4,#493ac1,#6a5cff,#94b3ff,#811f9f,#b44bc0,#e4aaff,#de107f,#ff3981,#ff99aa,#6d482f,#9c6925,#ffb470,#000000", + "defaultCanvas": "config/default-canvas-250.txt" + } + }, + "test": { + "metadata": { + "name": "Test Room", + "description": "A room small enough to test things out", + "canvasDimensions": 10, + "isPublic": true + }, + "settings": { + "roomColors": "#ffffff,#d4d7d9,#898d90,#515252,#000000,#fe4500,#fea800,#fed634,#01a268,#7eed56,#2350a4,#3690ea,#51e9f4,#811f9f,#b44bc0,#ff99aa,#9c6925" + } + } + } +}
\ No newline at end of file diff --git a/rushs/eplace/server/docker-compose.yml b/rushs/eplace/server/docker-compose.yml new file mode 100644 index 0000000..f0419b9 --- /dev/null +++ b/rushs/eplace/server/docker-compose.yml @@ -0,0 +1,56 @@ +version: '3.9' +services: + postgres: + image: registry.cri.epita.fr/ing/assistants/public/registry/postgres:15.2-alpine + container_name: postgres + restart: always + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: eplace + expose: + - 5432 + volumes: + - postgres-data:/var/lib/postgresql/data + # Proper docker-compose would use named networks + # networks: + # - postgres-network + redis: + image: registry.cri.epita.fr/ing/assistants/public/registry/redis:7.0.9-alpine + container_name: redis + restart: always + expose: + - 6379 + volumes: + - redis-data:/data + # Proper docker-compose would use named networks + # networks: + # - redis-network + eplace: + image: registry.cri.epita.fr/ing/assistants/public/registry/eplace:latest + container_name: eplace + restart: always + environment: + NODE_ENV: production + volumes: + - ./config:/usr/src/app/config + - type: 'bind' + source: './.env' + target: '/usr/src/app/.env' + ports: + - 3000:3000 + - 3333:3333 + # Proper docker-compose would use named networks + # networks: + # - postgres-network + # - redis-network + depends_on: + - postgres + - redis +volumes: + postgres-data: + redis-data: + # Proper docker-compose would use named networks + # networks: + # postgres-network: + # redis-network: diff --git a/rushs/eplace/server/openapi/openapi.json b/rushs/eplace/server/openapi/openapi.json new file mode 100644 index 0000000..4f0dd77 --- /dev/null +++ b/rushs/eplace/server/openapi/openapi.json @@ -0,0 +1,5064 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "E/PLACE API", + "description": "Publicly available API for E/PLACE", + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:3333/api" + } + ], + "paths": { + "/status": { + "get": { + "operationId": "status", + "summary": "Get the status of the API", + "description": "Get the status of the API", + "tags": [ + "Misc" + ], + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/reload-config": { + "put": { + "operationId": "reloadConfig", + "summary": "Reload the config", + "description": "Reload the config", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "reloadLocally": { + "type": "boolean" + } + }, + "required": [ + "reloadLocally" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/update-event/{slug}": { + "post": { + "operationId": "changeEvent", + "summary": "Update the event of a room", + "description": "Update the event of a room", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "event": { + "type": "string", + "enum": [ + null, + "EVEN_OR_ODD", + "EVEN_OR_ODD_DEFAULT_CANVAS", + "INITIAL_DEFAULT_CANVAS", + "RANDOM", + "GROUPS", + "VOID" + ], + "nullable": true, + "default": null + }, + "radius": { + "type": "number" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": [ + "message" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/update-rate-limits/{slug}": { + "post": { + "operationId": "updateRateLimits", + "summary": "Update the rate limits", + "description": "Update the rate limits for the API", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "rateLimitName": { + "type": "string", + "enum": [ + "testsLimiter", + "getCanvasLimiter", + "getPixelLimiter", + "placePixelLimiter", + "getRoomsLimiter", + "getRoomConfigLimiter", + "createRoomLimiter", + "updateRoomLimiter", + "deleteRoomLimiter", + "getStudentLimiter", + "updateStudentLimiter", + "sendMessageLimiter", + "reportRoomLimiter" + ] + }, + "limit": { + "type": "number", + "minimum": 1 + }, + "interval": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "rateLimitName", + "limit", + "interval" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/tests/error": { + "get": { + "operationId": "tests-error", + "summary": "Return a server error", + "description": "Always return 500 Internal Server Error", + "tags": [ + "Tests" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/tests/invalid-token": { + "post": { + "operationId": "tests-invalid-token", + "summary": "Return an invalid token error", + "description": "Always return 401 Unauthorized \"Invalid token\"", + "tags": [ + "Tests" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/tests/expired-token": { + "post": { + "operationId": "tests-expired-token", + "summary": "Return a token expired error", + "description": "Always return 401 Unauthorized \"Token expired\"", + "tags": [ + "Tests" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/tests/too-many-requests": { + "get": { + "operationId": "tests-too-many-requests", + "summary": "Return a too many requests error", + "description": "Always return 429 Too Many Requests", + "tags": [ + "Tests" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/students": { + "get": { + "operationId": "students-getStudents", + "summary": "Get all students", + "description": "Get all students", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uid": { + "type": "number" + }, + "login": { + "type": "string" + } + }, + "required": [ + "uid", + "login" + ], + "additionalProperties": false + }, + "description": "An array of students with their UID and login" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/students/{id}": { + "get": { + "operationId": "students-getStudent", + "summary": "Get a student by UID or login", + "description": "Get a student by UID or login", + "tags": [ + "Students (Mandatory)" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The UID or login of the student" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "groups": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ADMIN", + "YAKA", + "ING1_LYON", + "ING1_PARIS", + "ING1_RENNES", + "ING1_STRASBOURG", + "ING1_TOULOUSE" + ] + } + }, + "uid": { + "type": "number" + }, + "login": { + "type": "string" + }, + "avatarURL": { + "type": "string", + "nullable": true + }, + "quote": { + "type": "string", + "nullable": true + }, + "currentRoomSlug": { + "type": "string", + "nullable": true + }, + "banUntil": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "required": [ + "groups", + "uid", + "login", + "avatarURL", + "quote", + "currentRoomSlug", + "banUntil" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + }, + "put": { + "operationId": "students-updateStudent", + "summary": "Update a student by UID or login", + "description": "Update a student by UID or login", + "tags": [ + "Students (Optional)" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "avatarURL": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ], + "description": "The URL of your avatar" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ], + "description": "Your quote" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Your student UID or login" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "groups": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ADMIN", + "YAKA", + "ING1_LYON", + "ING1_PARIS", + "ING1_RENNES", + "ING1_STRASBOURG", + "ING1_TOULOUSE" + ] + } + }, + "uid": { + "type": "number" + }, + "login": { + "type": "string" + }, + "avatarURL": { + "type": "string", + "nullable": true + }, + "quote": { + "type": "string", + "nullable": true + }, + "currentRoomSlug": { + "type": "string", + "nullable": true + }, + "banUntil": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "required": [ + "groups", + "uid", + "login", + "avatarURL", + "quote", + "currentRoomSlug", + "banUntil" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/students/{id}/ban": { + "post": { + "operationId": "students-banStudent", + "summary": "Ban a student by UID or login", + "description": "Ban a student by UID or by login. If no date is provided, the student will be unbanned.", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "banUntil": { + "type": "string", + "description": "The date until the student is banned" + }, + "reason": { + "type": "string", + "description": "The reason of the ban" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The UID or login of the student" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "groups": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ADMIN", + "YAKA", + "ING1_LYON", + "ING1_PARIS", + "ING1_RENNES", + "ING1_STRASBOURG", + "ING1_TOULOUSE" + ] + } + }, + "uid": { + "type": "number" + }, + "login": { + "type": "string" + }, + "avatarURL": { + "type": "string", + "nullable": true + }, + "quote": { + "type": "string", + "nullable": true + }, + "currentRoomSlug": { + "type": "string", + "nullable": true + }, + "banUntil": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "required": [ + "groups", + "uid", + "login", + "avatarURL", + "quote", + "currentRoomSlug", + "banUntil" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms": { + "get": { + "operationId": "rooms-getRooms", + "summary": "Get all rooms", + "description": "List all the rooms available to the student", + "tags": [ + "Rooms (Optional)" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [], + "responses": { + "200": { + "description": "List of available rooms", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Room" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + }, + "post": { + "operationId": "rooms-createRoom", + "summary": "Create a room", + "description": "Create a new room", + "tags": [ + "Rooms (Optional)" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the room" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ], + "description": "The description of the room" + }, + "iconURL": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ], + "description": "The URL of the room's icon" + }, + "isPublic": { + "type": "boolean", + "description": "Whether the room is public or not. Defaults to false" + }, + "studentsWhitelist": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "The list of students allowed to join the room. Effective only if isPublic is false. Accepts both UIDs and logins. Defaults to an empty array" + }, + "studentsBlacklist": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "The list of students not allowed to join the room. Effective only if isPublic is true. Accepts both UIDs and logins. Defaults to an empty array" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "iconURL": { + "type": "string", + "nullable": true + }, + "canvasDimensions": { + "type": "number" + }, + "isPublic": { + "type": "boolean" + }, + "studentsWhitelist": { + "type": "array", + "items": { + "type": "number" + } + }, + "studentsBlacklist": { + "type": "array", + "items": { + "type": "number" + } + }, + "ownerUid": { + "type": "number" + }, + "password": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "boolean" + }, + "deleted": { + "type": "boolean" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "slug", + "name", + "description", + "iconURL", + "canvasDimensions", + "isPublic", + "studentsWhitelist", + "studentsBlacklist", + "ownerUid", + "password", + "hidden", + "deleted", + "createdAt" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/{slug}": { + "put": { + "operationId": "rooms-updateRoom", + "summary": "Update a room", + "description": "Update a room", + "tags": [ + "Rooms (Optional)" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the room" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ], + "description": "The description of the room" + }, + "iconURL": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ], + "description": "The URL of the room's icon" + }, + "isPublic": { + "type": "boolean", + "description": "Whether the room is public or not. Defaults to false" + }, + "studentsWhitelist": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "The list of students allowed to join the room. Effective only if isPublic is false. Accepts both UIDs and logins. Defaults to an empty array" + }, + "studentsBlacklist": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "The list of students not allowed to join the room. Effective only if isPublic is true. Accepts both UIDs and logins. Defaults to an empty array" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "iconURL": { + "type": "string", + "nullable": true + }, + "canvasDimensions": { + "type": "number" + }, + "isPublic": { + "type": "boolean" + }, + "studentsWhitelist": { + "type": "array", + "items": { + "type": "number" + } + }, + "studentsBlacklist": { + "type": "array", + "items": { + "type": "number" + } + }, + "ownerUid": { + "type": "number" + }, + "password": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "boolean" + }, + "deleted": { + "type": "boolean" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "slug", + "name", + "description", + "iconURL", + "canvasDimensions", + "isPublic", + "studentsWhitelist", + "studentsBlacklist", + "ownerUid", + "password", + "hidden", + "deleted", + "createdAt" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "rooms-deleteRoom", + "summary": "Delete a room", + "description": "Delete a room", + "tags": [ + "Rooms (Optional)" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/{slug}/config": { + "get": { + "operationId": "rooms-getRoomConfig", + "summary": "Get the room config", + "description": "Get the room config", + "tags": [ + "Rooms (Mandatory)" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "metadata": { + "type": "object", + "properties": { + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ] + }, + "iconURL": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ] + }, + "canvasDimensions": { + "type": "number" + }, + "isPublic": { + "type": "boolean" + }, + "studentsWhitelist": { + "type": "array", + "items": { + "type": "number" + } + }, + "studentsBlacklist": { + "type": "array", + "items": { + "type": "number" + } + }, + "ownerUid": { + "type": "number" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "slug", + "name", + "description", + "iconURL", + "canvasDimensions", + "isPublic", + "ownerUid", + "createdAt" + ], + "additionalProperties": false + }, + "settings": { + "type": "object", + "properties": { + "roomColors": { + "type": "string" + } + }, + "required": [ + "roomColors" + ], + "additionalProperties": false + }, + "rateLimits": { + "type": "object", + "properties": { + "testsLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getCanvasLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getPixelLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "placePixelLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getRoomsLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getRoomConfigLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "createRoomLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "updateRoomLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "deleteRoomLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getStudentLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "updateStudentLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "sendMessageLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "reportRoomLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + } + }, + "required": [ + "testsLimiter", + "getCanvasLimiter", + "getPixelLimiter", + "placePixelLimiter", + "getRoomsLimiter", + "getRoomConfigLimiter", + "createRoomLimiter", + "updateRoomLimiter", + "deleteRoomLimiter", + "getStudentLimiter", + "updateStudentLimiter", + "sendMessageLimiter", + "reportRoomLimiter" + ], + "additionalProperties": false + } + }, + "required": [ + "metadata", + "settings", + "rateLimits" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + }, + "post": { + "operationId": "rooms-changeRoomConfig", + "summary": "Load another json room config", + "description": "Load another json room config", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "settings": { + "type": "object", + "properties": { + "roomColors": { + "type": "string", + "description": "The colors of the room" + } + }, + "additionalProperties": false, + "description": "The settings to change" + }, + "events": { + "type": "object", + "properties": { + "colorationEvent": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of the coloration event" + }, + "groups": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The groups of the coloration event" + }, + "colorsSubSet": { + "type": "array", + "items": { + "type": "number" + }, + "description": "The colors subset of the coloration event" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "radiusEvent": { + "type": "object", + "properties": { + "radius": { + "type": "number", + "description": "The radius of the event" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "rateLimitsOverride": { + "type": "object", + "properties": { + "testsLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getCanvasLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getPixelLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "placePixelLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getRoomsLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getRoomConfigLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "createRoomLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "updateRoomLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "deleteRoomLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "getStudentLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "updateStudentLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "sendMessageLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + }, + "reportRoomLimiter": { + "type": "object", + "properties": { + "limit": { + "type": "number" + }, + "interval": { + "type": "number" + } + }, + "required": [ + "limit", + "interval" + ], + "additionalProperties": false + } + }, + "required": [ + "testsLimiter", + "getCanvasLimiter", + "getPixelLimiter", + "placePixelLimiter", + "getRoomsLimiter", + "getRoomConfigLimiter", + "createRoomLimiter", + "updateRoomLimiter", + "deleteRoomLimiter", + "getStudentLimiter", + "updateStudentLimiter", + "sendMessageLimiter", + "reportRoomLimiter" + ], + "additionalProperties": false, + "description": "The rate limits to override" + } + }, + "required": [ + "events" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/{slug}/report": { + "post": { + "operationId": "rooms-reportRoom", + "summary": "Report a room", + "description": "Report a room", + "tags": [ + "Misc" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "The reason for the report" + } + }, + "required": [ + "reason" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/yeet": { + "post": { + "operationId": "rooms-yeetFromRoom", + "summary": "Yeet a student from a room", + "description": "Yeet a student from a room", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slug": { + "type": "string", + "description": "The slug of the room. If empty, all rooms will be yeeted" + }, + "studentsList": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "The list of students to yeet. If empty, all students will be yeeted" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/{slug}/canvas": { + "get": { + "operationId": "rooms-canvas-getCanvas", + "summary": "Get the canvas of a room", + "description": "Get the canvas of a room", + "tags": [ + "Rooms (Mandatory)" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "pixels": { + "type": "string", + "description": "The pixels of the room" + } + }, + "required": [ + "pixels" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/{slug}/canvas/pixels": { + "get": { + "operationId": "rooms-canvas-getPixel", + "summary": "Get the pixels of a room", + "description": "Get the pixels of a room", + "tags": [ + "Rooms (Mandatory)" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + }, + { + "name": "posX", + "in": "query", + "required": true, + "schema": { + "type": "number" + }, + "description": "The X position of the pixel" + }, + { + "name": "posY", + "in": "query", + "required": true, + "schema": { + "type": "number" + }, + "description": "The Y position of the pixel" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "roomSlug": { + "type": "string" + }, + "posX": { + "type": "number" + }, + "posY": { + "type": "number" + }, + "color": { + "type": "number" + }, + "timestamp": { + "anyOf": [ + { + "type": "number" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ] + }, + "placedByUid": { + "anyOf": [ + { + "type": "number" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ] + } + }, + "required": [ + "roomSlug", + "posX", + "posY", + "color", + "timestamp", + "placedByUid" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + }, + "post": { + "operationId": "rooms-canvas-placePixel", + "summary": "Place a pixel in a room", + "description": "Place a pixel in a room", + "tags": [ + "Rooms (Mandatory)" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "posX": { + "type": "number", + "description": "The X position of the pixel" + }, + "posY": { + "type": "number", + "description": "The Y position of the pixel" + }, + "color": { + "type": "number", + "description": "The color index of the pixel" + } + }, + "required": [ + "posX", + "posY", + "color" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "roomSlug": { + "type": "string" + }, + "posX": { + "type": "number" + }, + "posY": { + "type": "number" + }, + "color": { + "type": "number" + }, + "timestamp": { + "anyOf": [ + { + "type": "number" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ] + }, + "placedByUid": { + "anyOf": [ + { + "type": "number" + }, + { + "enum": [ + "null" + ], + "nullable": true + } + ] + } + }, + "required": [ + "roomSlug", + "posX", + "posY", + "color", + "timestamp", + "placedByUid" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/{slug}/canvas/resize": { + "put": { + "operationId": "rooms-canvas-resizeCanvas", + "summary": "Resize the canvas of a room", + "description": "Resize the canvas of a room", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "newCanvasDimensions": { + "type": "number", + "description": "The new size of the room" + } + }, + "required": [ + "newCanvasDimensions" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "iconURL": { + "type": "string", + "nullable": true + }, + "canvasDimensions": { + "type": "number" + }, + "isPublic": { + "type": "boolean" + }, + "studentsWhitelist": { + "type": "array", + "items": { + "type": "number" + } + }, + "studentsBlacklist": { + "type": "array", + "items": { + "type": "number" + } + }, + "ownerUid": { + "type": "number" + }, + "password": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "boolean" + }, + "deleted": { + "type": "boolean" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "slug", + "name", + "description", + "iconURL", + "canvasDimensions", + "isPublic", + "studentsWhitelist", + "studentsBlacklist", + "ownerUid", + "password", + "hidden", + "deleted", + "createdAt" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/{slug}/canvas/reset": { + "put": { + "operationId": "rooms-canvas-resetCanvas", + "summary": "Reset the canvas of a room", + "description": "Reset the canvas of a room", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "resetOnDefault": { + "type": "boolean", + "description": "Reset the canvas on the default image if exists" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "iconURL": { + "type": "string", + "nullable": true + }, + "canvasDimensions": { + "type": "number" + }, + "isPublic": { + "type": "boolean" + }, + "studentsWhitelist": { + "type": "array", + "items": { + "type": "number" + } + }, + "studentsBlacklist": { + "type": "array", + "items": { + "type": "number" + } + }, + "ownerUid": { + "type": "number" + }, + "password": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "boolean" + }, + "deleted": { + "type": "boolean" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "slug", + "name", + "description", + "iconURL", + "canvasDimensions", + "isPublic", + "studentsWhitelist", + "studentsBlacklist", + "ownerUid", + "password", + "hidden", + "deleted", + "createdAt" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + }, + "/rooms/{slug}/canvas/load": { + "post": { + "operationId": "rooms-canvas-loadCanvas", + "summary": "Load the canvas of a room", + "description": "Load the canvas of a room", + "tags": [ + "Admin" + ], + "security": [ + { + "Authorization": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "backupId": { + "type": "number", + "description": "The id of the backup" + } + }, + "required": [ + "backupId" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The slug of the room" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidToken": { + "value": { + "code": "UNAUTHORIZED", + "message": "Invalid token" + } + }, + "TokenExpired": { + "value": { + "code": "UNAUTHORIZED", + "message": "Token expired" + } + }, + "Unauthenticated": { + "value": { + "code": "UNAUTHORIZED", + "message": "Unauthenticated" + } + }, + "Banned": { + "value": { + "code": "UNAUTHORIZED", + "message": "You are banned" + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotAdmin": { + "value": { + "code": "FORBIDDEN", + "message": "You are not an admin" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TooManyRequests": { + "value": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InternalServerError": { + "value": { + "code": "INTERNAL_SERVER_ERROR", + "message": "An error occured" + } + } + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "Authorization": { + "type": "http", + "scheme": "bearer" + } + }, + "responses": { + "error": { + "description": "Error response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "string" + }, + "issues": { + "type": "array", + "items": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": [ + "message" + ], + "additionalProperties": false + } + } + }, + "required": [ + "message", + "code" + ], + "additionalProperties": false + } + } + } + } + }, + "schemas": { + "Room": { + "type": "object", + "properties": { + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "iconURL": { + "type": "string", + "nullable": true + }, + "canvasDimensions": { + "type": "number" + }, + "isPublic": { + "type": "boolean" + }, + "studentsWhitelist": { + "type": "array", + "items": { + "type": "number" + } + }, + "studentsBlacklist": { + "type": "array", + "items": { + "type": "number" + } + }, + "ownerUid": { + "type": "number" + }, + "password": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "boolean" + }, + "deleted": { + "type": "boolean" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + } + }, + "Student": { + "type": "object", + "properties": { + "groups": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ADMIN", + "YAKA", + "ING1_LYON", + "ING1_PARIS", + "ING1_RENNES", + "ING1_STRASBOURG", + "ING1_TOULOUSE" + ] + } + }, + "uid": { + "type": "number" + }, + "login": { + "type": "string" + }, + "avatarURL": { + "type": "string", + "nullable": true + }, + "quote": { + "type": "string", + "nullable": true + }, + "currentRoomSlug": { + "type": "string", + "nullable": true + }, + "banUntil": { + "type": "string", + "format": "date-time", + "nullable": true + } + } + }, + "Error": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + }, + "tags": [ + { + "name": "Misc" + }, + { + "name": "Tests" + }, + { + "name": "Rooms (Mandatory)" + }, + { + "name": "Rooms (Optional)" + }, + { + "name": "Students (Mandatory)" + }, + { + "name": "Students (Optional)" + }, + { + "name": "Admin" + } + ] +}
\ No newline at end of file diff --git a/rushs/eplace/src/components/debug.html b/rushs/eplace/src/components/debug.html new file mode 100644 index 0000000..750906d --- /dev/null +++ b/rushs/eplace/src/components/debug.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="stylesheet" type="text/css" media="screen" href="index.css" /> +</head> + +<body> + <div class="container"> + <h1>Local storage</h1> + + <h3>Token</h3> + <p id="token" class="token-text"> + {{ token }} + </p> + <h3>Refresh Token</h3> + <p id="refresh_token" class="token-text"> + {{ refresh_token }} + </p> + + <button id="errorBtn">Generate an error response</button> + <button id="expiredTokenBtn">Generate an expired token response</button> + <button id="deleteTokenBtn">Delete token</button> + <button id="deleteRefreshTokenBtn">Delete refresh token</button> + </div> +</body> + +</html> diff --git a/rushs/eplace/src/components/notifications/index.html b/rushs/eplace/src/components/notifications/index.html new file mode 100644 index 0000000..c211a39 --- /dev/null +++ b/rushs/eplace/src/components/notifications/index.html @@ -0,0 +1,12 @@ +<div class="Alert"> + <div class="Icon"> + <i class="fa {{icon_classes}}"></i> + </div> + <div class="AlertBody"> + <span class="AlertTitle">{{title}}</span> + <span class="AlertContent">{{content}}</span> + </div> + <span class="AlertClose"> + <i class="fa fa-times-circle"></i> + </span> +</div> diff --git a/rushs/eplace/src/components/rooms/index.html b/rushs/eplace/src/components/rooms/index.html new file mode 100644 index 0000000..3d9f20e --- /dev/null +++ b/rushs/eplace/src/components/rooms/index.html @@ -0,0 +1,10 @@ +<button class="Room"> + <img src="{{icon_url}}" class="Avatar" /> + <div class="TextContainer"> + <div class="Name"> + <i class="RoomPrivacy {{privacy_icon}}"></i> + <span>{{name}}</span> + </div> + <span class="RoomOwner">owner: {{owner_login}}</span> + </div> +</button> diff --git a/rushs/eplace/src/components/rooms/message.html b/rushs/eplace/src/components/rooms/message.html new file mode 100644 index 0000000..1c35e20 --- /dev/null +++ b/rushs/eplace/src/components/rooms/message.html @@ -0,0 +1,8 @@ +<div class="ChatMessage"> + <div class="MessageHeader"> + <img src="{{avatar_url}}" class="Avatar" /> + <span class="Login">{{message_author}}</span> + <span class="Time">{{sent_at}}</span> + </div> + <span class="MessageContent">{{message_content}}</span> +</div> diff --git a/rushs/eplace/src/components/rooms/upsert.html b/rushs/eplace/src/components/rooms/upsert.html new file mode 100644 index 0000000..8b02b69 --- /dev/null +++ b/rushs/eplace/src/components/rooms/upsert.html @@ -0,0 +1,70 @@ +<div class="FormOverlay"> + <form class="StylisedForm" id="room-upsert-form"> + <div class="FormHeader"> + <h2 class="FormTitle">{{form_title}}</h2> + </div> + <div class="FormItem"> + <label for="name" class="FormLabel">Name</label> + <input + type="text" + class="FormInput" + id="name" + name="name" + placeholder="Enter name" + /> + </div> + <div class="FormItem"> + <label for="description" class="FormLabel">Description</label> + <input + type="text" + class="FormInput" + id="description" + name="description" + placeholder="Enter description" + /> + </div> + <div class="FormItem"> + <label for="icon-url" class="FormLabel">Icon URL</label> + <input + type="" + class="FormInput" + id="icon-url" + name="icon-url" + placeholder="Enter icon URL" + /> + </div> + <div class="FormItem"> + <label for="whitelist" class="FormLabel">Students Whitelist</label> + <input + type="text" + class="FormInput" + id="whitelist" + name="whitelist" + placeholder="Enter student's logins or UIDs, separated by commas (private rooms only)" + /> + </div> + <div class="FormItem"> + <label for="blacklist" class="FormLabel">Students Blacklist</label> + <input + type="text" + class="FormInput" + id="blacklist" + name="blacklist" + placeholder="Enter student's logins or UIDs, separated by commas (public rooms only)" + /> + </div> + <div class="FormItem"> + <label for="is-public" class="FormLabel">Is Public</label> + <input + type="checkbox" + class="FormInput" + id="is-public" + name="is-public" + /> + </div> + <div class="FormButtons"> + <button type="button" id="close-modal">Cancel</button> + <button type="submit">Submit</button> + </div> + </form> +</div> diff --git a/rushs/eplace/src/components/rooms/user-event.html b/rushs/eplace/src/components/rooms/user-event.html new file mode 100644 index 0000000..3aec718 --- /dev/null +++ b/rushs/eplace/src/components/rooms/user-event.html @@ -0,0 +1,3 @@ +<div class="ChatUserEvent"> + <span class="MessageContent">{{message_content}}</span> +</div> diff --git a/rushs/eplace/src/components/students/update.html b/rushs/eplace/src/components/students/update.html new file mode 100644 index 0000000..912526e --- /dev/null +++ b/rushs/eplace/src/components/students/update.html @@ -0,0 +1,31 @@ +<div class="FormOverlay"> + <form class="StylisedForm" id="student-update-form"> + <div class="FormHeader"> + <h2 class="FormTitle">Update Profile</h2> + </div> + <div class="FormItem"> + <label for="avatar-url" class="FormLabel">Avatar URL</label> + <input + type="" + class="FormInput" + id="avatar-url" + name="avatar-url" + placeholder="Enter avatar URL" + /> + </div> + <div class="FormItem"> + <label for="quote" class="FormLabel">Quote</label> + <input + type="text" + class="FormInput" + id="quote" + name="quote" + placeholder="Enter a quote" + /> + </div> + <div class="FormButtons"> + <button type="button" id="close-modal">Cancel</button> + <button type="submit">Submit</button> + </div> + </form> +</div> diff --git a/rushs/eplace/src/pages/complete/epita/index.html b/rushs/eplace/src/pages/complete/epita/index.html new file mode 100644 index 0000000..a6ebe75 --- /dev/null +++ b/rushs/eplace/src/pages/complete/epita/index.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <title>E/PLACE</title> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="icon" href="/favicon.ico" /> + <script type="module" src="index.js"></script> + </head> + <body></body> +</html> diff --git a/rushs/eplace/src/pages/complete/epita/index.js b/rushs/eplace/src/pages/complete/epita/index.js new file mode 100644 index 0000000..ced46cf --- /dev/null +++ b/rushs/eplace/src/pages/complete/epita/index.js @@ -0,0 +1,53 @@ +// FIXME: This file should handle the auth redirection + +// Get the code from the URL parameters and redirect to the relevant page +const params = new URLSearchParams(window.location.search); + +const code = params.get("code"); +const form = new FormData(); + +form.append("client_id", import.meta.env.VITE_CLIENT_ID); +form.append("redirect_uri", `${import.meta.env.VITE_URL}/complete/epita/`); +form.append("grant_type", "authorization_code"); +form.append("code", code); +const config = { + method: "POST", + body: form, +}; + +export async function getToken() { + try { + const res = await fetch( + `${import.meta.env.VITE_URL}/auth-api/token`, + config, + ); + const response = await res.json(); + + const token = response.id_token; + + localStorage.setItem("token", token); + localStorage.setItem("refresh_token", response.refresh_token); + window.location.replace(import.meta.env.VITE_URL); + return true; + } catch (error) { + console.log(error); + return false; + } +} + +if (!code) { + const authQueryParams = { + client_id: import.meta.env.VITE_CLIENT_ID, + scope: "epita profile picture", + redirect_uri: `${import.meta.env.VITE_URL}/complete/epita/`, + response_type: "code", + }; + const url = new URL( + `?client_id=${authQueryParams.client_id}&scope=${authQueryParams.scope}&redirect_uri=${authQueryParams.redirect_uri}&response_type=${authQueryParams.response_type}`, + `${import.meta.env.VITE_AUTH_URL}/authorize`, + ); + + window.location.replace(url); +} else { + getToken(); +} diff --git a/rushs/eplace/src/pages/debug.js b/rushs/eplace/src/pages/debug.js new file mode 100644 index 0000000..e2da5f4 --- /dev/null +++ b/rushs/eplace/src/pages/debug.js @@ -0,0 +1,34 @@ +import $ from "jquery"; +import debugHtml from "../components/debug.html"; + +function refreshLocalStorage() { + $("#token").text(localStorage.getItem("token") ?? "N/A"); + $("#refresh_token").text(localStorage.getItem("refresh_token") ?? "N/A"); +} + +if (import.meta.env.MODE === "debug") { + $.get(debugHtml, function (response) { + $("body").html(response); + refreshLocalStorage(); + }).fail(function (xhr, status, error) { + console.error("Error fetching debug HTML:", error); + }); + + $(document).on("click", "#errorBtn", function () { + // Make a call to VITE_URL/tests/error using your own api call function + }); + + $(document).on("click", "#expiredTokenBtn", function () { + // Make a call to VITE_URL/tests/expired using your own api call function + }); + + $(document).on("click", "#deleteTokenBtn", function () { + localStorage.removeItem("token"); + refreshLocalStorage(); + }); + + $(document).on("click", "#deleteRefreshTokenBtn", function () { + localStorage.removeItem("refresh_token"); + refreshLocalStorage(); + }); +} diff --git a/rushs/eplace/src/pages/index.css b/rushs/eplace/src/pages/index.css new file mode 100644 index 0000000..6548524 --- /dev/null +++ b/rushs/eplace/src/pages/index.css @@ -0,0 +1,78 @@ +@import url(http://fonts.googleapis.com/css?family=Barlow:800); +@import url(http://fonts.googleapis.com/css?family=Montserrat:400,700); + +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif, Barlow; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + justify-content: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; + margin: 0; +} + +h2 { + margin: 0; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} +input { + border: none; +} +.token-text { + max-width: 10ch; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} diff --git a/rushs/eplace/src/pages/index.html b/rushs/eplace/src/pages/index.html new file mode 100644 index 0000000..d52232b --- /dev/null +++ b/rushs/eplace/src/pages/index.html @@ -0,0 +1,173 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <title>E/PLACE</title> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" type="text/css" media="screen" href="index.css" /> + <link rel="stylesheet/less" type="text/css" href="styles.less" /> + <link + href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" + rel="stylesheet" + /> + <script src="https://cdn.jsdelivr.net/npm/less"></script> + <script type="module" src="index.js"></script> + </head> + <body> + <div class="App"> + <div class="AlertContainer" id="alert-container"></div> + <div class="Container" id="container"> + <div class="RoomList Hidden" id="left-container"> + <div class="Header"> + <h1 class="Title">E/PLACE</h1> + <button class="CloseButton" id="close-left"> + <i class="fa-solid fa-backward"></i> + </button> + </div> + <div class="ListContainer"> + <div class="ListSearchBar"> + <div class="InputContainer"> + <input + aria-placeholder="Search a room..." + placeholder="Search a room..." + class="Input" + id="search-input" + /> + <div class="Divider"></div> + <button class="RoomButton" id="create-room"> + <i class="fa-solid fa-square-plus"></i> + </button> + <button class="RoomButton" id="refresh-rooms"> + <i class="fa-solid fa-rotate"></i> + </button> + </div> + <div class="FilterContainer"> + <span class="FilterText">Filters:</span> + <div class="FilterHeader"> + <button class="Filter" id="filter-name"> + <span>Name</span> + <i class="fa-solid fa-sort-down"></i> + </button> + <button class="Filter" id="filter-owner"> + <span>Owned by you</span> + <i class="fa-solid fa-plus"></i> + </button> + <button class="Filter" id="filter-public"> + <span>Public</span> + <i class="fa-solid fa-minus"></i> + </button> + <button class="Filter" id="filter-private"> + <span>Private</span> + <i class="fa-solid fa-minus"></i> + </button> + </div> + </div> + </div> + <div class="RoomsContainer" id="rooms-container"></div> + </div> + <div class="StudentProfile"> + <img src="" class="Avatar" id="profile-info-avatar" /> + <div class="TextContainer"> + <span class="Login" id="profile-info-login"></span> + <span class="Quote" id="profile-info-quote"></span> + </div> + <button class="ModifyProfileButton" id="profile-update"> + <i class="fa-solid fa-pencil"></i> + </button> + </div> + </div> + <div class="RoomCanvas"> + <div class="Header"> + <div class="TextContainer"> + <h2 class="Title" id="room-name">{{room_name}}</h2> + <span class="Description" id="room-description" + >{{room_description}}</span + > + </div> + <div class="HeaderDivider"></div> + <div class="ButtonContainer"> + <button class="RoomButton" id="edit-room"> + <i class="fa-solid fa-pencil"></i> + </button> + <button class="RoomButton" id="delete-room"> + <i class="fa-solid fa-trash-can"></i> + </button> + <button class="ReportButton">Report Abuse</button> + </div> + </div> + <div class="CanvasContainer" id="canvas-container"> + <canvas class="Canvas" id="canvas"></canvas> + <img class="Selector" id="selector" src="/selector.svg" /> + <div class="Tooltip" id="tooltip"> + <div class="Header"> + <div class="PlacedByInfo"> + <img + src="{{student_avatar}}" + class="Avatar" + id="tooltip-info-avatar" + /> + <div class="Profile"> + <span class="Login" id="tooltip-info-login" + >{{student_login}}</span + > + <span class="Quote" id="tooltip-info-quote" + >{{student_quote}}</span + > + </div> + </div> + <div class="TextContainer"> + <span id="tooltip-date">{{date_placed}}</span> + <span id="tooltip-time">{{time_placed}}</span> + </div> + </div> + <div class="ButtonContainer"> + <button class="ColorPicker" id="color-picker"> + <i class="fas fa-eye-dropper"></i> + </button> + <button class="PlaceButton" id="color-place-button"> + PLACE + </button> + </div> + </div> + </div> + <div class="PositionTooltip" id="position-tooltip"> + <span>X=0</span> + <span>Y=0</span> + </div> + <div class="ColorWheelContainer" id="color-wheel-container"> + <div class="ColorWheel" id="color-wheel"></div> + </div> + </div> + <div class="RoomChat" id="right-container"> + <div class="ChatContainer"> + <div class="Header"> + <button class="CloseButton" id="close-right"> + <i class="fa-solid fa-forward"></i> + </button> + </div> + <div class="ChatMessageContainer" id="chat-message-container"></div> + <form + class="InputContainer" + id="chat-input-form" + autocomplete="off" + > + <input + aria-placeholder="Type your message here..." + placeholder="Type your message here..." + class="Input" + id="message-content" + name="message-content" + autocomplete="off" + /> + <div class="ChatTimeout"> + <i class="fa-solid fa-stopwatch"></i> + </div> + </form> + </div> + </div> + </div> + </div> + </body> +</html> diff --git a/rushs/eplace/src/pages/index.js b/rushs/eplace/src/pages/index.js new file mode 100644 index 0000000..59cdb91 --- /dev/null +++ b/rushs/eplace/src/pages/index.js @@ -0,0 +1,10 @@ +// FIXME: This is the entry point of the application, write your code here + +import { calculateLayout } from "./utils"; +import "./debug"; +import { initSocket } from "../utils/streams"; + +// Initialize the layout +calculateLayout(); + +initSocket(); diff --git a/rushs/eplace/src/pages/styles.less b/rushs/eplace/src/pages/styles.less new file mode 100644 index 0000000..dd8ae95 --- /dev/null +++ b/rushs/eplace/src/pages/styles.less @@ -0,0 +1,905 @@ +@base: rgba(16, 18, 60, 0.95); +@dark: #05061a; +@light: #f0f0f0; +@accent: #ff4603; + +.App { + background-color: @dark; + min-height: 100vh; + margin: 0 auto; + overflow: hidden; + padding: 0rem; + position: relative; + text-align: center; + width: 100vw; +} + +.AlertContainer { + position: absolute; + top: 0; + right: 0; + display: flex; + flex-direction: column-reverse; + align-items: flex-end; + justify-content: flex-end; + gap: 1rem; + padding: 2rem; + z-index: 3; + pointer-events: none; + + .Alert { + position: relative; + background-color: #fff; + display: flex; + align-items: center; + gap: 1rem; + padding: 0.5rem; + width: 100%; + pointer-events: all; + + box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; + + .Icon { + font-size: 28px; + } + + .AlertBody { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + margin: 0.5rem 2rem 0.5rem 0; + text-align: left; + font-family: Barlow; + color: @dark; + + .AlertTitle { + font-size: 1rem; + font-weight: 800; + text-transform: uppercase; + } + .AlertContent { + font-size: 0.75rem; + opacity: 50%; + } + } + + .AlertClose { + position: absolute; + top: 0.5rem; + right: 0.5rem; + font-size: 1em; + color: @dark; + } + } + + .AlertSuccess { + border-left: 5px solid #49d761; + + .Icon { + color: #49d761; + } + } + .AlertWarning { + border-left: 5px solid #ff9f1c; + + .Icon { + color: #ff9f1c; + } + } + .AlertError { + border-left: 5px solid #fd2020; + + .Icon { + color: #fd2020; + } + } +} + +.Container { + column-gap: 2em; + display: grid; + flex-direction: row; + grid-auto-flow: row dense; + // Fully openned sidebars layout + // -> grid-template-columns: 1fr 2.5fr 1fr; + // Closed sidebars layout + grid-template-columns: 0fr 2.5fr 0fr; + height: calc(100vh - 4rem); + overflow: hidden; + padding: 2rem; + + transition: all 0.5s ease-in-out; +} + +.RoomList { + background-color: @base; + border-radius: 0.5rem; + display: grid; + flex-grow: 0; + gap: 0.5em 0em; + grid-template-rows: 1fr 8.25fr 0.75fr; + overflow: hidden; + padding: 1.5rem; + z-index: 1; + // Fully openned sidebar + // -> opacity: 1; + // Closed sidebar + opacity: 0; + + transition: opacity 0.5s ease-in-out; + + .Header { + display: flex; + align-items: center; + justify-content: space-between; + overflow: hidden; + + .Title { + color: @light; + font-family: Barlow; + font-size: 3rem; + font-weight: 800; + grid-row-start: 1; + overflow: hidden; + text-align: start; + text-overflow: ellipsis; + text-transform: uppercase; + white-space: nowrap; + } + } + + .ListContainer { + display: flex; + flex-direction: column; + gap: 1em; + margin: 1rem 0rem; + overflow: auto; + padding: 0rem; + } + + .ListSearchBar { + display: flex; + flex-direction: column; + gap: 0.5em 0em; + + .FilterContainer { + background-color: rgba(black, 0.5); + align-items: center; + display: flex; + font-family: Barlow; + font-weight: 800; + font-size: 0.75rem; + gap: 0em 1em; + overflow: hidden; + text-align: start; + white-space: nowrap; + padding: 0.5rem; + border-radius: 0.5rem; + + .FilterText { + margin-left: 0.5rem; + opacity: 0.5; + font-size: 0.8rem; + } + + .FilterHeader { + display: flex; + font-family: Barlow; + font-weight: 800; + overflow: scroll; + scrollbar-width: none; + text-align: start; + gap: 0.5em; + + -ms-overflow-style: none; + scrollbar-width: none; + &::-webkit-scrollbar { + display: none; + } + + .Filter { + background-color: rgba(@light, 0.25); + border-radius: 0.5rem; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5em; + padding: 0.25rem 0.5rem; + font-size: 0.65rem; + } + } + } + } + + .RoomsContainer { + display: flex; + flex-direction: column; + gap: 0.5rem; + grid-row-start: 2; + overflow: scroll; + + .Room { + background-color: rgba(black, 0.25); + border-radius: 0.5rem; + display: flex; + gap: 1em; + align-items: center; + padding: 0.5rem; + + &:disabled { + border: @accent 0.15rem solid; + cursor: not-allowed; + } + + .Avatar { + height: 4rem; + width: 4rem; + object-fit: cover; + aspect-ratio: 1/1; + } + + .TextContainer { + display: flex; + flex-direction: column; + justify-content: center; + gap: 0.5em; + color: @light; + overflow: hidden; + + .Name { + font-family: Barlow; + font-size: 1rem; + font-weight: 800; + text-align: start; + text-transform: uppercase; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + .RoomPrivacy { + margin-right: 0.25rem; + } + } + + .RoomOwner { + font-family: Montserrat; + font-size: 0.65rem; + font-weight: 700; + text-align: start; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + } + + .ListRoomDivider { + background-color: rgba(@light, 0.25); + height: 0.1rem; + margin: 0.5rem 0rem; + } + } + + .StudentProfile { + align-items: center; + background-color: @light; + border-radius: 5rem; + column-gap: 0.5em; + display: flex; + flex-direction: row; + grid-row-start: 3; + overflow: hidden; + padding: 0.5rem; + + .Avatar { + border-radius: 100%; + max-height: 3rem; + max-width: 3rem; + object-fit: cover; + aspect-ratio: 1/1; + } + + .TextContainer { + display: flex; + flex-direction: column; + justify-content: center; + margin-right: 0.5rem; + overflow: hidden; + color: black; + text-align: start; + overflow: hidden; + + .Login { + font-family: Barlow; + font-size: 1rem; + font-weight: 800; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .Quote { + font-family: Montserrat; + font-size: 0.7rem; + font-weight: 700; + opacity: 65%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .ModifyProfileButton { + background-color: transparent; + color: @dark; + padding: 0.25rem; + margin-left: auto; + margin-right: 0.5rem; + border-radius: 100%; + } + } +} + +.RoomCanvas { + display: grid; + flex-direction: column; + flex-grow: 0; + grid-template-rows: 0.25fr 9.75fr; + min-width: 50vw; + row-gap: 0em; + overflow: hidden; + + .Header { + background-color: @base; + border-radius: 0.5rem; + align-items: center; + justify-content: center; + display: flex; + flex-direction: row; + gap: 1.5rem; + grid-row-start: 1; + padding: 0.5rem; + z-index: 1; + + .TextContainer { + display: flex; + flex-direction: column; + justify-content: center; + text-align: end; + + .Title { + color: @light; + font-family: Barlow; + font-size: 2rem; + font-weight: 800; + overflow: hidden; + text-overflow: ellipsis; + text-transform: uppercase; + white-space: nowrap; + } + + .Description { + // Start with the description hidden. + // It needs to be visible if the room has a description. + display: none; + position: relative; + top: -0.25rem; + + color: @light; + font-family: Montserrat; + font-size: 0.5rem; + font-weight: 700; + opacity: 0.5; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .HeaderDivider { + background-color: rgba(@light, 0.25); + height: 100%; + margin: 0.5rem 0rem; + width: 0.1rem; + } + + .ButtonContainer { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + + .ReportButton { + background-color: @accent; + border-radius: 0.5rem; + border: 0px solid transparent; + color: @light; + display: block; + font-family: Montserrat; + font-size: 0.75rem; + font-weight: 700; + height: auto; + padding: 0.35rem 0.75rem; + text-transform: uppercase; + } + } + } + + .CanvasContainer { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + grid-row-start: 2; + overflow: hidden; + z-index: 0; + + .Canvas { + transform: translate(0, 0) scale(2.5); + } + + .Selector { + position: absolute; + inset: 0; + width: 1px; + height: 1px; + margin: auto; + pointer-events: none; + } + + .Tooltip { + // The tooltip is a flexbox + // -> display: flex; + // Start with the tooltip hidden + display: none; + + position: absolute; + top: 50%; + left: 50%; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.5rem; + transform: translate(-50%, -150%); + background-color: @base; + border-radius: 0.5rem; + border: @accent 0.15rem solid; + padding: 0.5rem; + + .Header { + display: flex; + gap: 0.75rem; + + .PlacedByInfo { + position: relative; + display: inline-block; + height: 3rem; + width: 3rem; + + .Avatar { + border-radius: 100%; + width: 100%; + height: 100%; + object-fit: cover; + aspect-ratio: 1/1; + } + + .Profile { + visibility: hidden; + background-color: @dark; + color: @light; + text-align: center; + padding: 0.5rem; + border-radius: 0.5rem; + + bottom: 100%; + left: 50%; + transform: translate(-50%, 0); + position: absolute; + z-index: 1; + + &::after { + content: " "; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: @dark transparent transparent transparent; + } + + .Login { + font-family: Barlow; + font-size: 0.8rem; + font-weight: 800; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .Quote { + font-family: Montserrat; + font-size: 0.7rem; + font-weight: 700; + opacity: 0.5; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + &:hover .Profile { + visibility: visible; + } + } + + .TextContainer { + display: flex; + flex-direction: column; + justify-content: center; + font-family: Montserrat; + font-size: 0.75rem; + font-weight: 700; + text-align: left; + } + } + + .ButtonContainer { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.5rem; + width: 100%; + font-family: Montserrat; + font-size: 0.75rem; + font-weight: 700; + + .ColorPicker { + padding: 0.2rem; + outline: none; + color: white; + border: white 0.1rem solid; + } + + .PlaceButton { + padding: 0.2rem; + border: @accent 0.1rem solid; + border-radius: 0.5rem; + outline: none; + font-family: Barlow; + font-size: 0.75rem; + font-weight: 800; + + &:active { + background-color: @accent; + color: @light; + } + + &:disabled { + background-color: @dark; + color: @accent; + } + } + } + } + } + + .PositionTooltip { + background-color: rgba(@dark, 0.25); + padding: 0.5rem; + margin: 0.5rem auto auto 0; + border-radius: 0.5rem; + font-family: Montserrat; + font-weight: 700; + z-index: 2; + } + + .ColorWheelContainer { + // The color wheel is a flexbox + // -> display: block; + // Start with the color wheel hidden + display: none; + + background-color: @base; + margin: auto 0 0 auto; + padding: 0.5rem; + max-height: calc(100% - 12rem); + overflow: scroll; + border-radius: 1rem; + border: @accent 0.15rem solid; + z-index: 1; + + min-block-size: -webkit-fill-available; + + -ms-overflow-style: none; + scrollbar-width: none; + &::-webkit-scrollbar { + display: none; + } + + transition: all 0.5s ease-in-out; + + .ColorWheel { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.5rem; + width: 100%; + margin: 0.25rem 0; + } + } +} + +.RoomChat { + display: grid; + flex-grow: 0; + grid-auto-flow: row; + grid-template-rows: 1fr 8fr; + overflow: hidden; + padding: 0rem; + z-index: 1; + // Fully openned sidebar + // -> opacity: 1; + // Closed sidebar + opacity: 0; + + transition: opacity 0.5s ease-in-out; + + .ChatContainer { + background-color: @base; + border-radius: 0.5rem; + display: grid; + gap: 1em; + grid-row-start: 2; + grid-template-rows: 0.5fr 6.75fr 0.75fr; + grid-template-columns: 1fr; + overflow: hidden; + padding: 0.8rem; + + .Header { + display: flex; + flex-direction: row-reverse; + align-items: center; + } + + .ChatMessageContainer { + display: flex; + flex-direction: column-reverse; + overflow: auto; + padding: 0rem; + row-gap: 1em; + + .ChatMessage { + color: @light; + background-color: rgba(black, 0.25); + border-radius: 0.5rem; + display: flex; + flex-direction: column; + padding: 0.5rem; + + .MessageHeader { + column-gap: 0.5em; + display: flex; + padding: 0.5rem; + overflow: hidden; + + .Avatar { + border-radius: 100%; + max-height: 2rem; + max-width: 2rem; + object-fit: cover; + aspect-ratio: 1/1; + } + + .Login { + font-family: Barlow; + font-weight: 800; + text-align: left; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .Time { + font-family: Barlow; + margin-left: auto; + text-align: end; + } + } + } + + .ChatUserEvent { + background-color: rgba(black, 0.25); + border-radius: 0.5rem; + display: flex; + flex-direction: column; + padding: 0.25rem; + opacity: 0.5; + } + + .ChatMessageMentionned { + background-color: rgba(@accent, 0.25); + } + + .MessageContent { + font-family: Montserrat; + font-size: 0.75rem; + font-weight: 400; + overflow-wrap: break-word; + padding: 0.5rem; + text-align: start; + } + } + } +} + +.Hidden { + width: 0; + height: 0; + margin: 0; + padding: 0; +} + +.CloseButton { + background-color: @accent; + border-radius: 0.5rem; + border: 0px solid transparent; + color: @light; + display: block; + font-family: Montserrat; + font-size: 0.75rem; + font-weight: 700; + max-height: 2rem; + padding: 0.5rem 0.75rem; + text-transform: uppercase; +} + +.InputContainer { + background-color: rgba(black, 0.5); + border-radius: 0.5rem; + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + overflow: hidden; + + .Divider { + background-color: @light; + height: 2rem; + width: 0.1rem; + opacity: 0.75; + } +} + +.RoomButton { + background-color: rgba(@light, 0.25); + padding: 0.35rem 0.5rem; + font-size: 0.75rem; +} + +.ChatTimeout { + --fill-percent: 0; + + border-radius: 50%; + padding: 0.25rem 0.5rem; + + background: radial-gradient( + closest-side, + @dark 80%, + transparent 0 99.9%, + @dark 0 + ), + conic-gradient(@accent calc(var(--fill-percent) * 1%), @dark 0); +} + +.Input { + background-color: rgba(black, 0); + color: @light; + flex-grow: 1; + font-family: Montserrat; + font-size: 0.75rem; + font-weight: 700; + opacity: 1; + padding: 0.5rem; + overflow: hidden; + text-overflow: ellipsis; +} + +.FormOverlay { + position: absolute; + inset: 0; + background-color: rgba(@dark, 0.95); + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + + .StylisedForm { + background-color: @base; + padding: 2rem 1rem; + border: 0.25rem solid @accent; + border-radius: 0.5rem; + display: flex; + flex-direction: column; + gap: 1rem; + align-items: center; + justify-content: center; + font-family: Barlow; + min-width: 65vw; + max-width: 90vw; + color: @light; + + .FormHeader { + display: flex; + margin-bottom: 2rem; + + .FormTitle { + font-size: 1.5rem; + font-weight: 800; + text-align: center; + } + } + + .FormItem { + display: grid; + grid-template-columns: 1fr 6fr; + width: 100%; + gap: 1rem; + align-items: center; + justify-content: space-between; + + .FormLabel { + font-size: 1rem; + font-weight: 800; + text-align: end; + } + + .FormInput { + color: @light; + grid-column: 2; + padding: 0.5rem; + border-radius: 0.25rem; + font-family: Montserrat; + background-color: @dark; + } + + .FormInput[type="checkbox"] { + width: auto; + margin-right: auto; + } + } + + .FormButtons { + display: flex; + margin-top: 1rem; + gap: 0.5rem; + justify-content: space-around; + + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + + [type="submit"] { + background-color: #ff4603; + } + + button { + background-color: @dark; + color: @light; + border: 0.1rem solid #ff4603; + + &:hover { + border: 0.1rem solid @light; + } + } + } + } +} diff --git a/rushs/eplace/src/pages/utils.js b/rushs/eplace/src/pages/utils.js new file mode 100644 index 0000000..f8b1008 --- /dev/null +++ b/rushs/eplace/src/pages/utils.js @@ -0,0 +1,95 @@ +/** + * Global variables + */ +let [leftTimer, rightTimer] = [null, null]; +let [leftSize, rightSize] = [ + localStorage.getItem("leftSize") ?? 0, + localStorage.getItem("rightSize") ?? 0, +]; + +const parentContainer = document.getElementById("container"); + +const leftContainer = document.getElementById("left-container"); +const closeLeftButton = document.getElementById("close-left"); +const rightContainer = document.getElementById("right-container"); +const closeRightButton = document.getElementById("close-right"); + +leftContainer.classList.toggle("Hidden", !leftSize); + +/** + * Calculate the layout of the home page + */ +export const calculateLayout = () => { + const parentContainerSize = `${4.5 - leftSize - rightSize}fr`; + + // left and right are reversed because of the grid layout + parentContainer.style.gridTemplateColumns = `${leftSize}fr ${parentContainerSize} ${rightSize}fr`; + leftContainer.style.opacity = leftSize; + rightContainer.style.opacity = rightSize; +}; + +closeLeftButton.addEventListener("click", () => { + leftSize = 1 - leftSize; + localStorage.setItem("leftSize", leftSize); + + calculateLayout(); + setTimeout( + () => { + leftContainer.classList.toggle("Hidden", true); + }, + leftSize ? 0 : 300, + ); +}); + +closeRightButton.addEventListener("click", () => { + rightSize = 1 - rightSize; + localStorage.setItem("rightSize", rightSize); + + calculateLayout(); + setTimeout( + () => { + rightContainer.classList.toggle("Hidden", true); + }, + rightSize ? 0 : 300, + ); +}); + +// If the mouse holds on the left side of the screen, open the left container +document.addEventListener("mousemove", (e) => { + if (e.clientX < 10) { + if (!leftTimer) { + leftTimer = setTimeout(() => { + leftSize = 1; + localStorage.setItem("leftSize", leftSize); + + calculateLayout(); + setTimeout(() => { + leftContainer.classList.toggle("Hidden", false); + }, 300); + }, 200); + } + } else { + clearTimeout(leftTimer); + leftTimer = null; + } +}); + +// If the mouse holds on the right side of the screen, open the right container +document.addEventListener("mousemove", (e) => { + if (e.clientX > window.innerWidth - 10) { + if (!rightTimer) { + rightTimer = setTimeout(() => { + rightSize = 1; + localStorage.setItem("rightSize", rightSize); + + calculateLayout(); + setTimeout(() => { + rightContainer.classList.toggle("Hidden", false); + }, 300); + }, 200); + } + } else { + clearTimeout(rightTimer); + rightTimer = null; + } +}); diff --git a/rushs/eplace/src/rooms/canvas/index.js b/rushs/eplace/src/rooms/canvas/index.js new file mode 100644 index 0000000..440e0d3 --- /dev/null +++ b/rushs/eplace/src/rooms/canvas/index.js @@ -0,0 +1,96 @@ +// FIXME: This file should handle the room canvas API +// Link buttons to their respective functions +// Functions may include: + +import { getStudent } from "../../students"; +import { authedAPIRequest } from "../../utils/auth"; +import { getPlacementData } from "./utils"; + +// - getCanvas (get the canvas of a room and deserialize it) +export async function getCanvas(slug) { + const config = { + method: "get", + }; + + return authedAPIRequest(`/rooms/${slug}/canvas`, config) + .then(async (res) => { + if (!res) { + return null; + } + + const response = await res.json(); + + const pixels = response.pixels + .split("") + .map((c) => c.charCodeAt(0).toString(2).padStart(8, "0")) + .join("") + .match(/.{5}/g) + .map((b) => parseInt(b, 2)); + + return pixels; + }) + .catch((error) => { + console.log(error); + return null; + }); +} +// - subscribeToRoom (subscribe to the stream of a room) +// - getPixelInfo (get the pixel info of a room) +export async function getPixelInfo() { + const info = getPlacementData(); + + const response = await authedAPIRequest( + `/rooms/epi-place/canvas/pixels?posX=${info.posX}&posY=${info.posY}`, + { method: "get" }, + ); + + if (!response) { + return null; + } else { + return response.json(); + } +} + +// - placePixel (place a pixel in a room) +export async function placePixel() { + const info = getPlacementData(); + + const res = await authedAPIRequest(`/rooms/epi-place/canvas/pixels`, { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + body: JSON.stringify({ + posX: info.posX, + posY: info.posY, + color: info.color, + }), + }); + + if (!res) { + return; + } + + const response = await res.json(); + + const placeDate = new Date(response.timestamp); + const studentInfo = await getStudent(response.placedByUid); + + if (!studentInfo) { + return; + } + + document.getElementById("tooltip-time").innerHTML = + placeDate.toLocaleTimeString(); + document.getElementById("tooltip-date").innerHTML = + placeDate.toLocaleDateString(); + document + .getElementById("tooltip-info-avatar") + .setAttribute("src", studentInfo.avatarURL ?? "/default-avatar.png"); + document.getElementById("tooltip-info-quote").innerHTML = studentInfo.quote; + document.getElementById("tooltip-info-login").innerHTML = studentInfo.login; +} +document + .getElementById("color-place-button") + .addEventListener("click", placePixel); diff --git a/rushs/eplace/src/rooms/canvas/utils.js b/rushs/eplace/src/rooms/canvas/utils.js new file mode 100644 index 0000000..5737dbb --- /dev/null +++ b/rushs/eplace/src/rooms/canvas/utils.js @@ -0,0 +1,432 @@ +// This file handles the room canvas DOM manipulation +// Functions includes: +// - initCanvas (initialize the canvas) +// - renderCanvasUpdate (render a canvas update) +// - getPlacementData (get the necessary data to place a pixel) +// - toggleTooltip (toggle the tooltip and display the pixel's information) + +import $ from "jquery"; +import { getPixelInfo } from "."; +import { getStudent } from "../../students"; + +const canvasContainer = $("#canvas-container")?.[0]; +const canvas = $("#canvas")?.[0]; +const canvasCtx = canvas.getContext("2d"); +const selector = $("#selector")?.[0]; + +const positionTooltip = $("#position-tooltip")?.[0]; +const tooltip = $("#tooltip")?.[0]; +const colorPicker = $("#color-picker")?.[0]; +const colorWheelContainer = $("#color-wheel-container")?.[0]; +const colorWheel = $("#color-wheel")?.[0]; + +/** + * Global variables + */ +let board, palette, selectedColorIdx; +let animation; + +const zoomSpeed = 1 / 25; +let zoom = 2.5; + +let x, y; +let cx = 0; +let cy = 0; +let target = { x: 0, y: 0 }; +let isDrag = false; + +/** + * Returns the necessary data to place a pixel + * @returns {{color: number, posX: number, posX: number}} the data + */ +export const getPlacementData = () => ({ + color: selectedColorIdx, + posX: target.x, + posY: target.y, +}); + +/** + * Toggle the tooltip and display the pixel's information + * @param {boolean} state + */ +export const toggleTooltip = async (state = false) => { + tooltip.style.display = state ? "flex" : "none"; + + if (state) { + const pixelInfo = await getPixelInfo(); + const uid = pixelInfo.placedByUid; + const placeDate = new Date(pixelInfo.timestamp); + + if (!pixelInfo) { + throw new Error( + 'An error occured while hitting the "/rooms/epi-place/canvas/pixels" endpoint', + ); + } + + const studentInfo = await getStudent(uid); + + if (!studentInfo) { + throw new Error( + 'An error occured while hitting the "/students/:id" endpoint', + ); + } + + document.getElementById("tooltip-time").innerHTML = + placeDate.toLocaleTimeString(); + document.getElementById("tooltip-date").innerHTML = + placeDate.toLocaleDateString(); + document + .getElementById("tooltip-info-avatar") + .setAttribute( + "src", + studentInfo.avatarURL ?? "/default-avatar.png", + ); + document.getElementById("tooltip-info-quote").innerHTML = + studentInfo.quote; + document.getElementById("tooltip-info-login").innerHTML = + studentInfo.login; + // FIXME: You should implement or call a function to get the pixel's information + // and display it. Make use of target.x and target.y to get the pixel's position. + } +}; + +/** + * Calculate the target position according to the top left corner of the canvas + * @param {*} event + * @returns {x: number, y: number} the target position + */ +const calculateTarget = (event) => { + const rect = canvas.getBoundingClientRect(); + const scaleX = canvas.width / rect.width; + const scaleY = canvas.height / rect.height; + const canvasLeft = rect.left + window.pageXOffset; + const canvasTop = rect.top + window.pageYOffset; + + return { + x: Math.floor( + ((event?.pageX ?? window.innerWidth / 2) - canvasLeft) * scaleX, + ), + y: Math.floor( + ((event?.pageY ?? window.innerHeight / 2) - canvasTop) * scaleY, + ), + }; +}; + +/** + * Update the position tooltip + * @param {*} event + */ +const positionUpdate = (event) => positionDisplay(calculateTarget(event)); + +/** + * Update the position tooltip + * @param {{x: number, y: number}} target + */ +const positionDisplay = ({ x, y }) => { + positionTooltip.innerText = `X=${x} Y=${y}`; + canvas.style.transform = `translate(${cx}px, ${cy}px) scale(${zoom})`; + + // We add the canvas.width * zoom to make cx and cy positive + let selectorX = cx + canvas.width * zoom; + let selectorY = cy + canvas.height * zoom; + + // Make odd canvas align + if (canvas.width % 2 !== 0) { + selectorX += zoom / 2; + selectorY += zoom / 2; + } + + // Find the translate + selectorX %= zoom; + selectorY %= zoom; + + // Center selector on the pixel + selectorX -= zoom / 2; + selectorY -= zoom / 2; + + selector.style.transform = `translate(${selectorX}px, ${selectorY}px) scale(${zoom})`; +}; + +// Toggle the color wheel on click on the color picker +colorPicker.addEventListener("click", () => { + const state = colorWheelContainer.style.display; + + colorWheelContainer.style.display = + !state || state === "none" ? "block" : "none"; +}); + +/** + * Transform #RRGGBB to 0xBBGGRRAA + * @param {string} hex + * @returns {number} the 32 bits color + */ +const transformHexTo32Bits = (hex) => { + const reverse = hex.substring(1).match(/.{2}/g).reverse().join(""); + + return parseInt(`0xFF${reverse}`, 16); +}; + +/** + * Render the canvas + * @param {number[]} pixels + * @param {string[]} colors + */ +const renderCanvas = (pixels, colors) => { + const img = new ImageData(canvas.width, canvas.height); + const data = new Uint32Array(img.data.buffer); + + board = pixels; + palette = colors; + for (let i = 0; i < pixels.length; i++) { + data[i] = transformHexTo32Bits(colors[pixels[i]]); + } + + canvasCtx.putImageData(img, 0, 0); + canvasCtx.imageSmoothingEnabled = false; + canvas.style.imageRendering = "pixelated"; + + // Remove all the colors from the color wheel + while (colorWheel.firstChild) { + colorWheel.removeChild(colorWheel.firstChild); + } + + // Add the colors to the color wheel + for (let i = 0; i < colors.length; i++) { + const btn = document.createElement("button"); + + colorWheel.appendChild(btn); + + btn.addEventListener("click", () => { + selectedColorIdx = i; + colorPicker.style.color = colors[i]; + colorPicker.style.border = `${colors[i]} 0.1rem solid`; + }); + + btn.style.backgroundColor = colors[i]; + } +}; + +/** + * Initialize the canvas + * @param {*} roomConfig + * @param {number[]} pixels + */ +export const initCanvas = (roomConfig, pixels) => { + const canvasDimensions = roomConfig.metadata.canvasDimensions; + + canvas.width = canvasDimensions; + canvas.height = canvasDimensions; + + positionDisplay({ x: canvasDimensions / 2, y: canvasDimensions / 2 }); + selectedColorIdx = 0; + + const roomColors = roomConfig.settings.roomColors.split(","); + + colorPicker.style.color = roomColors[0]; + colorPicker.style.border = `${roomColors[0]} 0.1rem solid`; + + renderCanvas(pixels, roomColors); +}; + +/** + * Update the canvas + * @param {string} color + * @param {number} x + * @param {number} y + */ +export const renderCanvasUpdate = (color, x, y) => { + const img = new ImageData(canvas.width, canvas.height); + const data = new Uint32Array(img.data.buffer); + + board[y * canvas.width + x] = color; + for (let i = 0; i < board.length; i++) { + data[i] = transformHexTo32Bits(palette[board[i]]); + } + + canvasCtx.putImageData(img, 0, 0); +}; + +/** + * Reset the canvas values + */ +export const resetValues = () => { + zoom = 2.5; + x = 0; + y = 0; + cx = 0; + cy = 0; + isDrag = false; + + positionDisplay({ x, y }); + colorWheelContainer.style.display = "none"; + toggleTooltip(false); +}; + +// Handle scroll on canvas +document.addEventListener("wheel", (e) => { + // Make sure we're scrolling on the canvas or the body and not the UI + if (e.target !== canvas && e.target !== canvasContainer) { + return; + } + + clearInterval(animation); + toggleTooltip(false); + + const delta = Math.sign(e.deltaY) * zoomSpeed; + const zoomFactor = 1 + delta; + const oldZoom = zoom; + const newZoom = Math.max(2.5, Math.min(40, oldZoom * zoomFactor)); + + // Get the position of the mouse relative to the canvas + const mouseX = e.clientX - window.innerWidth / 2; + const mouseY = e.clientY - window.innerHeight / 2; + + // Calculate the new center point based on the mouse position + const newCx = mouseX - (mouseX - cx) * (newZoom / oldZoom); + const newCy = mouseY - (mouseY - cy) * (newZoom / oldZoom); + + if (newZoom !== oldZoom) { + zoom = newZoom; + cx = newCx; + cy = newCy; + positionUpdate(); + } +}); + +// Handle click and drag on canvas +document.addEventListener("mousedown", (e) => { + // Make sure we're clicking on the canvas or the body and not the UI + if (e.target !== canvas && e.target !== canvasContainer) { + return; + } + + e.preventDefault(); + + // Ignore if right click + if (e.button === 2) { + return; + } + + clearInterval(animation); + + isDrag = false; + x = e.clientX; + y = e.clientY; + + document.addEventListener("mousemove", mouseMove); +}); + +// Smooth animation +function easeOutQuart(t, b, c, d) { + t /= d; + t--; + return -c * (t * t * t * t - 1) + b; +} + +// Handle when the user releases the mouse +document.addEventListener("mouseup", (e) => { + document.removeEventListener("mousemove", mouseMove); + + // Make sure we're clicking on the canvas or the body and not the UI + if (e.target !== canvas && e.target !== canvasContainer) { + return; + } + + e.preventDefault(); + + // Get the tile position + target = calculateTarget(e); + + // Make sure we're clicking on the canvas + if ( + target.x >= 0 && + target.x < canvas.width && + target.y >= 0 && + target.y < canvas.height + ) { + // We want to differentiate between a click and a drag + // If it is a click, we want to move the camera to the clicked tile + + // We wait to see if the position changed + // If it did not, we consider it a click + if (!isDrag) { + const duration = 1000; + const startZoom = zoom; + const endZoom = Math.max(15, Math.min(40, zoom)); + + // Get the position of the click in relation to the center of the screen + const clickX = e.clientX - window.innerWidth / 2; + const clickY = e.clientY - window.innerHeight / 2; + const canvaswidthzoom = canvas.width * startZoom; + const canvasheightzoom = canvas.height * startZoom; + const startx = (cx + canvaswidthzoom / 2) / startZoom; + const starty = (cy + canvasheightzoom / 2) / startZoom; + const endx = startx - clickX / startZoom; + const endy = starty - clickY / startZoom; + const endCx = endx * endZoom - (canvas.width / 2) * endZoom; + const endCy = endy * endZoom - (canvas.height / 2) * endZoom; + const startCx = cx; + const startCy = cy; + const startTime = Date.now(); + + // If the distance is small enough, we just warp to it + if ( + Math.abs(endCx - startCx) < 10 && + Math.abs(endCy - startCy) < 10 + ) { + cx = endCx; + cy = endCy; + zoom = endZoom; + canvas.style.transform = `translate(${cx}px, ${cy}px) scale(${zoom})`; + } else { + clearInterval(animation); + + animation = setInterval(() => { + const elapsed = Date.now() - startTime; + + if (elapsed >= duration) { + clearInterval(animation); + return; + } + + const t = elapsed / duration; + + zoom = easeOutQuart(t, startZoom, endZoom - startZoom, 1); + cx = easeOutQuart(t, startCx, endCx - startCx, 1); + cy = easeOutQuart(t, startCy, endCy - startCy, 1); + + positionUpdate(); + }, 10); + } + } + + // Toggle the tooltip if it is a click + toggleTooltip(!isDrag); + + // Update the position of the tooltip + positionDisplay(target); + } +}); + +// Handle mouse move +const mouseMove = (e) => { + e.preventDefault(); + + toggleTooltip(false); + positionUpdate(); + + const dx = e.clientX - x; + const dy = e.clientY - y; + + // For a big enough delta, we consider it a drag + if (Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5) { + isDrag = true; + } + + x = e.clientX; + y = e.clientY; + cx += dx; + cy += dy; + + canvas.style.transform = `translate(${cx}px, ${cy}px) scale(${zoom})`; +}; diff --git a/rushs/eplace/src/rooms/chat/index.js b/rushs/eplace/src/rooms/chat/index.js new file mode 100644 index 0000000..493f142 --- /dev/null +++ b/rushs/eplace/src/rooms/chat/index.js @@ -0,0 +1,4 @@ +// FIXME: This file should handle the room's chat subscription +// Functions may include: +// - subscribeToRoomChat (subscribe to the chat of a room) +// - sendChatMessage (send a chat message) diff --git a/rushs/eplace/src/rooms/chat/utils.js b/rushs/eplace/src/rooms/chat/utils.js new file mode 100644 index 0000000..2d21ab2 --- /dev/null +++ b/rushs/eplace/src/rooms/chat/utils.js @@ -0,0 +1,6 @@ +// FIXME: This file should handle the room's chat DOM manipulation +// Link buttons to their respective functions +// Handle the chat input form and its submission +// Functions may include: +// - displayChatMessage (display a chat message in the DOM) +// - displayUserEvents (display a user event in the DOM) diff --git a/rushs/eplace/src/rooms/index.js b/rushs/eplace/src/rooms/index.js new file mode 100644 index 0000000..dde88e6 --- /dev/null +++ b/rushs/eplace/src/rooms/index.js @@ -0,0 +1,50 @@ +// FIXME: This file should handle the rooms API +// Functions may include: + +import { subscribe } from "../utils/streams"; +import { authedAPIRequest } from "../utils/auth"; + +// - fetchRoomConfig (get the configuration of a room) +export async function fetchRoomConfig(slug) { + const config = { + method: "get", + }; + + return authedAPIRequest(`/rooms/${slug}/config`, config) + .then(async (res) => { + if (!res) { + return null; + } + + const response = await res.json(); + + document.getElementById("room-name").innerHTML = + response.metadata.name; + const description = document.getElementById("room-description"); + + if (response.metadata.description) { + description.innerHTML = response.metadata.description; + description.style.display = "inherit"; + } else { + description.style.display = "none"; + } + + return response; + }) + .catch((error) => { + console.log(error); + return null; + }); +} +// - joinRoom (join a room by its slug) +export function joinRoom(slug) { + if (!slug) { + slug = "epi-place"; + } + + subscribe(slug); +} +// - listRooms (list all the rooms available) +// - createRoom (create a room) +// - updateRoom (update a room's configuration) +// - deleteRoom (delete a room) diff --git a/rushs/eplace/src/rooms/utils.js b/rushs/eplace/src/rooms/utils.js new file mode 100644 index 0000000..5e94739 --- /dev/null +++ b/rushs/eplace/src/rooms/utils.js @@ -0,0 +1,6 @@ +// FIXME: This file should handle the rooms DOM manipulation +// Link buttons to their respective functions +// Functions may include: +// - showModal (add a form modal to the DOM) +// - createRoomObject (create a room in the DOM) +// - displayRoomsList (display the rooms list in the DOM) diff --git a/rushs/eplace/src/students/index.js b/rushs/eplace/src/students/index.js new file mode 100644 index 0000000..2aa18a2 --- /dev/null +++ b/rushs/eplace/src/students/index.js @@ -0,0 +1,19 @@ +// FIXME: This file should handle the students API +// Functions may include: + +import { authedAPIRequest } from "../utils/auth"; + +// - getStudent (get a student from the API by its uid or login) +export async function getStudent(id) { + const response = await authedAPIRequest(`/students/${id}`, { + method: "get", + }); + + if (!response) { + return null; + } else { + return response.json(); + } +} +// - getUserUidFromToken (get the user's uid from the token in local storage) +// - updateStudent (update the student's profile through the API) diff --git a/rushs/eplace/src/students/utils.js b/rushs/eplace/src/students/utils.js new file mode 100644 index 0000000..09bb32e --- /dev/null +++ b/rushs/eplace/src/students/utils.js @@ -0,0 +1,5 @@ +// FIXME: This file should handle the students DOM manipulation +// Link buttons to their respective functions +// Functions may include: +// - displayStudentProfile (display the student's profile in the DOM) +// - showModal (add a form modal to the DOM) diff --git a/rushs/eplace/src/utils/auth.js b/rushs/eplace/src/utils/auth.js new file mode 100644 index 0000000..2576282 --- /dev/null +++ b/rushs/eplace/src/utils/auth.js @@ -0,0 +1,124 @@ +// FIXME: This file should handle the authentication +// Exports must include: +// - authedAPIRequest (make an authenticated request to the API) + +/** + * This function makes an authenticated request to the API + * This function must always hit the /api/* endpoint. + * @param {string} endpoint + * @param {object} options This object should at least contain the method. + * For the other options, you can refer to the fetch documentation as it should be the same. + * @returns {Promise<Response>} the response + * We want a {Promise<Response>} so we can read the headers as well as the body, rather than + * just the body. + **/ +export async function authedAPIRequest(endpoint, options) { + if (localStorage.getItem("token")) { + // essaye de contacter l'endpoint + const headers = { + Authorization: `Bearer ${localStorage.getItem("token")}`, + }; + + if (options["headers"]) { + options["headers"]["Authorization"] = + `Bearer ${localStorage.getItem("token")}`; + } else { + options["headers"] = headers; + } + + const apiURL = `${import.meta.env.VITE_URL}/api${endpoint}`; + + try { + const response = await fetch(apiURL, options); + + if (response.status === 200) { + return response; + } else { + console.log("request error"); + console.log(response); + if ( + response.status === 401 && + (await response.json()).message.match(/Token expired/) + ) { + localStorage.removeItem("token"); + if (!(await sendTokenRequest())) { + return null; + } + + const response = await authedAPIRequest(endpoint, options); + + if (!response) { + return null; + } + + return response; + } else { + localStorage.clear(); + // window.location.replace(import.meta.env.VITE_URL); + await sendTokenRequest(); + return null; + } + } + } catch { + console.log("an error occured while fetching"); + return null; + } + } + + await sendTokenRequest(); + return null; +} + +// Functions may include: +// - sendTokenRequest (get a token or refresh it) +export async function sendTokenRequest() { + if ( + !localStorage.getItem("token") && + !localStorage.getItem("refresh_token") + ) { + const authQueryParams = { + client_id: import.meta.env.VITE_CLIENT_ID, + scope: "epita profile picture", + redirect_uri: `${import.meta.env.VITE_URL}/complete/epita/`, + response_type: "code", + }; + const url = new URL(`${import.meta.env.VITE_AUTH_URL}/authorize`); + + //`?client_id=${authQueryParams.client_id}&scope=${authQueryParams.scope}&redirect_uri=${authQueryParams.redirect_uri}&response_type=${authQueryParams.response_type}`, + url.searchParams.append("client_id", authQueryParams.client_id); + url.searchParams.append("scope", authQueryParams.scope); + url.searchParams.append("redirect_uri", authQueryParams.redirect_uri); + url.searchParams.append("response_type", authQueryParams.response_type); + + window.location.replace(url); + return false; + } else if (localStorage.getItem("refresh_token")) { + const form = new FormData(); + + form.append("client_id", import.meta.env.VITE_CLIENT_ID); + form.append( + "redirect_uri", + `${import.meta.env.VITE_URL}/complete/epita/`, + ); + form.append("grant_type", "refresh_token"); + form.append("refresh_token", localStorage.getItem("refresh_token")); + const res = await fetch(`${import.meta.env.VITE_URL}/auth-api/token`, { + method: "POST", + body: form, + }); + + if (res.status === 200) { + const response = await res.json(); + + localStorage.setItem("token", response.id_token); + localStorage.setItem("refresh_token", response.refresh_token); + return true; + } else { + localStorage.clear(); + // window.location.replace(import.meta.env.VITE_URL); + // HERE ptetre return direct senTokenRequest + await sendTokenRequest(); + return false; + } + } +} diff --git a/rushs/eplace/src/utils/notify.js b/rushs/eplace/src/utils/notify.js new file mode 100644 index 0000000..b6ed7dc --- /dev/null +++ b/rushs/eplace/src/utils/notify.js @@ -0,0 +1,57 @@ +import $ from "jquery"; +import alertHtml from "../components/notifications/index.html"; + +const alertContainer = $("#alert-container")?.[0]; + +const iconMap = { + info: "fa-info-circle", + success: "fa-thumbs-up", + warning: "fa-exclamation-triangle", + error: "ffa fa-exclamation-circle", +}; + +/** + * Create an alert + * @param {string} title + * @param {string} message + * @param {string} type - success, warning, error + */ +export const createAlert = (title, message, type) => { + $.ajax({ + url: alertHtml, + success: (data) => { + const [alert] = $(data); + + // Return if the alert cannot be created, usefull when a redirect is made + if (!alertContainer || !alert || !alert.classList) { + return; + } + + // Add the type class to the alert + alert.classList.add( + `Alert${type.charAt(0).toUpperCase() + type.slice(1)}`, + ); + + // Replace values in innerHTML + alert.innerHTML = alert.innerHTML + .replace(/{{title}}/g, title) + .replace(/{{content}}/g, message) + .replace(/{{icon_classes}}/g, iconMap[type]); + + // Get the close button + const closeBtn = alert.getElementsByClassName("AlertClose")?.[0]; + + closeBtn?.addEventListener("click", () => { + alert.remove(); + }); + + // Append the alert to the container + alertContainer.append(alert); + + // Remove the alert after 5 seconds + setTimeout(() => { + alert.remove(); + }, 5000); + }, + }); +}; diff --git a/rushs/eplace/src/utils/rateLimits.js b/rushs/eplace/src/utils/rateLimits.js new file mode 100644 index 0000000..d7b11a6 --- /dev/null +++ b/rushs/eplace/src/utils/rateLimits.js @@ -0,0 +1,3 @@ +// FIXME: This file should handle the rate limits +// Functions may include: +// - displayTimer (util function to display the timer for the rate limit) diff --git a/rushs/eplace/src/utils/streams.js b/rushs/eplace/src/utils/streams.js new file mode 100644 index 0000000..f714527 --- /dev/null +++ b/rushs/eplace/src/utils/streams.js @@ -0,0 +1,108 @@ +// FIXME: This file should handle the sockets and the subscriptions +import { io } from "socket.io-client"; +import { v4 as uuidv4 } from "uuid"; + +import { createAlert } from "./notify"; +import { fetchRoomConfig, joinRoom } from "../rooms"; +import { getCanvas } from "../rooms/canvas"; +import { initCanvas, renderCanvasUpdate } from "../rooms/canvas/utils"; +import { sendTokenRequest } from "../utils/auth"; + +let subscribed = false; + +export let socket = undefined; + +const updateBuffer = []; + +// Exports must include +// - initSocket (initialize the connection to the socket server) +export async function initSocket() { + if (!localStorage.getItem("token")) { + if (!(await sendTokenRequest())) { + createAlert("ForgeID", "Authentication failed", "error"); + return; + } + + createAlert("ForgeID", "Authentication successful", "success"); + } + + if (socket) { + return socket; + } + + socket = io(import.meta.env.VITE_URL, { + extraHeaders: { + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + }); + socket.on("connect", () => { + joinRoom(); + }); + + socket.on("message", async (msg) => { + if (msg.result && msg.result.type === "started") { + const roomConfig = await fetchRoomConfig("epi-place"); + + if (!roomConfig) { + return; + } + + const pixels = await getCanvas("epi-place"); + + if (!pixels) { + return; + } + + initCanvas(roomConfig, pixels); + // debuffer pixel updates + catchUpOnUpdates(); + subscribed = true; + } + }); + + socket.on("pixel-update", (update) => { + if (!subscribed) { + updateBuffer.push({ + color: update.result.data.json.color, + posX: update.result.data.json.posX, + posY: update.result.data.json.posY, + }); + } else { + renderCanvasUpdate( + update.result.data.json.color, + update.result.data.json.posX, + update.result.data.json.posY, + ); + } + }); + return socket; +} +// - socket (variable resulting of initSocket function) + +// Functions may include: +// - subscribe (subscribe to a room's stream or chat) +export function subscribe(slug) { + const subscription = { + id: uuidv4(), + method: "subscription", + params: { + path: "rooms.canvas.getStream", + input: { + json: { + roomSlug: slug, + }, + }, + }, + }; + + socket.send(subscription); +} +function catchUpOnUpdates() { + while (updateBuffer.length > 0) { + const update = updateBuffer.pop(); + + renderCanvasUpdate(update.color, update.posX, update.posY); + } +} +// - unsubscribe (unsubscribe from a room's stream or chat) +// - sendMessage (send a message to a room's chat) diff --git a/rushs/eplace/vite.config.js b/rushs/eplace/vite.config.js new file mode 100644 index 0000000..bb8b7a2 --- /dev/null +++ b/rushs/eplace/vite.config.js @@ -0,0 +1,41 @@ +import { resolve } from "path"; +import { defineConfig, loadEnv } from "vite"; +import dns from "dns"; + +dns.setDefaultResultOrder("verbatim"); +const root = resolve(__dirname, "src/pages/"); + +export default ({ mode }) => { + process.env = { ...process.env, ...loadEnv(mode, process.cwd()) }; + + return defineConfig({ + root, + server: { + host: process.env.VITE_HOST, + port: process.env.VITE_PORT, + proxy: { + // $VITE_URL/api* -> $VITE_API_URL/api* + "/api": { + target: process.env.VITE_API_URL, + changeOrigin: true, + }, + // $VITE_URL/socket.io* -> $VITE_API_URL/socket.io* + "/socket.io": { + target: process.env.VITE_API_URL, + changeOrigin: true, + ws: true, + }, + // $VITE_URL/auth-api* -> $VITE_AUTH_URL* + "/auth-api": { + target: process.env.VITE_AUTH_URL, + changeOrigin: true, + secure: false, + rewrite: (path) => path.replace(/^\/auth-api/, ""), + }, + }, + }, + + publicDir: resolve(__dirname, "public"), + assetsInclude: ["src/components/**/*.html"], + }); +}; diff --git a/rushs/eplace/yarn.lock b/rushs/eplace/yarn.lock new file mode 100644 index 0000000..8b7336f --- /dev/null +++ b/rushs/eplace/yarn.lock @@ -0,0 +1,1957 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@esbuild/android-arm64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.15.tgz#893ad71f3920ccb919e1757c387756a9bca2ef42" + integrity sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA== + +"@esbuild/android-arm@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.15.tgz#143e0d4e4c08c786ea410b9a7739779a9a1315d8" + integrity sha512-sRSOVlLawAktpMvDyJIkdLI/c/kdRTOqo8t6ImVxg8yT7LQDUYV5Rp2FKeEosLr6ZCja9UjYAzyRSxGteSJPYg== + +"@esbuild/android-x64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.15.tgz#d2d12a7676b2589864281b2274355200916540bc" + integrity sha512-MzDqnNajQZ63YkaUWVl9uuhcWyEyh69HGpMIrf+acR4otMkfLJ4sUCxqwbCyPGicE9dVlrysI3lMcDBjGiBBcQ== + +"@esbuild/darwin-arm64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.15.tgz#2e88e79f1d327a2a7d9d06397e5232eb0a473d61" + integrity sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA== + +"@esbuild/darwin-x64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.15.tgz#9384e64c0be91388c57be6d3a5eaf1c32a99c91d" + integrity sha512-NbImBas2rXwYI52BOKTW342Tm3LTeVlaOQ4QPZ7XuWNKiO226DisFk/RyPk3T0CKZkKMuU69yOvlapJEmax7cg== + +"@esbuild/freebsd-arm64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.15.tgz#2ad5a35bc52ebd9ca6b845dbc59ba39647a93c1a" + integrity sha512-Xk9xMDjBVG6CfgoqlVczHAdJnCs0/oeFOspFap5NkYAmRCT2qTn1vJWA2f419iMtsHSLm+O8B6SLV/HlY5cYKg== + +"@esbuild/freebsd-x64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.15.tgz#b513a48446f96c75fda5bef470e64d342d4379cd" + integrity sha512-3TWAnnEOdclvb2pnfsTWtdwthPfOz7qAfcwDLcfZyGJwm1SRZIMOeB5FODVhnM93mFSPsHB9b/PmxNNbSnd0RQ== + +"@esbuild/linux-arm64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.15.tgz#9697b168175bfd41fa9cc4a72dd0d48f24715f31" + integrity sha512-T0MVnYw9KT6b83/SqyznTs/3Jg2ODWrZfNccg11XjDehIved2oQfrX/wVuev9N936BpMRaTR9I1J0tdGgUgpJA== + +"@esbuild/linux-arm@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.15.tgz#5b22062c54f48cd92fab9ffd993732a52db70cd3" + integrity sha512-MLTgiXWEMAMr8nmS9Gigx43zPRmEfeBfGCwxFQEMgJ5MC53QKajaclW6XDPjwJvhbebv+RzK05TQjvH3/aM4Xw== + +"@esbuild/linux-ia32@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.15.tgz#eb28a13f9b60b5189fcc9e98e1024f6b657ba54c" + integrity sha512-wp02sHs015T23zsQtU4Cj57WiteiuASHlD7rXjKUyAGYzlOKDAjqK6bk5dMi2QEl/KVOcsjwL36kD+WW7vJt8Q== + +"@esbuild/linux-loong64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.15.tgz#32454bdfe144cf74b77895a8ad21a15cb81cfbe5" + integrity sha512-k7FsUJjGGSxwnBmMh8d7IbObWu+sF/qbwc+xKZkBe/lTAF16RqxRCnNHA7QTd3oS2AfGBAnHlXL67shV5bBThQ== + +"@esbuild/linux-mips64el@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.15.tgz#af12bde0d775a318fad90eb13a0455229a63987c" + integrity sha512-ZLWk6czDdog+Q9kE/Jfbilu24vEe/iW/Sj2d8EVsmiixQ1rM2RKH2n36qfxK4e8tVcaXkvuV3mU5zTZviE+NVQ== + +"@esbuild/linux-ppc64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.15.tgz#34c5ed145b2dfc493d3e652abac8bd3baa3865a5" + integrity sha512-mY6dPkIRAiFHRsGfOYZC8Q9rmr8vOBZBme0/j15zFUKM99d4ILY4WpOC7i/LqoY+RE7KaMaSfvY8CqjJtuO4xg== + +"@esbuild/linux-riscv64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.15.tgz#87bd515e837f2eb004b45f9e6a94dc5b93f22b92" + integrity sha512-EcyUtxffdDtWjjwIH8sKzpDRLcVtqANooMNASO59y+xmqqRYBBM7xVLQhqF7nksIbm2yHABptoioS9RAbVMWVA== + +"@esbuild/linux-s390x@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.15.tgz#20bf7947197f199ddac2ec412029a414ceae3aa3" + integrity sha512-BuS6Jx/ezxFuHxgsfvz7T4g4YlVrmCmg7UAwboeyNNg0OzNzKsIZXpr3Sb/ZREDXWgt48RO4UQRDBxJN3B9Rbg== + +"@esbuild/linux-x64@0.17.15": + version "0.17.15" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.15.tgz" + integrity sha512-JsdS0EgEViwuKsw5tiJQo9UdQdUJYuB+Mf6HxtJSPN35vez1hlrNb1KajvKWF5Sa35j17+rW1ECEO9iNrIXbNg== + +"@esbuild/netbsd-x64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.15.tgz#8da299b3ac6875836ca8cdc1925826498069ac65" + integrity sha512-R6fKjtUysYGym6uXf6qyNephVUQAGtf3n2RCsOST/neIwPqRWcnc3ogcielOd6pT+J0RDR1RGcy0ZY7d3uHVLA== + +"@esbuild/openbsd-x64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.15.tgz#04a1ec3d4e919714dba68dcf09eeb1228ad0d20c" + integrity sha512-mVD4PGc26b8PI60QaPUltYKeSX0wxuy0AltC+WCTFwvKCq2+OgLP4+fFd+hZXzO2xW1HPKcytZBdjqL6FQFa7w== + +"@esbuild/sunos-x64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.15.tgz#6694ebe4e16e5cd7dab6505ff7c28f9c1c695ce5" + integrity sha512-U6tYPovOkw3459t2CBwGcFYfFRjivcJJc1WC8Q3funIwX8x4fP+R6xL/QuTPNGOblbq/EUDxj9GU+dWKX0oWlQ== + +"@esbuild/win32-arm64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.15.tgz#1f95b2564193c8d1fee8f8129a0609728171d500" + integrity sha512-W+Z5F++wgKAleDABemiyXVnzXgvRFs+GVKThSI+mGgleLWluv0D7Diz4oQpgdpNzh4i2nNDzQtWbjJiqutRp6Q== + +"@esbuild/win32-ia32@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.15.tgz#c362b88b3df21916ed7bcf75c6d09c6bf3ae354a" + integrity sha512-Muz/+uGgheShKGqSVS1KsHtCyEzcdOn/W/Xbh6H91Etm+wiIfwZaBn1W58MeGtfI8WA961YMHFYTthBdQs4t+w== + +"@esbuild/win32-x64@0.17.15": + version "0.17.15" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.15.tgz#c2e737f3a201ebff8e2ac2b8e9f246b397ad19b8" + integrity sha512-DjDa9ywLUUmjhV2Y9wUTIF+1XsmuFGvZoCmOWkli1XcNAh5t25cc7fgsCx4Zi/Uurep3TTLyDiKATgGEg61pkA== + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/eslint-utils@^4.4.0": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz#e4c58fdcf0696e7a5f19c30201ed43123ab15abc" + integrity sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/config-array@^0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.20.0.tgz#7a1232e82376712d3340012a2f561a2764d1988f" + integrity sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/config-helpers@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.2.1.tgz#26042c028d1beee5ce2235a7929b91c52651646d" + integrity sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw== + +"@eslint/core@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.13.0.tgz#bf02f209846d3bf996f9e8009db62df2739b458c" + integrity sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964" + integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.25.1": + version "9.25.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.25.1.tgz#25f5c930c2b68b5ebe7ac857f754cbd61ef6d117" + integrity sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@eslint/plugin-kit@^0.2.8": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz#47488d8f8171b5d4613e833313f3ce708e3525f8" + integrity sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA== + dependencies: + "@eslint/core" "^0.13.0" + levn "^0.4.1" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161" + integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgr/core@^0.2.3": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" + integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== + +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + +"@types/estree@^1.0.6": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" + integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@typescript-eslint/scope-manager@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz#48c7f7d729ea038e36cae0ff511e48c2412fb11c" + integrity sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw== + dependencies: + "@typescript-eslint/types" "8.31.0" + "@typescript-eslint/visitor-keys" "8.31.0" + +"@typescript-eslint/types@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.31.0.tgz#c48e20ec47a43b72747714f49ea9f7b38a4fa6c1" + integrity sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ== + +"@typescript-eslint/typescript-estree@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz#9c7f84eff6ad23d63cf086c6e93af571cd561270" + integrity sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ== + dependencies: + "@typescript-eslint/types" "8.31.0" + "@typescript-eslint/visitor-keys" "8.31.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.0.1" + +"@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.31.0.tgz#6fb52471a29fdd16fc253d568c5ad4b048f78ba4" + integrity sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.31.0" + "@typescript-eslint/types" "8.31.0" + "@typescript-eslint/typescript-estree" "8.31.0" + +"@typescript-eslint/visitor-keys@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz#9a1a97ed16c60d4d1e7399b41c11a6d94ebc1ce5" + integrity sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ== + dependencies: + "@typescript-eslint/types" "8.31.0" + eslint-visitor-keys "^4.2.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.14.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-includes@^3.1.6: + version "3.1.6" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz" + integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + is-string "^1.0.7" + +array.prototype.flat@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz" + integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz" + integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +axios@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +builtins@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz" + integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + dependencies: + semver "^7.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +copy-anything@^2.0.1: + version "2.0.6" + resolved "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz" + integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw== + dependencies: + is-what "^3.14.1" + +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== + +debug@^3.2.6, debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.3.1, debug@^4.3.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +debug@^4.3.2, debug@~4.3.1, debug@~4.3.2: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.2.0" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +engine.io-client@~6.4.0: + version "6.4.0" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.4.0.tgz" + integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.11.0" + xmlhttprequest-ssl "~2.0.0" + +engine.io-parser@~5.0.3: + version "5.0.6" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz" + integrity sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw== + +errno@^0.1.1: + version "0.1.8" + resolved "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.2" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== + dependencies: + array-buffer-byte-length "^1.0.0" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.2.0" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.10" + is-weakref "^1.0.2" + object-inspect "^1.12.3" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.9" + +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +esbuild@^0.17.5: + version "0.17.15" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.17.15.tgz" + integrity sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw== + optionalDependencies: + "@esbuild/android-arm" "0.17.15" + "@esbuild/android-arm64" "0.17.15" + "@esbuild/android-x64" "0.17.15" + "@esbuild/darwin-arm64" "0.17.15" + "@esbuild/darwin-x64" "0.17.15" + "@esbuild/freebsd-arm64" "0.17.15" + "@esbuild/freebsd-x64" "0.17.15" + "@esbuild/linux-arm" "0.17.15" + "@esbuild/linux-arm64" "0.17.15" + "@esbuild/linux-ia32" "0.17.15" + "@esbuild/linux-loong64" "0.17.15" + "@esbuild/linux-mips64el" "0.17.15" + "@esbuild/linux-ppc64" "0.17.15" + "@esbuild/linux-riscv64" "0.17.15" + "@esbuild/linux-s390x" "0.17.15" + "@esbuild/linux-x64" "0.17.15" + "@esbuild/netbsd-x64" "0.17.15" + "@esbuild/openbsd-x64" "0.17.15" + "@esbuild/sunos-x64" "0.17.15" + "@esbuild/win32-arm64" "0.17.15" + "@esbuild/win32-ia32" "0.17.15" + "@esbuild/win32-x64" "0.17.15" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^8.8.0: + version "8.8.0" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== + +eslint-config-standard@^17.0.0: + version "17.0.0" + resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz" + integrity sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg== + +eslint-import-resolver-node@^0.3.7: + version "0.3.7" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz" + integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== + dependencies: + debug "^3.2.7" + is-core-module "^2.11.0" + resolve "^1.22.1" + +eslint-module-utils@^2.7.4: + version "2.7.4" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz" + integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== + dependencies: + debug "^3.2.7" + +eslint-plugin-es@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz" + integrity sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + +eslint-plugin-eslint-comments@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa" + integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ== + dependencies: + escape-string-regexp "^1.0.5" + ignore "^5.0.5" + +eslint-plugin-import@^2.25.2: + version "2.27.5" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz" + integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + array.prototype.flatmap "^1.3.1" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.7" + eslint-module-utils "^2.7.4" + has "^1.0.3" + is-core-module "^2.11.0" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.6" + resolve "^1.22.1" + semver "^6.3.0" + tsconfig-paths "^3.14.1" + +eslint-plugin-jest@^28.11.0: + version "28.11.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.11.0.tgz#2641ecb4411941bbddb3d7cf8a8ff1163fbb510e" + integrity sha512-QAfipLcNCWLVocVbZW8GimKn5p5iiMcgGbRzz8z/P5q7xw+cNEpYqyzFMtIF/ZgF2HLOyy+dYBut+DoYolvqig== + dependencies: + "@typescript-eslint/utils" "^6.0.0 || ^7.0.0 || ^8.0.0" + +eslint-plugin-n@^15.0.0: + version "15.7.0" + resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz" + integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q== + dependencies: + builtins "^5.0.1" + eslint-plugin-es "^4.1.0" + eslint-utils "^3.0.0" + ignore "^5.1.1" + is-core-module "^2.11.0" + minimatch "^3.1.2" + resolve "^1.22.1" + semver "^7.3.8" + +eslint-plugin-prettier@^5.2.6: + version "5.2.6" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.6.tgz#be39e3bb23bb3eeb7e7df0927cdb46e4d7945096" + integrity sha512-mUcf7QG2Tjk7H055Jk0lGBjbgDnfrvqjhXh9t2xLMSCjZVcw9Rb1V6sVNXO0th3jgeO7zllWPTNRil3JW94TnQ== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.11.0" + +eslint-plugin-promise@^6.0.0: + version "6.1.1" + resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz" + integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== + +eslint-scope@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.3.0.tgz#10cd3a918ffdd722f5f3f7b5b83db9b23c87340d" + integrity sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.4.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz" + integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== + +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + +eslint@^9.25.1: + version "9.25.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.25.1.tgz#8a7cf8dd0e6acb858f86029720adb1785ee57580" + integrity sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.20.0" + "@eslint/config-helpers" "^0.2.1" + "@eslint/core" "^0.13.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.25.1" + "@eslint/plugin-kit" "^0.2.8" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.3.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== + dependencies: + acorn "^8.14.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.0" + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +ignore@^5.0.5: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +ignore@^5.1.1, ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +image-size@~0.5.0: + version "0.5.5" + resolved "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz" + integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.11.0: + version "2.11.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.9: + version "1.1.10" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-what@^3.14.1: + version "3.14.1" + resolved "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz" + integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jquery@^3.6.4: + version "3.6.4" + resolved "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz" + integrity sha512-v28EW9DWDFpzcD9O5iyJXg3R3+q+mET5JhnjJzQUZMHOv67bpSIHq81GEYpPNZHG+XXHsfSme3nxp/hndKEcsQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +jwt-decode@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz" + integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +less@^4.1.3: + version "4.1.3" + resolved "https://registry.npmjs.org/less/-/less-4.1.3.tgz" + integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA== + dependencies: + copy-anything "^2.0.1" + parse-node-version "^1.0.1" + tslib "^2.3.0" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + image-size "~0.5.0" + make-dir "^2.1.0" + mime "^1.4.1" + needle "^3.1.0" + source-map "~0.6.0" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@^1.4.1: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.4: + version "3.3.6" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +needle@^3.1.0: + version "3.2.0" + resolved "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz" + integrity sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ== + dependencies: + debug "^3.2.6" + iconv-lite "^0.6.3" + sax "^1.2.4" + +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + +node-fetch@^3.3.1: + version "3.3.1" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz" + integrity sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + +object-inspect@^1.12.3, object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.values@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz" + integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-node-version@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +postcss@^8.4.21: + version "8.4.21" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz" + integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" + integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +regexpp@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.22.1: + version "1.22.2" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +rollup@^3.18.0: + version "3.20.2" + resolved "https://registry.npmjs.org/rollup/-/rollup-3.20.2.tgz" + integrity sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg== + optionalDependencies: + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +semver@^5.6.0: + version "5.7.1" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.0.0, semver@^7.3.8: + version "7.3.8" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + +semver@^7.6.0: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +socket.io-client@^4.6.1: + version "4.6.1" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.1.tgz" + integrity sha512-5UswCV6hpaRsNg5kkEHVcbBIXEYoVbMQaHJBXJCyEQ+CiFPV1NIOY0XOFWG4XR4GZcB8Kn6AsRs/9cy9TbqVMQ== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.4.0" + socket.io-parser "~4.2.1" + +socket.io-parser@~4.2.1: + version "4.2.2" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz" + integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map@~0.6.0: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +synckit@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.4.tgz#48972326b59723fc15b8d159803cf8302b545d59" + integrity sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ== + dependencies: + "@pkgr/core" "^0.2.3" + tslib "^2.8.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-api-utils@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" + integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== + +tsconfig-paths@^3.14.1: + version "3.14.2" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.3.0: + version "2.5.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + +tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + +vite@^4.2.0: + version "4.2.1" + resolved "https://registry.npmjs.org/vite/-/vite-4.2.1.tgz" + integrity sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg== + dependencies: + esbuild "^0.17.5" + postcss "^8.4.21" + resolve "^1.22.1" + rollup "^3.18.0" + optionalDependencies: + fsevents "~2.3.2" + +web-streams-polyfill@^3.0.3: + version "3.2.1" + resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +ws@~8.11.0: + version "8.11.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz" + integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== + +xmlhttprequest-ssl@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz" + integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/rushs/evalexpr/80cols/80cols.sh b/rushs/evalexpr/80cols/80cols.sh new file mode 100755 index 0000000..d66cf9b --- /dev/null +++ b/rushs/evalexpr/80cols/80cols.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +[ $# -ne 1 ] && exit 1 +[ -f $1 ] || exit 1 + +while IFS='' read -r line; do + var=$(printf '%s' "$line" | wc -m) + [ "$var" -ge 80 ] && printf '%s\n' "$line" +done < "$1" + +exit 0 diff --git a/rushs/evalexpr/80cols_grep/80cols.grep b/rushs/evalexpr/80cols_grep/80cols.grep new file mode 100644 index 0000000..1fe0c1f --- /dev/null +++ b/rushs/evalexpr/80cols_grep/80cols.grep @@ -0,0 +1 @@ +.\{80,\} diff --git a/rushs/evalexpr/a.out b/rushs/evalexpr/a.out Binary files differnew file mode 100755 index 0000000..33e84ed --- /dev/null +++ b/rushs/evalexpr/a.out diff --git a/rushs/evalexpr/add_int_ptr/add_int_ptr.c b/rushs/evalexpr/add_int_ptr/add_int_ptr.c new file mode 100644 index 0000000..ad48639 --- /dev/null +++ b/rushs/evalexpr/add_int_ptr/add_int_ptr.c @@ -0,0 +1,7 @@ +int *add_int_ptr(int *a, int *b) +{ + if (!a || !b) + return a; + *a += *b; + return a; +} diff --git a/rushs/evalexpr/alphabet/alphabet.c b/rushs/evalexpr/alphabet/alphabet.c new file mode 100644 index 0000000..9496c66 --- /dev/null +++ b/rushs/evalexpr/alphabet/alphabet.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +int main(void) +{ + for (char i = 'a'; i < 'z'; i++) + { + putchar(i); + putchar(' '); + } + putchar('z'); + putchar('\n'); + return 0; +} diff --git a/rushs/evalexpr/alphanum/alphanum.sh b/rushs/evalexpr/alphanum/alphanum.sh new file mode 100755 index 0000000..e4c5aee --- /dev/null +++ b/rushs/evalexpr/alphanum/alphanum.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +letters() +{ + grepped=$(echo "$1" | grep -E "^[a-zA-Z]+$") + [ "$1" = "$grepped" ] && return 0 || return 1 +} + +empty() +{ + if echo "$1" | grep -qE '^[[:space:]]+$'; then + return 0 + fi + return 1 +} + +digit() +{ + grepped=$(echo "$1" | grep -E "^[0-9]$") + [ "$1" = "$grepped" ] && return 0 || return 1 +} + +number() +{ + grepped=$(echo "$1" | grep -E "^[1-9][0-9]+$") + [ "$1" = "$grepped" ] && return 0 || return 1 +} + +alph() +{ + grepped=$(echo "$1" | grep -E "^[a-zA-Z0-9]+$") + [ "$1" = "$grepped" ] && return 0 || return 1 +} + +while IFS='' read -r str; do + if [ -z "$str" ]; then + echo it is empty + continue + elif letters "$str"; then + echo "it is a word" + elif number "$str"; then + echo "it is a number" + elif digit "$str"; then + echo "it is a digit" + elif empty "$str"; then + echo "it is empty" + elif alph "$str"; then + echo "it is an alphanum" + else + echo "it is too complicated" + exit + fi +done diff --git a/rushs/evalexpr/array_max_min/array_max_min.c b/rushs/evalexpr/array_max_min/array_max_min.c new file mode 100644 index 0000000..8b2d3a5 --- /dev/null +++ b/rushs/evalexpr/array_max_min/array_max_min.c @@ -0,0 +1,23 @@ +#include <stddef.h> +#include <stdio.h> + +void array_max_min(int tab[], size_t len, int *max, int *min) +{ + if (tab && len) + { + *min = tab[0]; + *max = tab[0]; + + for (size_t i = 0; i < len; i++) + { + if (tab[i] > *max) + { + *max = tab[i]; + } + else if (tab[i] < *min) + { + *min = tab[i]; + } + } + } +} diff --git a/rushs/evalexpr/ascii_carousel/rot_x.c b/rushs/evalexpr/ascii_carousel/rot_x.c new file mode 100644 index 0000000..667106d --- /dev/null +++ b/rushs/evalexpr/ascii_carousel/rot_x.c @@ -0,0 +1,26 @@ +#include <stddef.h> + +void rot_x(char *s, int x) +{ + if (s == NULL) + { + return; + } + + if (x < 0) + { + x = 26 + x; + } + + for (size_t i = 0; s[i]; i++) + { + if (s[i] >= 'a' && s[i] <= 'z') + { + s[i] = ((s[i] - 'a') + x) % 26 + 'a'; + } + else if (s[i] >= 'A' && s[i] <= 'Z') + { + s[i] = ((s[i] - 'A') + x) % 26 + 'A'; + } + } +} diff --git a/rushs/evalexpr/ascii_house/ascii_house.sh b/rushs/evalexpr/ascii_house/ascii_house.sh new file mode 100755 index 0000000..83d907e --- /dev/null +++ b/rushs/evalexpr/ascii_house/ascii_house.sh @@ -0,0 +1,9 @@ +#!/bin/sh + + +echo ' /\' +echo ' / \' +echo -n "/____\\ \`" && echo "'\`" +echo -n "| | \`" && echo "'''\`" +echo "| | \`|\`" +echo '|_/\_|___|__' diff --git a/rushs/evalexpr/assignment_operator/assignment_operator.c b/rushs/evalexpr/assignment_operator/assignment_operator.c new file mode 100644 index 0000000..cae560f --- /dev/null +++ b/rushs/evalexpr/assignment_operator/assignment_operator.c @@ -0,0 +1,37 @@ +void plus_equal(int *a, int *b) +{ + if (!a || !b) + { + return; + } + *a = *a + *b; +} + +void minus_equal(int *a, int *b) +{ + if (!a || !b) + { + return; + } + *a = *a - *b; +} + +void mult_equal(int *a, int *b) +{ + if (!a || !b) + { + return; + } + *a = *a * *b; +} + +int div_equal(int *a, int *b) +{ + if (!a || !b || *b == 0) + { + return 0; + } + int res = *a % *b; + *a = *a / *b; + return res; +} diff --git a/rushs/evalexpr/binary_search_ptr/bsearch.c b/rushs/evalexpr/binary_search_ptr/bsearch.c new file mode 100644 index 0000000..bdc189c --- /dev/null +++ b/rushs/evalexpr/binary_search_ptr/bsearch.c @@ -0,0 +1,38 @@ +#include "bsearch.h" + +#include <stddef.h> + +int *binary_search(int *begin, int *end, int elt) +{ + if (begin == end) + { + return begin; + } + if (begin > end) + { + if (elt > *begin) + { + return begin + 1; + } + return begin; + } + + size_t m = (end - begin) / 2; + + if (begin[m] == elt) + { + return begin + m; + } + + if (begin[m] > elt) + { + return binary_search(begin, begin + m, elt); + } + + if (m == 0) + { + m++; + } + + return binary_search(begin + m, end, elt); +} diff --git a/rushs/evalexpr/binary_search_ptr/bsearch.h b/rushs/evalexpr/binary_search_ptr/bsearch.h new file mode 100644 index 0000000..e011744 --- /dev/null +++ b/rushs/evalexpr/binary_search_ptr/bsearch.h @@ -0,0 +1,16 @@ +#ifndef BSEARCH_H_ +#define BSEARCH_H_ + +/* +** Search `elt` in the memory range of [`begin` - `end`[. +** `begin` is a pointer to the first element. +** `end` is a pointer **AFTER** the last element. +** The elements in the range [`begin` - `end`[ are sorted in ascending order. +** If the range is empty, `begin` == `end`. +** `begin` and `end` can't be `NULL`. +** Returns a pointer to the element if found, or a pointer to the memory +** location where the element could be inserted to keep the array sorted. +*/ +int *binary_search(int *begin, int *end, int elt); + +#endif /* !BSEARCH_H_ */ diff --git a/rushs/evalexpr/binary_tree_dynamic/Makefile b/rushs/evalexpr/binary_tree_dynamic/Makefile new file mode 100644 index 0000000..7fa9879 --- /dev/null +++ b/rushs/evalexpr/binary_tree_dynamic/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wvla -Wextra -std=c99 -pedantic + +SRC = binary_tree.c binary_tree_print.c +OBJ = $(SRC:.c=.o) + +.PHONY: library clean + +library: $(OBJ) + ar csr libbinary_tree.a $(OBJ) + +$(OBJ): $(SRC) + +clean: + $(RM) libbinary_tree.a $(OBJ) diff --git a/rushs/evalexpr/binary_tree_dynamic/binary_tree.c b/rushs/evalexpr/binary_tree_dynamic/binary_tree.c new file mode 100644 index 0000000..6d99e99 --- /dev/null +++ b/rushs/evalexpr/binary_tree_dynamic/binary_tree.c @@ -0,0 +1,95 @@ +#include "binary_tree.h" + +#include <stddef.h> +#include <stdio.h> + +int size(const struct binary_tree *tree) +{ + if (tree == NULL) + return 0; + + return 1 + size(tree->left) + size(tree->right); +} + +static int max(int a, int b) +{ + if (a > b) + return a; + return b; +} + +int height(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return -1; + } + + return 1 + max(height(tree->left), height(tree->right)); +} + +int is_perfect(const struct binary_tree *tree) +{ + if (tree == NULL) + return 1; + return height(tree->left) == height(tree->right) && is_perfect(tree->right) + && is_perfect(tree->right); +} + +int is_complete(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return 1; + } + + int hg = height(tree->left); + int hd = height(tree->right); + + if (hg - hd != 0 && hg - hd != 1) + { + return 0; + } + + return is_complete(tree->left) && is_complete(tree->right); +} + +int is_degenerate(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return 1; + } + + if (tree->left && tree->right) + { + return 0; + } + return is_degenerate(tree->left) && is_degenerate(tree->right); +} + +int is_full(const struct binary_tree *tree) +{ + if (tree == NULL) + return 1; + if ((tree->left && !tree->right) || (!tree->left && tree->right)) + return 0; + return is_full(tree->right) && is_full(tree->left); +} + +static int is_bzt(const struct binary_tree *tree, int min, int max) +{ + if (tree == NULL) + return 1; + if (tree->data > max || tree->data <= min) + return 0; + return is_bzt(tree->left, min, tree->data) + && is_bzt(tree->right, tree->data, max); +} + +int is_bst(const struct binary_tree *tree) +{ + if (tree == NULL) + return 1; + return is_bzt(tree, -2147483647, 2147483647); +} diff --git a/rushs/evalexpr/binary_tree_dynamic/binary_tree.h b/rushs/evalexpr/binary_tree_dynamic/binary_tree.h new file mode 100644 index 0000000..a08e4ef --- /dev/null +++ b/rushs/evalexpr/binary_tree_dynamic/binary_tree.h @@ -0,0 +1,22 @@ +#ifndef BINARY_TREE_H +#define BINARY_TREE_H + +struct binary_tree +{ + int data; + struct binary_tree *left; + struct binary_tree *right; +}; + +int size(const struct binary_tree *tree); +int height(const struct binary_tree *tree); +void dfs_print_prefix(const struct binary_tree *tree); +void dfs_print_infix(const struct binary_tree *tree); +void dfs_print_postfix(const struct binary_tree *tree); +int is_perfect(const struct binary_tree *tree); +int is_complete(const struct binary_tree *tree); +int is_degenerate(const struct binary_tree *tree); +int is_full(const struct binary_tree *tree); +int is_bst(const struct binary_tree *tree); + +#endif /* !BINARY_TREE_H */ diff --git a/rushs/evalexpr/binary_tree_dynamic/binary_tree_print.c b/rushs/evalexpr/binary_tree_dynamic/binary_tree_print.c new file mode 100644 index 0000000..bce0f77 --- /dev/null +++ b/rushs/evalexpr/binary_tree_dynamic/binary_tree_print.c @@ -0,0 +1,40 @@ +#include <stddef.h> +#include <stdio.h> + +#include "binary_tree.h" + +void dfs_print_prefix(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return; + } + + printf("%d ", tree->data); + dfs_print_prefix(tree->left); + dfs_print_prefix(tree->right); +} + +void dfs_print_infix(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return; + } + + dfs_print_infix(tree->left); + printf("%d ", tree->data); + dfs_print_infix(tree->right); +} + +void dfs_print_postfix(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return; + } + + dfs_print_postfix(tree->left); + dfs_print_postfix(tree->right); + printf("%d ", tree->data); +} diff --git a/rushs/evalexpr/bit_rotation/rol.c b/rushs/evalexpr/bit_rotation/rol.c new file mode 100644 index 0000000..151ebb5 --- /dev/null +++ b/rushs/evalexpr/bit_rotation/rol.c @@ -0,0 +1,5 @@ +unsigned char rol(unsigned char value, unsigned char roll) +{ + roll %= sizeof(unsigned char) * 8; + return (value << roll) | (value >> (8 * sizeof(unsigned char) - roll)); +} diff --git a/rushs/evalexpr/bubble_sort/bubble_sort.c b/rushs/evalexpr/bubble_sort/bubble_sort.c new file mode 100644 index 0000000..13d2ba3 --- /dev/null +++ b/rushs/evalexpr/bubble_sort/bubble_sort.c @@ -0,0 +1,25 @@ +#include "bubble_sort.h" + +void bubble_sort(int array[], size_t size) +{ + if (!array || size == 0) + { + return; + } + + int mod; + do + { + mod = 0; + for (size_t i = 0; i < size - 1; i++) + { + if (array[i] > array[i + 1]) + { + mod = 1; + int tmp = array[i]; + array[i] = array[i + 1]; + array[i + 1] = tmp; + } + } + } while (mod); +} diff --git a/rushs/evalexpr/bubble_sort/bubble_sort.h b/rushs/evalexpr/bubble_sort/bubble_sort.h new file mode 100644 index 0000000..a33d531 --- /dev/null +++ b/rushs/evalexpr/bubble_sort/bubble_sort.h @@ -0,0 +1,8 @@ +#ifndef BUBBLE_SORT_H +#define BUBBLE_SORT_H + +#include <stddef.h> + +void bubble_sort(int array[], size_t size); + +#endif /* !BUBBLE_SORT_H */ diff --git a/rushs/evalexpr/check_alphabet/check_alphabet.c b/rushs/evalexpr/check_alphabet/check_alphabet.c new file mode 100644 index 0000000..fc540b4 --- /dev/null +++ b/rushs/evalexpr/check_alphabet/check_alphabet.c @@ -0,0 +1,25 @@ +#include "check_alphabet.h" + +#include <stddef.h> + +int check_alphabet(const char *str, const char *alphabet) +{ + if (alphabet == NULL || *alphabet == '\0') + { + return 1; + } + + for (int i = 0; alphabet[i]; i++) + { + int j; + for (j = 0; str[j] && str[j] != alphabet[i]; j++) + { + continue; + } + if (str[j] == '\0') + { + return 0; + } + } + return 1; +} diff --git a/rushs/evalexpr/check_alphabet/check_alphabet.h b/rushs/evalexpr/check_alphabet/check_alphabet.h new file mode 100644 index 0000000..667a20f --- /dev/null +++ b/rushs/evalexpr/check_alphabet/check_alphabet.h @@ -0,0 +1,6 @@ +#ifndef CHECK_ALPHABET_H +#define CHECK_ALPHABET_H + +int check_alphabet(const char *str, const char *alphabet); + +#endif /* !CHECK_ALPHABET_H */ diff --git a/rushs/evalexpr/clang-format/.clang-format b/rushs/evalexpr/clang-format/.clang-format new file mode 100644 index 0000000..7ed8115 --- /dev/null +++ b/rushs/evalexpr/clang-format/.clang-format @@ -0,0 +1,79 @@ +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: false +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterEnum: true + AfterClass: true + AfterControlStatement: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeComma +BreakStringLiterals: true +ColumnLimit: 80 +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +FixNamespaceComments: true +ForEachMacros: ['ILIST_FOREACH', 'ILIST_FOREACH_ENTRY'] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '<.*>' + Priority: 1 + - Regex: '.*' + Priority: 2 +IndentCaseLabels: false +IndentPPDirectives: AfterHash +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +NamespaceIndentation: All +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/rushs/evalexpr/clang-format/zaza.c b/rushs/evalexpr/clang-format/zaza.c new file mode 100644 index 0000000..a6eec9a --- /dev/null +++ b/rushs/evalexpr/clang-format/zaza.c @@ -0,0 +1,78 @@ +#include <stdio.h> +#include <stdlib.h> +#define ZAZA_SIZE 4 + +static char get_zaza_char(size_t id) +{ + const int zaza[ZAZA_SIZE] = { + 10 * 10 + 2 * 10 + 2 * 10 / 10, + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + - (1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1), + 122, + (38943 * 43 - 84393 / 34583 + + ) % 10 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + }; + switch (id * 2 + 4 - 2 + id * 4 - 2 + -5 * id) + + { + case (0): + return (zaza[0]); + case (1000 - 100 - 4 * 100 + 10 * 100 - 14 * 100 - (10 * 10 - 1)): + return (zaza[1]); + case (1 << 11 >> 3 << 5 >> 2 << 1 << 1 << 1 >> 1 >> 1 >> 1 << 5 >> 4 << 1 + >> 1 >> 2 >> 9): + return zaza[2]; + case (3 ^ 100) - (100 ^ 100) - (99 - 99) - (98 - 98) - (97 - 97) - (96 - 96) + - (95 - 95) - (94 - 94) - (93 - 93) - (92 - 92) - (91 - 91) - (90 - 90) + - (89 - 89) - (88 - 88) - (87 - 87) - (86 - 86) - (85 - 85) - (84 - 84) + - (83 - 83) - (82 - 82) - (81 - 81) - (80 - 80) - (79 - 79) - (78 - 78) + - (77 - 77) - (76 - 76) - (75 - 75) - (74 - 74) - (73 - 73) - (72 - 72) + - (71 - 71) - (70 - 70) - + + (69 - 69) - (68 - 68) - (67 - 67) - (66 - 66) - (65 - 65) - (64 - 64) + - (63 - 63) - (62 - 62) - (61 - 61) - (60 - 60) - (59 - 59) - (58 - 58) + - (57 - 57) - (56 - 56) - (55 - 55) - (54 - 54) - (53 - 53) - (52 - 52) + - (51 - 51) - 100 - (50 - 50) - (49 - 49) - (48 - 48) - (47 - 47) + - (46 - 46) - (45 - 45) - (44 - 44) - (43 - 43) - (42 - 42) - (41 - 41) + - (40 - 40) - (39 - 39) - (38 - 38) - (37 - 37) + + - (36 - 36) - (35 - 35) - (34 - 34) - (33 - 33) - (32 - 32) - (31 - 31) + - (30 - 30) - (29 - 29) - (28 - 28) - (27 - 27) - (26 - 26) - (25 - 25) + - (24 - 24) - (23 - 23) - (22 - 22) - (21 - 21) - (20 - 20) - (19 - 19) + - (18 - 18) - (17 - 17) - (16 - 16) - (15 - 15) - (14 - 14) - (13 - 13) + - (12 - 12) - (11 - 11) - (10 - 10) - (9 - 9) - (8 - 8) - (7 - 7) + - (6 - 6) - (5 - 5) - (4 - 4) - (3 - 3) - (2 - 2) - (1 - 1): + return (zaza[3]); + default: + return (0); + } +} +int main(void) +{ + for (size_t i = 0; i < ZAZA_SIZE; i += (i % 2 == 2 - 2) ? 1 % 2 : 1 % 2) + { + putchar(get_zaza_char(i)); + } + putchar('\n'); + return (0); +} diff --git a/rushs/evalexpr/create_files/create_files.sh b/rushs/evalexpr/create_files/create_files.sh new file mode 100755 index 0000000..28dba00 --- /dev/null +++ b/rushs/evalexpr/create_files/create_files.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +touch ' ' +chmod 644 ' ' + +touch '\' +chmod 644 '\' + +touch -- -- +chmod 644 -- -- + +touch '|' +chmod 644 '|' + +touch '"' +chmod 644 '"' + +touch "'" +chmod 644 "'" + +touch -- --\$i*\'\"\\ +chmod 644 -- --\$i*\'\"\\ + +touch '# Exams are fun!' +chmod 644 '# Exams are fun!' + +touch ";\`kill -9 0\`" +chmod 644 ";\`kill -9 0\`" + +path="1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/41/42/43/44/45/46/47/48/49/50" + +mkdir -p "$path" +touch $path/farfaraway +chmod 644 $path/farfaraway diff --git a/rushs/evalexpr/cut_csv/test.csv b/rushs/evalexpr/cut_csv/test.csv new file mode 100644 index 0000000..d88282b --- /dev/null +++ b/rushs/evalexpr/cut_csv/test.csv @@ -0,0 +1,15 @@ +James;Lebron;LABron;Lakers; +Davis;Anthony;Unibrow;Pelicans; +Mitchell;Donovan;Spida;Jazz; +Harden;James;TheBeard;Rockets; +Cousins;DeMarcus;Boogie;Wariors; +Embiid;Joel;TheProcess;76Sixers; +Bryant;Kobe;BlackMamba;Lakers; +Jordan;Michael;AirJordan;Bulls; +Johnson;Earvin;Magic;Lakers; +Howard;Dwight;Superman;Wizards; +Westbrook;Russel;MrTripleDouble;Thunder; +Durant;Kevin;KD;Wariors; +George;Paul;PG-13;Thunder; +Leonard;Kawhi;TheKlaw;Raptors; +Irving;Kyrie;UncleDrew;Celtics; diff --git a/rushs/evalexpr/cut_csv/with_cut.sh b/rushs/evalexpr/cut_csv/with_cut.sh new file mode 100755 index 0000000..9618f00 --- /dev/null +++ b/rushs/evalexpr/cut_csv/with_cut.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +[ $# -ne 2 ] && exit 1 + +if ! [ -f "$1" ]; then + exit 1 +fi + +if ! [ "$2" -eq "$2" ] 2> /dev/null; then + exit 1 +fi + +[ "$2" -lt 0 ] && exit 1 + +if [ "$2" -gt "$(wc -l < "$1")" ]; then + exit 1 +fi + +line=$(head --lines="$2" "$1" 2> /dev/null | tail -n 1 | cut -d ';' -f 2-3 || exit 1) +c1=$(echo "$line" | cut -d ';' -f 1) +c2=$(echo "$line" | cut -d ';' -f 2) + +echo "$c1 is $c2" diff --git a/rushs/evalexpr/cut_csv/with_sed.sh b/rushs/evalexpr/cut_csv/with_sed.sh new file mode 100755 index 0000000..fb5e1f8 --- /dev/null +++ b/rushs/evalexpr/cut_csv/with_sed.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +[ $# -ne 2 ] && exit 1 + +if ! [ -f "$1" ]; then + exit 1 +fi + +if ! [ "$2" -eq "$2" ] 2>/dev/null; then + exit 1 +fi + +[ "$2" -lt 0 ] && exit 1 + +if [ "$2" -gt $(wc -l < "$1") ]; then + exit 1 +fi + +i=1 + +while IFS= read -r line; do + [ "$i" -eq "$2" ] && echo "$line" | sed 's/^.*;\(.*\);\(.*\);.*;$/\1 is \2/' + i=$(($i + 1)) +done < "$1" diff --git a/rushs/evalexpr/digit/digit.c b/rushs/evalexpr/digit/digit.c new file mode 100644 index 0000000..5646b13 --- /dev/null +++ b/rushs/evalexpr/digit/digit.c @@ -0,0 +1,13 @@ +unsigned int digit(int n, int k) +{ + if (n <= 0 || k <= 0) + { + return 0; + } + + for (int i = 0; i < k - 1; i++) + { + n /= 10; + } + return n % 10; +} diff --git a/rushs/evalexpr/display_square/display_square.c b/rushs/evalexpr/display_square/display_square.c new file mode 100644 index 0000000..9e834d7 --- /dev/null +++ b/rushs/evalexpr/display_square/display_square.c @@ -0,0 +1,44 @@ +#include <stdio.h> + +void display_square(int width) +{ + if (width <= 0) + { + return; + } + + if (width % 2 == 0) + { + width++; + } + + if (width == 1) + { + putchar('*'); + putchar('\n'); + return; + } + + for (int i = 0; i < width; i++) + { + putchar('*'); + } + putchar('\n'); + + for (int i = 0; i < ((width - 3) / 2); i++) + { + putchar('*'); + for (int j = 0; j < width - 2; j++) + { + putchar(' '); + } + putchar('*'); + putchar('\n'); + } + + for (int i = 0; i < width; i++) + { + putchar('*'); + } + putchar('\n'); +} diff --git a/rushs/evalexpr/dlist/Makefile b/rushs/evalexpr/dlist/Makefile new file mode 100644 index 0000000..1251967 --- /dev/null +++ b/rushs/evalexpr/dlist/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla + +SRC = dlist-1.c dlist-2.c dlist-3.c dlist-4.c +OBJ = $(SRC:.c=.o) + +.PHONY: library clean + +library: $(OBJ) + ar csr libdlist.a $(OBJ) + +clean: $(OBJ) + $(RM) *.a $(OBJ) + +$(OBJ): $(SRC) diff --git a/rushs/evalexpr/dlist/dlist-1.c b/rushs/evalexpr/dlist/dlist-1.c new file mode 100644 index 0000000..443ebca --- /dev/null +++ b/rushs/evalexpr/dlist/dlist-1.c @@ -0,0 +1,78 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "dlist.h" + +struct dlist *dlist_init(void) +{ + struct dlist *res = malloc(sizeof(struct dlist)); + if (res == NULL) + return NULL; + + res->size = 0; + res->head = NULL; + res->tail = NULL; + return res; +} + +int dlist_push_front(struct dlist *list, int element) +{ + if (element < 0) + return 0; + struct dlist_item *new = malloc(sizeof(struct dlist_item)); + if (new == NULL) + return 0; + + new->data = element; + new->next = list->head; + new->prev = NULL; + + if (list->size == 0) + list->tail = new; + else + list->head->prev = new; + + list->head = new; + list->size++; + + return 1; +} + +void dlist_print(const struct dlist *list) +{ + if (list->size == 0) + return; + + for (struct dlist_item *i = list->head; i != list->tail; i = i->next) + { + printf("%d\n", i->data); + } + printf("%d\n", list->tail->data); +} + +int dlist_push_back(struct dlist *list, int element) +{ + if (element < 0) + return 0; + struct dlist_item *new = malloc(sizeof(struct dlist_item)); + if (new == NULL) + return 0; + + new->data = element; + new->prev = list->tail; + new->next = NULL; + + if (list->size == 0) + list->head = new; + else + list->tail->next = new; + list->tail = new; + list->size++; + + return 1; +} + +size_t dlist_size(const struct dlist *list) +{ + return list->size; +} diff --git a/rushs/evalexpr/dlist/dlist-2.c b/rushs/evalexpr/dlist/dlist-2.c new file mode 100644 index 0000000..5ccdaa3 --- /dev/null +++ b/rushs/evalexpr/dlist/dlist-2.c @@ -0,0 +1,113 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "dlist.h" + +int dlist_get(const struct dlist *list, size_t index) +{ + if (index >= list->size) + return -1; + + struct dlist_item *i; + for (i = list->head; index; index--, i = i->next) + { + continue; + } + + return i->data; +} + +int dlist_insert_at(struct dlist *list, int element, size_t index) +{ + if (index > list->size || element < 0) + return 0; + else if (index == list->size) + dlist_push_back(list, element); + else if (index == 0) + dlist_push_front(list, element); + else + { + struct dlist_item *new = malloc(sizeof(struct dlist_item)); + if (new == NULL) + return 0; + new->data = element; + + struct dlist_item *i; + for (i = list->head; index - 1; index--, i = i->next) + continue; + new->next = i->next; + i->next->prev = new; + i->next = new; + new->prev = i; + list->size++; + } + return 1; +} + +int dlist_find(const struct dlist *list, int element) +{ + int index = 0; + struct dlist_item *i; + for (i = list->head; i && i->data != element; index++, i = i->next) + continue; + if (!i) + return -1; + return index; +} + +int dlist_remove_at(struct dlist *list, size_t index) +{ + if (index >= list->size) + return -1; + int res; + struct dlist_item *item; + if (list->size == 1) + { + item = list->head; + res = list->head->data; + list->head = NULL; + list->tail = NULL; + } + else if (index == 0) + { + item = list->head; + res = item->data; + item->next->prev = NULL; + list->head = item->next; + } + else if (index == list->size - 1) + { + item = list->tail; + res = item->data; + item->prev->next = NULL; + list->tail = item->prev; + } + else + { + for (item = list->head; index; index--, item = item->next) + continue; + + res = item->data; + item->prev->next = item->next; + item->next->prev = item->prev; + } + + free(item); + list->size--; + return res; +} + +void dlist_clear(struct dlist *list) +{ + if (list->size == 0) + return; + for (struct dlist_item *i = list->head; i;) + { + struct dlist_item *tmp = i->next; + free(i); + i = tmp; + } + list->size = 0; + list->head = NULL; + list->tail = NULL; +} diff --git a/rushs/evalexpr/dlist/dlist-3.c b/rushs/evalexpr/dlist/dlist-3.c new file mode 100644 index 0000000..22b4b52 --- /dev/null +++ b/rushs/evalexpr/dlist/dlist-3.c @@ -0,0 +1,83 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "dlist.h" + +void dlist_map_square(struct dlist *list) +{ + for (struct dlist_item *i = list->head; i; i = i->next) + { + i->data *= i->data; + } +} + +void dlist_reverse(struct dlist *list) +{ + struct dlist_item *tmp; + for (struct dlist_item *i = list->head; i; i = i->prev) + { + tmp = i->next; + i->next = i->prev; + i->prev = tmp; + } + tmp = list->tail; + list->tail = list->head; + list->head = tmp; +} + +struct dlist *dlist_split_at(struct dlist *list, size_t index) +{ + if (list->size == 0) + return dlist_init(); + if (index >= list->size) + { + return NULL; + } + + struct dlist *new = dlist_init(); + if (new == NULL) + return NULL; + new->size = list->size - index; + list->size = index; + + struct dlist_item *i; + for (i = list->head; index; index--, i = i->next) + { + continue; + } + + new->head = i; + new->tail = list->tail; + list->tail = i->prev; + if (i->prev) + { + i->prev->next = NULL; + } + else + { + list->head = NULL; + } + i->prev = NULL; + return new; +} + +void dlist_concat(struct dlist *list1, struct dlist *list2) +{ + if (list2->head == NULL) + return; + if (list1->tail == NULL) + { + list1->head = list2->head; + list1->tail = list2->tail; + list1->size = list2->size; + return; + } + + list1->tail->next = list2->head; + list2->head->prev = list1->tail; + list1->tail = list2->tail; + list1->size += list2->size; + list2->size = 0; + list2->head = NULL; + list2->tail = NULL; +} diff --git a/rushs/evalexpr/dlist/dlist-4.c b/rushs/evalexpr/dlist/dlist-4.c new file mode 100644 index 0000000..9ed7aaa --- /dev/null +++ b/rushs/evalexpr/dlist/dlist-4.c @@ -0,0 +1,97 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "dlist.h" + +size_t max(size_t a, size_t b) +{ + if (a >= b) + { + return a; + } + return b; +} + +size_t min(size_t a, size_t b) +{ + if (a <= b) + { + return a; + } + return b; +} + +size_t min_3(size_t a, size_t b, size_t c) +{ + if (a <= b) + { + if (a <= c) + { + return a; + } + return c; + } + else + { + if (b <= c) + { + return b; + } + return c; + } +} + +size_t my_strlen(const int *s) +{ + size_t i; + for (i = 0; s[i] != -1; i++) + { + continue; + } + return i; +} + +size_t levenshtein(const int *s1, const int *s2) +{ + size_t l1 = my_strlen(s1); + size_t l2 = my_strlen(s2); + if (min(l1, l2) == 0) + { + return max(l1, l2); + } + + if (s1[0] == s2[0]) + { + return levenshtein(s1 + 1, s2 + 1); + } + + size_t lev1 = levenshtein(s1 + 1, s2); + size_t lev2 = levenshtein(s1, s2 + 1); + size_t lev3 = levenshtein(s1 + 1, s2 + 1); + + return 1 + min_3(lev1, lev2, lev3); +} + +int *to_str(const struct dlist *l) +{ + int *res = malloc((l->size + 1) * sizeof(int)); + res[l->size] = -1; + size_t j = 0; + for (struct dlist_item *i = l->head; i; i = i->next, j++) + { + res[j] = i->data; + } + return res; +} + +unsigned int dlist_levenshtein(const struct dlist *list1, + const struct dlist *list2) +{ + int *l1 = to_str(list1); + int *l2 = to_str(list2); + + unsigned int res = levenshtein(l1, l2); + free(l1); + free(l2); + return res; +} diff --git a/rushs/evalexpr/dlist/dlist.h b/rushs/evalexpr/dlist/dlist.h new file mode 100644 index 0000000..97cde1a --- /dev/null +++ b/rushs/evalexpr/dlist/dlist.h @@ -0,0 +1,44 @@ +#ifndef DLIST_H +#define DLIST_H + +#include <stddef.h> + +struct dlist_item +{ + int data; + struct dlist_item *next; + struct dlist_item *prev; +}; + +struct dlist +{ + size_t size; + struct dlist_item *head; + struct dlist_item *tail; +}; + +// Threshold 1 +struct dlist *dlist_init(void); +int dlist_push_front(struct dlist *list, int element); +void dlist_print(const struct dlist *list); +int dlist_push_back(struct dlist *list, int element); +size_t dlist_size(const struct dlist *list); + +// Threshold 2 +int dlist_get(const struct dlist *list, size_t index); +int dlist_insert_at(struct dlist *list, int element, size_t index); +int dlist_find(const struct dlist *list, int element); +int dlist_remove_at(struct dlist *list, size_t index); +void dlist_clear(struct dlist *list); + +// Threshold 3 +void dlist_map_square(struct dlist *list); +void dlist_reverse(struct dlist *list); +struct dlist *dlist_split_at(struct dlist *list, size_t index); +void dlist_concat(struct dlist *list1, struct dlist *list2); + +// Threshold 4 +unsigned int dlist_levenshtein(const struct dlist *list1, + const struct dlist *list2); + +#endif /* !DLIST_H */ diff --git a/rushs/evalexpr/element_count/element_count.c b/rushs/evalexpr/element_count/element_count.c new file mode 100644 index 0000000..cec47ae --- /dev/null +++ b/rushs/evalexpr/element_count/element_count.c @@ -0,0 +1,10 @@ +#include "element_count.h" + +size_t element_count(int *begin, int *end) +{ + if (!begin || !end || begin >= end) + { + return 0; + } + return end - begin; +} diff --git a/rushs/evalexpr/element_count/element_count.h b/rushs/evalexpr/element_count/element_count.h new file mode 100644 index 0000000..57412ed --- /dev/null +++ b/rushs/evalexpr/element_count/element_count.h @@ -0,0 +1,8 @@ +#ifndef ELEMENT_COUNT_H +#define ELEMENT_COUNT_H + +#include <stddef.h> + +size_t element_count(int *begin, int *end); + +#endif /* !ELEMENT_COUNT_H */ diff --git a/rushs/evalexpr/evalexpr/Makefile b/rushs/evalexpr/evalexpr/Makefile new file mode 100644 index 0000000..280f19c --- /dev/null +++ b/rushs/evalexpr/evalexpr/Makefile @@ -0,0 +1,23 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wextra -pedantic -std=c99 -Wvla +AFLAGS = -fsanitize=address + +SRC=src/stack.c src/evalrpn.c src/shunting_yard.c src/fifo_access.c src/fifo_setup_destroy.c src/evalexpr.c +SRC_TEST=tests/unit_tests.c +#OBJ=src/stack.o src/evalrpn.o +OBJ=$(SRC:.c=.o) +#OBJ_TEST=$(SRC_TEST:.c=.o) + +all: $(OBJ) + $(CC) -o evalexpr $(OBJ) + +$(OBJ): $(SRC) + +check: #$(OBJ) $(OBJ_TEST) +# $(CC) $(CFLAGS) -o evaltest $(OBJ) $(OBJ_TEST) -lcriterion + tests/tests.sh + +.PHONY: clean + +clean: + rm $(OBJ) evalexpr diff --git a/rushs/evalexpr/evalexpr/src/evalexpr.c b/rushs/evalexpr/evalexpr/src/evalexpr.c new file mode 100644 index 0000000..5012355 --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/evalexpr.c @@ -0,0 +1,93 @@ +#include "evalexpr.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define BUFFER_SIZE 10 + +char *get_input(void) +{ + size_t r; + char buf[BUFFER_SIZE]; + size_t size = 0; + char *expr = malloc(size * sizeof(char) + 1); + if (expr == NULL) + return NULL; + expr[0] = '\0'; + do + { + r = fread(buf, sizeof(char), BUFFER_SIZE - 1, stdin); + if (r != 0) + { + buf[r] = '\0'; + size += r; + char *tmp = realloc(expr, size * sizeof(char) + 1); + if (tmp == NULL) + { + free(expr); + return NULL; + } + expr = tmp; + strcat(expr, buf); + } + } while (r != 0); + if (size == 0) + { + free(expr); + return NULL; + } + if (expr[size - 1] == '\n') + expr[size - 1] = '\0'; + return expr; +} + +void cleanup(char *expr, char *rpn) +{ + free(expr); + free(rpn); +} + +int main(int argc, char **argv) +{ + if ((argc == 2 && strcmp(argv[1], "-rpn") != 0) || (argc > 2)) + return 4; + char *expr = get_input(); + if (expr == NULL) + return 4; + if (argc == 1) + { + char *rpn; + int e = shunting_yard(expr, &rpn); + if (e != 0) + return e; + // call shunting yard + int retval; + e = evalrpn(rpn, &retval); + if (e != 0) + { + cleanup(expr, rpn); + return e; + } + // FREE RPN + printf("%d\n", retval); + cleanup(expr, rpn); + // return + return 0; + } + + if (argc == 2 && strcmp(argv[1], "-rpn") == 0) + { + // call rpn eval + int retval; + int e = evalrpn(expr, &retval); + printf("%d\n", retval); + // return + free(expr); + if (e != 0) + return e; + return 0; + } + + return 4; +} diff --git a/rushs/evalexpr/evalexpr/src/evalexpr.h b/rushs/evalexpr/evalexpr/src/evalexpr.h new file mode 100644 index 0000000..d440ae1 --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/evalexpr.h @@ -0,0 +1,43 @@ +#ifndef EVALEXPR_H +#define EVALEXPR_H + +#include <stddef.h> + +#include "fifo.h" +#include "stack.h" +#include "stack_struct.h" + +enum token_type +{ + NUMBER = 0, + SUB = 1, + ADD = 1, + MOD = 2, + DIV = 2, + MUL = 2, + EXP = 3, + UN_PLUS = 4, + UN_MINUS = 4, + PAR_LEFT = 5, + PAR_RIGHT = 5, + WRONG_TOKEN = -1, +}; + +struct token +{ + enum token_type type; + int value; +}; + +// evalrpn +int parse_number(const char *expr, size_t *offset); +int get_operands(struct stack **s, int *op1, int *op2); +int my_pow(int a, int b); +int evalrpn(const char *expr, int *retval); + +// shunting yard +int opcmp(struct token *op1, struct token *op2); +enum token_type get_type(char op); +int shunting_yard(const char *expr, char **rpn); + +#endif /* ! EVALEXPR_H */ diff --git a/rushs/evalexpr/evalexpr/src/evalrpn.c b/rushs/evalexpr/evalexpr/src/evalrpn.c new file mode 100644 index 0000000..db493eb --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/evalrpn.c @@ -0,0 +1,145 @@ +#include <ctype.h> + +#include "evalexpr.h" + +int parse_number(const char *expr, size_t *offset) +{ + for (*offset = 0; + expr[*offset] && expr[*offset] >= '0' && expr[*offset] <= '9'; + (*offset)++) + { + continue; + } + (*offset)--; + + int res = 0; + int pow = 1; + for (size_t n = 0; n <= *offset; n++, pow *= 10) + { + res += (expr[*offset - n] - '0') * pow; + } + + return res; +} + +int get_operands(struct stack **s, int *op1, int *op2) +{ + if (*s == NULL) + { + return 2; + } + *op1 = stack_peek(*s); + *s = stack_pop(*s); + if (*s == NULL) + { + return 2; + } + *op2 = stack_peek(*s); + *s = stack_pop(*s); + return 0; +} + +// Computes a to the bth +int my_pow(int a, int b) +{ + if (b == 0) + { + return 1; + } + if (a == 0) + { + return 0; + } + + int res = 1; + int c = b / 2; + while (c != 0) + { + res *= a * a; + c /= 2; + } + if (b % 2 != 0) + res *= a; + return res; +} + +int dispatch(const char c, struct stack **s, int op1, int op2) +{ + switch (c) + { + case '*': + *s = stack_push(*s, op1 * op2); + break; + case '+': + *s = stack_push(*s, op1 + op2); + break; + case '-': + *s = stack_push(*s, op2 - op1); + break; + case '/': + if (op1 == 0) + { + return 3; + } + *s = stack_push(*s, op2 / op1); + break; + case '%': + if (op1 == 0) + { + return 3; + } + *s = stack_push(*s, op2 % op1); + break; + case '^': + if (op1 < 0) + { + return 3; + } + *s = stack_push(*s, my_pow(op2, op1)); + break; + default: + return 1; + } + return 0; +} + +int evalrpn(const char *expr, int *retval) +{ + struct stack *s = NULL; + + for (size_t i = 0; expr[i]; i++) + { + if (expr[i] >= '0' && expr[i] <= '9') + { + size_t offset; + int val = parse_number(expr + i, &offset); + s = stack_push(s, val); + i += offset; + } + else if (isspace(expr[i])) + continue; + else + { + int op1; + int op2; + if (get_operands(&s, &op1, &op2) == 2) + { + return 2; + } + + int d = dispatch(expr[i], &s, op1, op2); + if (d != 0) + { + return d; + } + } + } + + if (s == NULL) + { + return 0; + } + *retval = stack_peek(s); + s = stack_pop(s); + return (!s) ? 0 : 2; +} diff --git a/rushs/evalexpr/evalexpr/src/fifo.h b/rushs/evalexpr/evalexpr/src/fifo.h new file mode 100644 index 0000000..b330eac --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/fifo.h @@ -0,0 +1,29 @@ +#ifndef FIFO_H +#define FIFO_H + +#include <stddef.h> + +#include "evalexpr.h" + +struct list +{ + struct token *data; + struct list *next; +}; + +struct fifo +{ + struct list *head; + struct list *tail; + size_t size; +}; + +struct fifo *fifo_init(void); +size_t fifo_size(struct fifo *fifo); +void fifo_push(struct fifo *fifo, struct token *elt); +struct token *fifo_head(struct fifo *fifo); +void fifo_pop(struct fifo *fifo); +void fifo_clear(struct fifo *fifo); +void fifo_destroy(struct fifo *fifo); + +#endif /* !FIFO_H */ diff --git a/rushs/evalexpr/evalexpr/src/fifo_access.c b/rushs/evalexpr/evalexpr/src/fifo_access.c new file mode 100644 index 0000000..1986a09 --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/fifo_access.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "fifo.h" + +size_t fifo_size(struct fifo *fifo) +{ + return fifo->size; +} + +void fifo_push(struct fifo *fifo, struct token *elt) +{ + struct list *new = malloc(sizeof(struct list)); + if (new == NULL) + { + return; + } + new->data = elt; + + if (fifo_size(fifo) == 0) + { + fifo->head = new; + } + new->next = NULL; + if (fifo_size(fifo) != 0) + { + fifo->tail->next = new; + } + fifo->tail = new; + + fifo->size++; +} + +struct token *fifo_head(struct fifo *fifo) +{ + return fifo->head->data; +} + +void fifo_pop(struct fifo *fifo) +{ + if (fifo_size(fifo) == 0) + { + return; + } + if (fifo_size(fifo) == 1) + { + free(fifo->head->data); + free(fifo->head); + fifo->head = NULL; + fifo->tail = NULL; + fifo->size = 0; + return; + } + + struct list *tmp = fifo->head->next; + free(fifo->head->data); + free(fifo->head); + fifo->head = tmp; + + fifo->size--; +} diff --git a/rushs/evalexpr/evalexpr/src/fifo_setup_destroy.c b/rushs/evalexpr/evalexpr/src/fifo_setup_destroy.c new file mode 100644 index 0000000..0f99ad0 --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/fifo_setup_destroy.c @@ -0,0 +1,44 @@ +#include <stdlib.h> + +#include "fifo.h" + +struct fifo *fifo_init(void) +{ + struct fifo *f = malloc(sizeof(struct fifo)); + if (f == NULL) + { + return NULL; + } + + f->size = 0; + f->head = NULL; + f->tail = NULL; + + return f; +} + +void fifo_clear(struct fifo *fifo) +{ + for (struct list *l = fifo->head; l != fifo->tail;) + { + struct list *tmp = l->next; + free(l->data); + free(l); + l = tmp; + } + if (fifo->tail) + { + free(fifo->tail->data); + free(fifo->tail); + } + + fifo->head = NULL; + fifo->tail = NULL; + fifo->size = 0; +} + +void fifo_destroy(struct fifo *fifo) +{ + fifo_clear(fifo); + free(fifo); +} diff --git a/rushs/evalexpr/evalexpr/src/shunting_yard.c b/rushs/evalexpr/evalexpr/src/shunting_yard.c new file mode 100644 index 0000000..2db5fc8 --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/shunting_yard.c @@ -0,0 +1,199 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "evalexpr.h" + +enum assoc +{ + NONE, + RIGHT, + LEFT, +}; + +int opcmp(struct token *op1, struct token *op2) +{ + return op1->type - op2->type; +} + +enum assoc get_assoc(struct token *op) +{ + if (op->type == EXP) + { + return RIGHT; + } + return LEFT; +} + +enum token_type get_type(char op) +{ + switch (op) + { + case '*': + return MUL; + case '/': + return DIV; + case '-': + return SUB; + case '+': + return ADD; + case '%': + return MOD; + case '^': + return EXP; + case '(': + return PAR_LEFT; + case ')': + return PAR_RIGHT; + default: + return WRONG_TOKEN; + } +} + +char *fifo_to_expr(struct fifo *output, size_t size_offset) +{ + char *res = malloc((2 * fifo_size(output) + size_offset) * sizeof(char)); + if (!res) + { + fifo_destroy(output); + return NULL; + } + res[2 * fifo_size(output) + size_offset - 1] = '\0'; + size_t i = 0; + while (fifo_size(output) > 0) + { + if (fifo_head(output)->type == NUMBER) + { + i += sprintf(res + i, "%d", fifo_head(output)->value) - 1; + } + else + { + res[i] = fifo_head(output)->value; + } + fifo_pop(output); + i++; + if (fifo_size(output) != 0) + { + res[i] = ' '; + i++; + } + } + fifo_destroy(output); + return res; +} + +int handle_rpar(struct tstack **opstack, struct fifo *output, struct token **t) +{ + while (*opstack) + { + struct token *o2 = tstack_peek(*opstack); + if (o2->value == '(') + { + free(o2); + break; + } + *opstack = tstack_pop(*opstack); + fifo_push(output, o2); + } + if (*opstack == NULL) + { + free(*t); + fifo_destroy(output); + return 2; + } + free(*t); + *opstack = tstack_pop(*opstack); + return 0; +} + +int empty_opstack(struct tstack **opstack, struct fifo *output) +{ + while (*opstack) + { + struct token *t = tstack_peek(*opstack); + if (t->value == '(' || t->value == ')') + { + fifo_destroy(output); + return 1; + } + *opstack = tstack_pop(*opstack); + fifo_push(output, t); + } + return 0; +} + +void pop_ops(struct tstack **opstack, struct fifo *output, struct token *t) +{ + while (*opstack) + { + struct token *o2 = tstack_peek(*opstack); + if (!(o2->value != '(' + && (opcmp(t, o2) < 0 + || (opcmp(t, o2) == 0 && get_assoc(t) == LEFT)))) + { + break; + } + + *opstack = tstack_pop(*opstack); + fifo_push(output, o2); + } +} + +void handle_numbers(struct fifo *output, size_t *i, int *size_offset, + const char *expr) +{ + size_t offset; + int val = parse_number(expr + *i, &offset); + struct token *t = malloc(sizeof(struct token)); + t->type = NUMBER; + t->value = val; + fifo_push(output, t); + *i += offset; + *size_offset += offset; +} + +int shunting_yard(const char *expr, char **rpn) +{ + struct fifo *output = fifo_init(); + struct tstack *opstack = NULL; + int size_offset = 0; + for (size_t i = 0; expr[i]; i++) + { + if (expr[i] >= '0' && expr[i] <= '9') + { + handle_numbers(output, &i, &size_offset, expr); + } + else if (expr[i] != ' ') + { + struct token *t = malloc(sizeof(struct token)); + t->value = expr[i]; + if ((t->type = get_type(expr[i])) == WRONG_TOKEN) + { + free(t); + return 1; + } + if (t->value == '(') + { + opstack = tstack_push(opstack, t); + continue; + } + else if (t->value == ')') + { + if (handle_rpar(&opstack, output, &t) != 0) + return 2; + continue; + } + pop_ops(&opstack, output, t); + opstack = tstack_push(opstack, t); + } + } + + if (empty_opstack(&opstack, output) != 0) + { + return 1; + } + *rpn = fifo_to_expr(output, size_offset); + if (!*rpn) + return 4; + + return 0; +} diff --git a/rushs/evalexpr/evalexpr/src/stack.c b/rushs/evalexpr/evalexpr/src/stack.c new file mode 100644 index 0000000..14f659e --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/stack.c @@ -0,0 +1,57 @@ +#include "stack.h" + +#include <stdlib.h> + +struct stack *stack_push(struct stack *s, int e) +{ + struct stack *new = malloc(sizeof(struct stack)); + new->data = e; + new->next = NULL; + + new->next = s; + return new; +} + +struct stack *stack_pop(struct stack *s) +{ + if (s == NULL) + { + return NULL; + } + + struct stack *res = s->next; + free(s); + return res; +} + +int stack_peek(struct stack *s) +{ + return s->data; +} + +struct tstack *tstack_push(struct tstack *s, struct token *e) +{ + struct tstack *new = malloc(sizeof(struct tstack)); + new->token = e; + new->next = NULL; + + new->next = s; + return new; +} + +struct tstack *tstack_pop(struct tstack *s) +{ + if (s == NULL) + { + return NULL; + } + + struct tstack *res = s->next; + free(s); + return res; +} + +struct token *tstack_peek(struct tstack *s) +{ + return s->token; +} diff --git a/rushs/evalexpr/evalexpr/src/stack.h b/rushs/evalexpr/evalexpr/src/stack.h new file mode 100644 index 0000000..d08e465 --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/stack.h @@ -0,0 +1,20 @@ +#ifndef STACK_H +#define STACK_H + +#include "evalexpr.h" +#include "stack_struct.h" + +struct tstack +{ + struct token *token; + struct tstack *next; +}; + +struct stack *stack_push(struct stack *s, int e); +struct stack *stack_pop(struct stack *s); +int stack_peek(struct stack *s); + +struct tstack *tstack_push(struct tstack *s, struct token *e); +struct tstack *tstack_pop(struct tstack *s); +struct token *tstack_peek(struct tstack *s); +#endif /* !STACK_H */ diff --git a/rushs/evalexpr/evalexpr/src/stack_struct.h b/rushs/evalexpr/evalexpr/src/stack_struct.h new file mode 100644 index 0000000..105cd5d --- /dev/null +++ b/rushs/evalexpr/evalexpr/src/stack_struct.h @@ -0,0 +1,10 @@ +#ifndef STACK_STRUCT_H +#define STACK_STRUCT_H + +struct stack +{ + int data; + struct stack *next; +}; + +#endif /* ! STACK_STRUCT_H */ diff --git a/rushs/evalexpr/evalexpr/tests/tests.sh b/rushs/evalexpr/evalexpr/tests/tests.sh new file mode 100755 index 0000000..920f09b --- /dev/null +++ b/rushs/evalexpr/evalexpr/tests/tests.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +REF_OUT="ref.out" +TEST_OUT="test.out" + +testrpn() +{ + echo "$2" > "$REF_OUT" + echo "Evaluating '$1' in RPN notation..." + echo "$1" | ./evalexpr -rpn > "$TEST_OUT" + diff "$REF_OUT" "$TEST_OUT" && echo "Success" +} + +testeval() +{ + echo "$1" | bc 2> /dev/null > "$REF_OUT" + echo "Evaluating '$1' in standard notation..." + echo "$1" | ./evalexpr > "$TEST_OUT" + diff "$REF_OUT" "$TEST_OUT" && echo "Success" +} + +testerror() +{ + echo "Testing error code '$2'..." + echo "$1" | ./evalexpr + error="$(echo $?)" + [ "$2" -eq "$error" ] && echo "Succesful failure" || echo "Wrong error $error" +} + +clean() +{ + rm "$REF_OUT" "$TEST_OUT" +} + +# RPN + +echo "Tests for RPN:" +echo "======" + +testrpn "1 1 +" 2 +testrpn "5 2 2 ^ 3 + *" 35 +testrpn "10 6 9 3 + 0 11 - * / * 17 + 5 +" 22 +testrpn "3 4 5 * 3 + -" "-20" +testrpn "3 2 % 9 3 1 2 + * / -" 0 + +echo +echo "=============================================" +echo + +# Standard + +echo "Tests for standard notation:" +echo "======" + +testeval "1 + 1" +testeval " 1 + 1 +1 " +testeval "2 * 2" +testeval "5 * (2 + 4)" +testeval "5 * (2 % 4)" +testeval " 5 *(2 ^4) " +testeval " 5 *(2 ^4 " + +echo +echo "=============================================" +echo + +# Errors + +echo "Error tests:" +echo "======" + +testerror "" 0 +testerror "a+1" 1 +testerror "1%0" 3 + +echo "Testing error code '4'..." +./evalexpr --toto 2> /dev/null +echo $? + +# Cleanup + +clean diff --git a/rushs/evalexpr/evalexpr/tests/unit_tests.c b/rushs/evalexpr/evalexpr/tests/unit_tests.c new file mode 100644 index 0000000..ed445a0 --- /dev/null +++ b/rushs/evalexpr/evalexpr/tests/unit_tests.c @@ -0,0 +1,208 @@ +#include <criterion/criterion.h> +#include <criterion/assert.h> +#include <stddef.h> +#include <string.h> + +#include "../src/evalexpr.h" + +TestSuite(parse_number); + +Test(parse_number, parse_42) +{ + size_t o; + int actual = parse_number("42", &o); + cr_expect(actual == 42, "Attendu : %d, renvoyé : %d", 42, actual); + cr_expect(o == 1, "Décalage attendu : %d, renvoyé : %zu", 1, o); +} + +Test(parse_number, parse_4) +{ + size_t o; + int actual = parse_number("4", &o); + cr_expect(actual == 4, "Attendu : %d, renvoyé : %d", 4, actual); + cr_expect(o == 0, "Décalage attendu : %d, renvoyé : %zu", 0, o); +} + +TestSuite(my_pow); + +Test(my_pow, my_pow00) +{ + int actual = my_pow(0, 0); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} + +Test(my_pow, my_pown0) +{ + int actual = my_pow(50, 0); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} +Test(my_pow, my_pow0n) +{ + int actual = my_pow(0, 42); + cr_expect(actual == 0, "Attendu : %d, renvoyé : %d", 0, actual); +} +Test(my_pow, my_powab) +{ + int actual = my_pow(3,3); + cr_expect(actual == 27, "Attendu : %d, renvoyé : %d", 27, actual); +} +Test(my_pow, my_powab_2) +{ + int actual = my_pow(4, 2); + cr_expect(actual == 16, "Attendu : %d, renvoyé : %d", 16, actual); +} +Test(my_pow, my_powab_3) +{ + int actual = my_pow(10, 3); + cr_expect(actual == 1000, "Attendu : %d, renvoyé : %d", 1000, actual); +} +Test(my_pow, my_pow1n) +{ + int actual = my_pow(1, 50); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} + +TestSuite(RPN); + +Test(RPN, evalrpn_easiest) +{ + const char test[] = "1 1 +"; + int expected = 0; + int retval; + int res = 2; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_35) +{ + const char test[] = "5 2 2 ^ 3 + *"; + int expected = 0; + int retval; + int res = 35; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_22) +{ + const char test[] = "10 6 9 3 + 0 11 - * / * 17 + 5 +"; + int expected = 0; + int retval; + int res = 22; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_minus20) +{ + const char test[] = "3 4 5 * 3 + -"; + int expected = 0; + int retval; + int res = -20; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_zero) +{ + const char test[] = "3 2 % 9 3 1 2 + * / -"; + int expected = 0; + int retval; + int res = 0; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} + +TestSuite(Precedence); + +Test(Precedence, parenthesis_above_all) +{ + struct token pleft = { PAR_LEFT, '(' }; + struct token pright = { PAR_RIGHT, ')' }; + struct token unplus = { UN_PLUS, '+' }; + struct token exp = { EXP, '^' }; + struct token mul = { MUL, '*' }; + struct token minus = { SUB, '-' }; + int eq = opcmp(&pleft, &pright); + int sup = opcmp(&pleft, &unplus); + int inf = opcmp(&unplus, &pright); + int parftw = opcmp(&pleft, &exp); + int par4ever = opcmp(&pright, &mul); + int paragain = opcmp(&pright, &minus); + cr_expect(eq == 0, "Wrong order (equal)"); + cr_expect(sup > 0, "Wrong order (>)"); + cr_expect(inf < 0, "Wrong order (<)"); + cr_expect(parftw > 0, "Wrong order (>)"); + cr_expect(par4ever > 0, "Wrong order (>)"); + cr_expect(paragain > 0, "Wrong order (>)"); +} + +Test(Precedence, other_precedence_tests) +{ + struct token exp = { EXP, '^' }; + struct token mul = { MUL, '*' }; + struct token unplus = { UN_PLUS, '+' }; + struct token minus = { SUB, '-' }; + struct token plus = { ADD, '+' }; + int eq = opcmp(&minus, &plus); + int sup = opcmp(&exp, &mul); + int inf = opcmp(&plus, &unplus); + + cr_expect(eq == 0, "Wrong order (equal)"); + cr_expect(sup > 0, "Wrong order (>)"); + cr_expect(inf < 0, "Wrong order (<)"); +} + +TestSuite(ShuntingTests); + +Test(ShuntingTests, shunt_simplest) +{ + char *rpn; + const char *expr = "1 + 1"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "1 1 +") == 0, "Expected '1 1 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_nico) +{ + char *rpn; + const char *expr = "1 + 1 + 1"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "1 1 + 1 +") == 0, "Expected '1 1 + 1 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_harderdaddy) +{ + char *rpn; + const char *expr = "5*(2^2+3)"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "5 2 2 ^ 3 + *") == 0, "Expected '5 2 2 ^ 3 + *', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_numbers) +{ + char *rpn; + const char *expr = "42 + 50"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "42 50 +") == 0, "Expected '42 50 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_mod) +{ + char *rpn; + const char *expr = "42 % 50"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "42 50 %") == 0, "Expected '42 50 +', got %s", rpn); + free(rpn); +} diff --git a/rushs/evalexpr/fact/fact.c b/rushs/evalexpr/fact/fact.c new file mode 100644 index 0000000..1440c94 --- /dev/null +++ b/rushs/evalexpr/fact/fact.c @@ -0,0 +1,8 @@ +unsigned long fact(unsigned n) +{ + if (n == 0) + { + return 1; + } + return n * fact(n - 1); +} diff --git a/rushs/evalexpr/facto/facto.sh b/rushs/evalexpr/facto/facto.sh new file mode 100755 index 0000000..350973a --- /dev/null +++ b/rushs/evalexpr/facto/facto.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +[ $# -ne 1 ] && exit 1 +i=$1 +res=1 +while [ "$i" -gt 0 ]; do + res=$(($res * $i)) + i=$(($i - 1)) +done +echo "$res" diff --git a/rushs/evalexpr/fibo/fibo.c b/rushs/evalexpr/fibo/fibo.c new file mode 100644 index 0000000..99c0d79 --- /dev/null +++ b/rushs/evalexpr/fibo/fibo.c @@ -0,0 +1,8 @@ +unsigned long fibonacci(unsigned long n) +{ + if (n == 0 || n == 1) + { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} diff --git a/rushs/evalexpr/fibo_iter/fibo_iter.c b/rushs/evalexpr/fibo_iter/fibo_iter.c new file mode 100644 index 0000000..36ebf46 --- /dev/null +++ b/rushs/evalexpr/fibo_iter/fibo_iter.c @@ -0,0 +1,21 @@ +#include <stdio.h> + +unsigned long fibo_iter(unsigned long n) +{ + if (n == 0) + { + return 0; + } + unsigned long prev = 1; + unsigned long pprev = 0; + unsigned long i; + + for (i = 1; i < n; i++) + { + unsigned long next = pprev + prev; + pprev = prev; + prev = next; + } + + return prev; +} diff --git a/rushs/evalexpr/fifo/Makefile b/rushs/evalexpr/fifo/Makefile new file mode 100644 index 0000000..e5c9374 --- /dev/null +++ b/rushs/evalexpr/fifo/Makefile @@ -0,0 +1,16 @@ +CC=gcc +CFLAGS=-std=c99 -Wall -Wextra -Wvla -Werror -pedantic + +.PHONY: library clean + +library: fifo_access.o fifo_setup_destroy.o + ar csr libfifo.a $^ + +fifo_access.o: fifo_access.c + $(CC) $(CFLAGS) -c -o fifo_access.o fifo_access.c + +fifo_setup_destroy.o: fifo_setup_destroy.c + $(CC) $(CFLAGS) -c -o fifo_setup_destroy.o fifo_setup_destroy.c + +clean: + rm *.o libfifo.a diff --git a/rushs/evalexpr/fifo/fifo.h b/rushs/evalexpr/fifo/fifo.h new file mode 100644 index 0000000..c4b0a6f --- /dev/null +++ b/rushs/evalexpr/fifo/fifo.h @@ -0,0 +1,28 @@ +#ifndef FIFO_H +#define FIFO_H + +#include <stddef.h> + +struct list +{ + int data; + struct list *next; +}; + +struct fifo +{ + struct list *head; + struct list *tail; + size_t size; +}; + +struct fifo *fifo_init(void); +size_t fifo_size(struct fifo *fifo); +void fifo_push(struct fifo *fifo, int elt); +int fifo_head(struct fifo *fifo); +void fifo_pop(struct fifo *fifo); +void fifo_clear(struct fifo *fifo); +void fifo_destroy(struct fifo *fifo); +void fifo_print(const struct fifo *fifo); + +#endif /* !FIFO_H */ diff --git a/rushs/evalexpr/fifo/fifo_access.c b/rushs/evalexpr/fifo/fifo_access.c new file mode 100644 index 0000000..5d31586 --- /dev/null +++ b/rushs/evalexpr/fifo/fifo_access.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "fifo.h" + +size_t fifo_size(struct fifo *fifo) +{ + return fifo->size; +} + +void fifo_push(struct fifo *fifo, int elt) +{ + struct list *new = malloc(sizeof(struct list)); + if (new == NULL) + { + return; + } + new->data = elt; + + if (fifo_size(fifo) == 0) + { + fifo->head = new; + } + new->next = NULL; + if (fifo_size(fifo) != 0) + { + fifo->tail->next = new; + } + fifo->tail = new; + + fifo->size++; +} + +int fifo_head(struct fifo *fifo) +{ + return fifo->head->data; +} + +void fifo_pop(struct fifo *fifo) +{ + if (fifo_size(fifo) == 0) + { + return; + } + if (fifo_size(fifo) == 1) + { + free(fifo->head); + fifo->head = NULL; + fifo->tail = NULL; + return; + } + + struct list *tmp = fifo->head->next; + free(fifo->head); + fifo->head = tmp; + + fifo->size--; +} + +void fifo_print(const struct fifo *fifo) +{ + for (struct list *l = fifo->head; l; l = l->next) + { + printf("%d\n", l->data); + } +} diff --git a/rushs/evalexpr/fifo/fifo_setup_destroy.c b/rushs/evalexpr/fifo/fifo_setup_destroy.c new file mode 100644 index 0000000..80820e1 --- /dev/null +++ b/rushs/evalexpr/fifo/fifo_setup_destroy.c @@ -0,0 +1,39 @@ +#include <stdlib.h> + +#include "fifo.h" + +struct fifo *fifo_init(void) +{ + struct fifo *f = malloc(sizeof(struct fifo)); + if (f == NULL) + { + return NULL; + } + + f->size = 0; + f->head = NULL; + f->tail = NULL; + + return f; +} + +void fifo_clear(struct fifo *fifo) +{ + for (struct list *l = fifo->head; l != fifo->tail;) + { + struct list *tmp = l->next; + free(l); + l = tmp; + } + free(fifo->tail); + + fifo->head = NULL; + fifo->tail = NULL; + fifo->size = 0; +} + +void fifo_destroy(struct fifo *fifo) +{ + fifo_clear(fifo); + free(fifo); +} diff --git a/rushs/evalexpr/find_ascii/find_ascii.sh b/rushs/evalexpr/find_ascii/find_ascii.sh new file mode 100755 index 0000000..db31722 --- /dev/null +++ b/rushs/evalexpr/find_ascii/find_ascii.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +for filename in $(ls "$1"); do + echo $1/$filename | file -f - | grep ASCII +done diff --git a/rushs/evalexpr/freq_analysis/freq_analysis.c b/rushs/evalexpr/freq_analysis/freq_analysis.c new file mode 100644 index 0000000..c60d7a6 --- /dev/null +++ b/rushs/evalexpr/freq_analysis/freq_analysis.c @@ -0,0 +1,28 @@ +#include <stdio.h> + +int find_rank(int h[26], int min) +{ + int res = 0; + for (int i = 0; i < 26; i++) + { + res += h[i] > h[min] || (h[i] == h[min] && i < min); + } + return res; +} + +void freq_analysis(const char text[], const char table[]) +{ + int h[26] = { 0 }; + for (int i = 0; text[i]; i++) + { + h[text[i] - 'A']++; + } + + for (int j = 0; j < 26; j++) + { + if (h[j] != 0) + { + printf("%c %c\n", j + 'A', table[find_rank(h, j)]); + } + } +} diff --git a/rushs/evalexpr/functional_programming/foldl.c b/rushs/evalexpr/functional_programming/foldl.c new file mode 100644 index 0000000..ac222a7 --- /dev/null +++ b/rushs/evalexpr/functional_programming/foldl.c @@ -0,0 +1,11 @@ +#include "functional_programming.h" + +int foldl(int *array, size_t len, int (*func)(int, int)) +{ + int acc = 0; + for (size_t i = 0; i < len; i++) + { + acc = (*func)(acc, array[i]); + } + return acc; +} diff --git a/rushs/evalexpr/functional_programming/foldr.c b/rushs/evalexpr/functional_programming/foldr.c new file mode 100644 index 0000000..c232410 --- /dev/null +++ b/rushs/evalexpr/functional_programming/foldr.c @@ -0,0 +1,10 @@ +#include "functional_programming.h" + +int foldr(int *array, size_t len, int (*func)(int, int)) +{ + if (len == 1) + { + return (*func)(array[0], 0); + } + return (*func)(array[0], foldr(array + 1, len - 1, func)); +} diff --git a/rushs/evalexpr/functional_programming/functional_programming.h b/rushs/evalexpr/functional_programming/functional_programming.h new file mode 100644 index 0000000..429b13c --- /dev/null +++ b/rushs/evalexpr/functional_programming/functional_programming.h @@ -0,0 +1,10 @@ +#ifndef FUNCTIONAL_PROGRAMMING_H +#define FUNCTIONAL_PROGRAMMING_H + +#include <stddef.h> + +void map(int *array, size_t len, void (*func)(int *)); +int foldr(int *array, size_t len, int (*func)(int, int)); +int foldl(int *array, size_t len, int (*func)(int, int)); + +#endif /* !FUNCTIONAL_PROGRAMMING_H */ diff --git a/rushs/evalexpr/functional_programming/map.c b/rushs/evalexpr/functional_programming/map.c new file mode 100644 index 0000000..311c39c --- /dev/null +++ b/rushs/evalexpr/functional_programming/map.c @@ -0,0 +1,9 @@ +#include "functional_programming.h" + +void map(int *array, size_t len, void (*func)(int *)) +{ + for (size_t i = 0; i < len; i++) + { + (*func)(array + i); + } +} diff --git a/rushs/evalexpr/generate_files/generate_files.sh b/rushs/evalexpr/generate_files/generate_files.sh new file mode 100755 index 0000000..cf2ba0a --- /dev/null +++ b/rushs/evalexpr/generate_files/generate_files.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +FILENAME="default" +NUMBER="1" +EXTENSION="txt" + +while [ $# -gt 0 ]; do + case "$1" in + '-f' | '--filename') + shift + FILENAME="$1" + shift + ;; + '-n' | '--number') + shift + NUMBER="$1" + shift + ;; + '-e' | '--extension') + shift + EXTENSION="$1" + shift + ;; + *) + exit 1 + ;; + esac +done + +for i in $(seq 1 $NUMBER); do + touch -- "$FILENAME-$i.$EXTENSION" +done diff --git a/rushs/evalexpr/generic_void_list/list.c b/rushs/evalexpr/generic_void_list/list.c new file mode 100644 index 0000000..20ecfa8 --- /dev/null +++ b/rushs/evalexpr/generic_void_list/list.c @@ -0,0 +1,36 @@ +#include "list.h" + +#include <stdlib.h> +#include <string.h> + +struct list *list_prepend(struct list *list, const void *value, + size_t data_size) +{ + struct list *new = malloc(sizeof(struct list)); + new->next = list; + new->data = malloc(sizeof(void *)); + memcpy(new->data, value, data_size); + return new; +} + +size_t list_length(struct list *list) +{ + size_t res = 0; + while (list) + { + res++; + list = list->next; + } + return res; +} + +void list_destroy(struct list *list) +{ + while (list) + { + struct list *tmp = list->next; + free(list->data); + free(list); + list = tmp; + } +} diff --git a/rushs/evalexpr/generic_void_list/list.h b/rushs/evalexpr/generic_void_list/list.h new file mode 100644 index 0000000..a1bc035 --- /dev/null +++ b/rushs/evalexpr/generic_void_list/list.h @@ -0,0 +1,31 @@ +#ifndef LIST_H +#define LIST_H + +#include <stddef.h> + +struct list +{ + void *data; + struct list *next; +}; + +/* +** Insert a node containing `value` at the beginning of the list. +** Return `NULL` if an error occurred. +*/ +struct list *list_prepend(struct list *list, const void *value, + size_t data_size); + +/* +** Return the length of the list. +** Return `0` if the list is empty. +*/ +size_t list_length(struct list *list); + +/* +** Release the memory used by the list. +** Does nothing if `list` is `NULL`. +*/ +void list_destroy(struct list *list); + +#endif /* !LIST_H */ diff --git a/rushs/evalexpr/glob_easy/glob_easy.sh b/rushs/evalexpr/glob_easy/glob_easy.sh new file mode 100755 index 0000000..b6ae028 --- /dev/null +++ b/rushs/evalexpr/glob_easy/glob_easy.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo $1/*.[A-Za-z][A-Za-z] diff --git a/rushs/evalexpr/glob_remove_shell/glob_remove_shell.sh b/rushs/evalexpr/glob_remove_shell/glob_remove_shell.sh new file mode 100755 index 0000000..c2e7ff7 --- /dev/null +++ b/rushs/evalexpr/glob_remove_shell/glob_remove_shell.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +fmt=*.${1:-"txt"} + +for file in $(echo "$fmt"); do + [ -e "$file" ] && rm "$file" || exit 1 +done diff --git a/rushs/evalexpr/grade/grade.c b/rushs/evalexpr/grade/grade.c new file mode 100644 index 0000000..caecc82 --- /dev/null +++ b/rushs/evalexpr/grade/grade.c @@ -0,0 +1,29 @@ +#include <stdio.h> + +void grade(char g) +{ + switch (g) + { + case 'A': + puts("Excellent"); + break; + case 'B': + puts("Good"); + break; + case 'C': + puts("Not so bad"); + break; + case 'D': + puts("Could be worse"); + break; + case 'E': + puts("Maybe next time"); + break; + case 'F': + puts("No comment"); + break; + default: + puts("Call a wild ACU"); + break; + } +} diff --git a/rushs/evalexpr/greatest_divisor/greatest_divisor.c b/rushs/evalexpr/greatest_divisor/greatest_divisor.c new file mode 100644 index 0000000..4c8efef --- /dev/null +++ b/rushs/evalexpr/greatest_divisor/greatest_divisor.c @@ -0,0 +1,15 @@ +unsigned int greatest_divisor(unsigned int n) +{ + if (n == 0 || n == 1) + { + return 1; + } + + int i; + for (i = n / 2; i > 0 && n % i; i--) + { + continue; + } + + return i; +} diff --git a/rushs/evalexpr/hacker_news/input.html b/rushs/evalexpr/hacker_news/input.html new file mode 100644 index 0000000..54d338d --- /dev/null +++ b/rushs/evalexpr/hacker_news/input.html @@ -0,0 +1,147 @@ +<html op="news" class=" lddwcbt idc0_332" lang="en"><head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta name="referrer" content="origin"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" type="text/css" href="02_files/news.css"> + <link rel="shortcut icon" href="https://news.ycombinator.com/favicon.ico"> + <link rel="alternate" type="application/rss+xml" title="RSS" href="https://news.ycombinator.com/rss"> + <title>Hacker News</title></head><body><center><table id="hnmain" width="85%" cellspacing="0" cellpadding="0" border="0" bgcolor="#f6f6ef"> + <tbody><tr><td bgcolor="#ff6600"><table style="padding:2px" width="100%" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td style="width:18px;padding-right:4px"><a href="https://news.ycombinator.com/"><img src="02_files/y18.gif" style="border:1px white solid;" width="18" height="18"></a></td> + <td style="line-height:12pt; height:10px;"><span class="pagetop"><b class="hnname"><a href="https://news.ycombinator.com/news">Hacker News</a></b> + <a href="https://news.ycombinator.com/newest">new</a> | <a href="https://news.ycombinator.com/front">past</a> | <a href="https://news.ycombinator.com/newcomments">comments</a> | <a href="https://news.ycombinator.com/ask">ask</a> | <a href="https://news.ycombinator.com/show">show</a> | <a href="https://news.ycombinator.com/jobs">jobs</a> | <a href="https://news.ycombinator.com/submit">submit</a> </span></td><td style="text-align:right;padding-right:4px;"><span class="pagetop"> + <a href="https://news.ycombinator.com/login?goto=news%3Fp%3D2">login</a> + </span></td> + </tr></tbody></table></td></tr> +<tr id="pagespace" title="" style="height:10px"></tr><tr><td><table class="itemlist" cellspacing="0" cellpadding="0" border="0"> + <tbody><tr class="athing" id="28943869"> + <td class="title" valign="top" align="right"><span class="rank">31.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943869" href="https://news.ycombinator.com/vote?id=28943869&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://apnews.com/article/technology-business-arts-and-entertainment-be48d7582fdd5604664fff33ed81ca80" class="titlelink">Sinclair Broadcast Group identifies data breach</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=apnews.com"><span class="sitestr">apnews.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943869">8 points</span> by <a href="https://news.ycombinator.com/user?id=xojoc" class="hnuser">xojoc</a> <span class="age" title="2021-10-21T13:12:05"><a href="https://news.ycombinator.com/item?id=28943869">1 hour ago</a></span> <span id="unv_28943869"></span> | <a href="https://news.ycombinator.com/hide?id=28943869&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943869">1 comment</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28926775"> + <td class="title" valign="top" align="right"><span class="rank">32.</span></td> <td class="votelinks" valign="top"><center><a id="up_28926775" href="https://news.ycombinator.com/vote?id=28926775&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.earlevel.com/main/2002/08/31/a-gentle-introduction-to-the-fft/" class="titlelink">A gentle introduction to the FFT (2002)</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=earlevel.com"><span class="sitestr">earlevel.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28926775">71 points</span> by <a href="https://news.ycombinator.com/user?id=tigerlily" class="hnuser">tigerlily</a> <span class="age" title="2021-10-20T04:31:20"><a href="https://news.ycombinator.com/item?id=28926775">12 hours ago</a></span> <span id="unv_28926775"></span> | <a href="https://news.ycombinator.com/hide?id=28926775&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28926775">14 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28930157"> + <td class="title" valign="top" align="right"><span class="rank">33.</span></td> <td class="votelinks" valign="top"><center><a id="up_28930157" href="https://news.ycombinator.com/vote?id=28930157&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://thebrowser.com/notes/jon-ingold/" class="titlelink">Jon Ingold on translating archeology into video games</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=thebrowser.com"><span class="sitestr">thebrowser.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28930157">36 points</span> by <a href="https://news.ycombinator.com/user?id=nupitalnumber" class="hnuser">nupitalnumber</a> <span class="age" title="2021-10-20T13:04:53"><a href="https://news.ycombinator.com/item?id=28930157">9 hours ago</a></span> <span id="unv_28930157"></span> | <a href="https://news.ycombinator.com/hide?id=28930157&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28930157">4 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28943611"> + <td class="title" valign="top" align="right"><span class="rank">34.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943611" href="https://news.ycombinator.com/vote?id=28943611&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://news.ycombinator.com/item?id=28943611" class="titlelink">Ask HN: How to Sell a Website</a></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943611">7 points</span> by <a href="https://news.ycombinator.com/user?id=legrisch" class="hnuser">legrisch</a> <span class="age" title="2021-10-21T12:45:35"><a href="https://news.ycombinator.com/item?id=28943611">1 hour ago</a></span> <span id="unv_28943611"></span> | <a href="https://news.ycombinator.com/hide?id=28943611&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943611">3 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28933391"> + <td class="title" valign="top" align="right"><span class="rank">35.</span></td> <td class="votelinks" valign="top"><center><a id="up_28933391" href="https://news.ycombinator.com/vote?id=28933391&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://iconmap.io/blog" class="titlelink">We analyzed 425k favicons</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=iconmap.io"><span class="sitestr">iconmap.io</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28933391">493 points</span> by <a href="https://news.ycombinator.com/user?id=gurgeous" class="hnuser">gurgeous</a> <span class="age" title="2021-10-20T17:29:03"><a href="https://news.ycombinator.com/item?id=28933391">20 hours ago</a></span> <span id="unv_28933391"></span> | <a href="https://news.ycombinator.com/hide?id=28933391&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28933391">119 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28938551"> + <td class="title" valign="top" align="right"><span class="rank">36.</span></td> <td class="votelinks" valign="top"><center><a id="up_28938551" href="https://news.ycombinator.com/vote?id=28938551&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.science.org/content/article/machu-picchu-was-built-over-major-fault-zones-now-researchers-think-they-know-why" class="titlelink">Machu Picchu was built over major fault zones (2019)</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=science.org"><span class="sitestr">science.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28938551">98 points</span> by <a href="https://news.ycombinator.com/user?id=Anon84" class="hnuser">Anon84</a> <span class="age" title="2021-10-21T00:07:54"><a href="https://news.ycombinator.com/item?id=28938551">14 hours ago</a></span> <span id="unv_28938551"></span> | <a href="https://news.ycombinator.com/hide?id=28938551&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28938551">41 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940507"> + <td class="title" valign="top" align="right"><span class="rank">37.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940507" href="https://news.ycombinator.com/vote?id=28940507&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://brave.com/wp-content/uploads/2021/03/goggles.pdf" class="titlelink">Goggles: Democracy dies in darkness, and so does the Web [pdf]</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=brave.com"><span class="sitestr">brave.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940507">114 points</span> by <a href="https://news.ycombinator.com/user?id=InvaderFizz" class="hnuser">InvaderFizz</a> <span class="age" title="2021-10-21T05:03:56"><a href="https://news.ycombinator.com/item?id=28940507">9 hours ago</a></span> <span id="unv_28940507"></span> | <a href="https://news.ycombinator.com/hide?id=28940507&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940507">119 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28933663"> + <td class="title" valign="top" align="right"><span class="rank">38.</span></td> <td class="votelinks" valign="top"><center><a id="up_28933663" href="https://news.ycombinator.com/vote?id=28933663&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://browser.geekbench.com/v5/cpu/10496766" class="titlelink">Apple M1 Max Geekbench Score</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=geekbench.com"><span class="sitestr">geekbench.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28933663">467 points</span> by <a href="https://news.ycombinator.com/user?id=mv9" class="hnuser">mv9</a> <span class="age" title="2021-10-20T17:50:17"><a href="https://news.ycombinator.com/item?id=28933663">20 hours ago</a></span> <span id="unv_28933663"></span> | <a href="https://news.ycombinator.com/hide?id=28933663&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28933663">771 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28933981"> + <td class="title" valign="top" align="right"><span class="rank">39.</span></td> <td class="votelinks" valign="top"><center><a id="up_28933981" href="https://news.ycombinator.com/vote?id=28933981&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.commerce.gov/news/press-releases/2021/10/commerce-tightens-export-controls-items-used-surveillance-private" class="titlelink">U.S. tightens export controls on items used in surveillance of private citizens</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=commerce.gov"><span class="sitestr">commerce.gov</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28933981">275 points</span> by <a href="https://news.ycombinator.com/user?id=transpute" class="hnuser">transpute</a> <span class="age" title="2021-10-20T18:14:33"><a href="https://news.ycombinator.com/item?id=28933981">20 hours ago</a></span> <span id="unv_28933981"></span> | <a href="https://news.ycombinator.com/hide?id=28933981&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28933981">161 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28943645"> + <td class="title" valign="top" align="right"><span class="rank">40.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943645" href="https://news.ycombinator.com/vote?id=28943645&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.wsj.com/articles/wework-set-to-go-public-via-spac-deal-two-years-after-failed-ipo-11634808600" class="titlelink" rel="nofollow">WeWork is trying to go public – again</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=wsj.com"><span class="sitestr">wsj.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943645">8 points</span> by <a href="https://news.ycombinator.com/user?id=collegeburner" class="hnuser">collegeburner</a> <span class="age" title="2021-10-21T12:49:02"><a href="https://news.ycombinator.com/item?id=28943645">1 hour ago</a></span> <span id="unv_28943645"></span> | <a href="https://news.ycombinator.com/hide?id=28943645&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943645">2 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28934624"> + <td class="title" valign="top" align="right"><span class="rank">41.</span></td> <td class="votelinks" valign="top"><center><a id="up_28934624" href="https://news.ycombinator.com/vote?id=28934624&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.copetti.org/writings/consoles/playstation-3/" class="titlelink">Playstation 3 Architecture</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=copetti.org"><span class="sitestr">copetti.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28934624">362 points</span> by <a href="https://news.ycombinator.com/user?id=bangonkeyboard" class="hnuser">bangonkeyboard</a> <span class="age" title="2021-10-20T18:56:53"><a href="https://news.ycombinator.com/item?id=28934624">19 hours ago</a></span> <span id="unv_28934624"></span> | <a href="https://news.ycombinator.com/hide?id=28934624&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28934624">81 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28929639"> + <td class="title" valign="top" align="right"><span class="rank">42.</span></td> <td class="votelinks" valign="top"><center><a id="up_28929639" href="https://news.ycombinator.com/vote?id=28929639&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://owlpal.substack.com/p/about-that-time-i-had-an-outburst" class="titlelink">About that time I had an outburst during the Y Combinator Interview</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=owlpal.substack.com"><span class="sitestr">owlpal.substack.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28929639">498 points</span> by <a href="https://news.ycombinator.com/user?id=curiousowl" class="hnuser">curiousowl</a> <span class="age" title="2021-10-20T12:03:25"><a href="https://news.ycombinator.com/item?id=28929639">1 day ago</a></span> <span id="unv_28929639"></span> | <a href="https://news.ycombinator.com/hide?id=28929639&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28929639">242 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28938378"> + <td class="title" valign="top" align="right"><span class="rank">43.</span></td> <td class="votelinks" valign="top"><center><a id="up_28938378" href="https://news.ycombinator.com/vote?id=28938378&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.guernicamag.com/one-mans-pest/" class="titlelink" rel="nofollow">One Man's Pest</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=guernicamag.com"><span class="sitestr">guernicamag.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28938378">8 points</span> by <a href="https://news.ycombinator.com/user?id=yimby" class="hnuser">yimby</a> <span class="age" title="2021-10-20T23:47:13"><a href="https://news.ycombinator.com/item?id=28938378">6 hours ago</a></span> <span id="unv_28938378"></span> | <a href="https://news.ycombinator.com/hide?id=28938378&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28938378">discuss</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28926582"> + <td class="title" valign="top" align="right"><span class="rank">44.</span></td> <td class="votelinks" valign="top"><center><a id="up_28926582" href="https://news.ycombinator.com/vote?id=28926582&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://brave.com/search-and-web-discovery/" class="titlelink">Brave Search replaces Google as default search engine in the Brave browser</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=brave.com"><span class="sitestr">brave.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28926582">723 points</span> by <a href="https://news.ycombinator.com/user?id=skellertor" class="hnuser">skellertor</a> <span class="age" title="2021-10-20T03:56:51"><a href="https://news.ycombinator.com/item?id=28926582">1 day ago</a></span> <span id="unv_28926582"></span> | <a href="https://news.ycombinator.com/hide?id=28926582&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28926582">528 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28943866"> + <td class="title" valign="top" align="right"><span class="rank">45.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943866" href="https://news.ycombinator.com/vote?id=28943866&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://twitter.com//rashiq/status/1319346264992026624" class="titlelink" rel="nofollow">I reverse engineered mcdonald's internal API</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=twitter.com/rashiq"><span class="sitestr">twitter.com/rashiq</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943866">3 points</span> by <a href="https://news.ycombinator.com/user?id=graderjs" class="hnuser">graderjs</a> <span class="age" title="2021-10-21T13:11:46"><a href="https://news.ycombinator.com/item?id=28943866">1 hour ago</a></span> <span id="unv_28943866"></span> | <a href="https://news.ycombinator.com/hide?id=28943866&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943866">discuss</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28936324"> + <td class="title" valign="top" align="right"><span class="rank">46.</span></td> <td class="votelinks" valign="top"><center><a id="up_28936324" href="https://news.ycombinator.com/vote?id=28936324&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.science.org/doi/10.1126/scisignal.abc4764" class="titlelink">Injury response to DNA damage in live tumor cells promotes antitumor immunity</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=science.org"><span class="sitestr">science.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28936324">109 points</span> by <a href="https://news.ycombinator.com/user?id=bcaulfield" class="hnuser">bcaulfield</a> <span class="age" title="2021-10-20T20:48:40"><a href="https://news.ycombinator.com/item?id=28936324">17 hours ago</a></span> <span id="unv_28936324"></span> | <a href="https://news.ycombinator.com/hide?id=28936324&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28936324">5 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940197"> + <td class="title" valign="top" align="right"><span class="rank">47.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940197" href="https://news.ycombinator.com/vote?id=28940197&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.cowin.gov.in/" class="titlelink">India Counting Down to 1B Doses</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=cowin.gov.in"><span class="sitestr">cowin.gov.in</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940197">105 points</span> by <a href="https://news.ycombinator.com/user?id=neelkadia" class="hnuser">neelkadia</a> <span class="age" title="2021-10-21T04:17:41"><a href="https://news.ycombinator.com/item?id=28940197">10 hours ago</a></span> <span id="unv_28940197"></span> | <a href="https://news.ycombinator.com/hide?id=28940197&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940197">78 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28943066"> + <td class="title" valign="top" align="right"><span class="rank">48.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943066" href="https://news.ycombinator.com/vote?id=28943066&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://slate.com/technology/2021/10/tether-crypto-danger-ben-mckenzie.html" class="titlelink" rel="nofollow">Time to get worried about Tether, the “stablecoin†at center of cryptocurrency</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=slate.com"><span class="sitestr">slate.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943066">6 points</span> by <a href="https://news.ycombinator.com/user?id=RickJWagner" class="hnuser">RickJWagner</a> <span class="age" title="2021-10-21T11:45:09"><a href="https://news.ycombinator.com/item?id=28943066">2 hours ago</a></span> <span id="unv_28943066"></span> | <a href="https://news.ycombinator.com/hide?id=28943066&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943066">5 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940258"> + <td class="title" valign="top" align="right"><span class="rank">49.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940258" href="https://news.ycombinator.com/vote?id=28940258&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.alifewithoutlimits.com.au/the-history-of-surveying/" class="titlelink">The History of Surveying</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=alifewithoutlimits.com.au"><span class="sitestr">alifewithoutlimits.com.au</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940258">20 points</span> by <a href="https://news.ycombinator.com/user?id=barbazoo" class="hnuser">barbazoo</a> <span class="age" title="2021-10-21T04:27:11"><a href="https://news.ycombinator.com/item?id=28940258">9 hours ago</a></span> <span id="unv_28940258"></span> | <a href="https://news.ycombinator.com/hide?id=28940258&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940258">9 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28921244"> + <td class="title" valign="top" align="right"><span class="rank">50.</span></td> <td class="votelinks" valign="top"><center><a id="up_28921244" href="https://news.ycombinator.com/vote?id=28921244&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.npr.org/2021/10/19/1047303559/fda-hearing-aid-prescription-over-the-counter" class="titlelink">The FDA wants you to be able to buy a hearing aid without a prescription</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=npr.org"><span class="sitestr">npr.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28921244">722 points</span> by <a href="https://news.ycombinator.com/user?id=cf100clunk" class="hnuser">cf100clunk</a> <span class="age" title="2021-10-19T17:58:42"><a href="https://news.ycombinator.com/item?id=28921244">1 day ago</a></span> <span id="unv_28921244"></span> | <a href="https://news.ycombinator.com/hide?id=28921244&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28921244">441 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28942594"> + <td class="title" valign="top" align="right"><span class="rank">51.</span></td> <td class="votelinks" valign="top"><center><a id="up_28942594" href="https://news.ycombinator.com/vote?id=28942594&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.pcgamer.com/windows-11-pcs-can-hobble-gaming-performance/" class="titlelink">Windows 11 will hobble gaming performance by default on some prebuilt PCs</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=pcgamer.com"><span class="sitestr">pcgamer.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28942594">13 points</span> by <a href="https://news.ycombinator.com/user?id=DeathArrow" class="hnuser">DeathArrow</a> <span class="age" title="2021-10-21T10:33:39"><a href="https://news.ycombinator.com/item?id=28942594">3 hours ago</a></span> <span id="unv_28942594"></span> | <a href="https://news.ycombinator.com/hide?id=28942594&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28942594">3 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940705"> + <td class="title" valign="top" align="right"><span class="rank">52.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940705" href="https://news.ycombinator.com/vote?id=28940705&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.gimp.org/news/2021/10/20/gimp-2-99-8-released/" class="titlelink">Development version: GIMP 2.99.8 Released</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=gimp.org"><span class="sitestr">gimp.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940705">19 points</span> by <a href="https://news.ycombinator.com/user?id=pauloxnet" class="hnuser">pauloxnet</a> <span class="age" title="2021-10-21T05:33:20"><a href="https://news.ycombinator.com/item?id=28940705">8 hours ago</a></span> <span id="unv_28940705"></span> | <a href="https://news.ycombinator.com/hide?id=28940705&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940705">2 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28903383"> + <td class="title" valign="top" align="right"><span class="rank">53.</span></td> <td class="votelinks" valign="top"><center><a id="up_28903383" href="https://news.ycombinator.com/vote?id=28903383&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://mikolaj-kaminski.com/jetbrains-rider-docker-compose-unicodedecodeerror-issue-fix/" class="titlelink">I couldn't debug the code because of my name</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=mikolaj-kaminski.com"><span class="sitestr">mikolaj-kaminski.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28903383">247 points</span> by <a href="https://news.ycombinator.com/user?id=mikasjp" class="hnuser">mikasjp</a> <span class="age" title="2021-10-18T08:40:39"><a href="https://news.ycombinator.com/item?id=28903383">23 hours ago</a></span> <span id="unv_28903383"></span> | <a href="https://news.ycombinator.com/hide?id=28903383&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28903383">268 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28937484"> + <td class="title" valign="top" align="right"><span class="rank">54.</span></td> <td class="votelinks" valign="top"><center><a id="up_28937484" href="https://news.ycombinator.com/vote?id=28937484&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://calbryant.uk/blog/10-ways-to-get-the-best-out-of-openscad/" class="titlelink">Getting the best out of OpenSCAD</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=calbryant.uk"><span class="sitestr">calbryant.uk</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28937484">109 points</span> by <a href="https://news.ycombinator.com/user?id=naggie" class="hnuser">naggie</a> <span class="age" title="2021-10-20T22:13:20"><a href="https://news.ycombinator.com/item?id=28937484">16 hours ago</a></span> <span id="unv_28937484"></span> | <a href="https://news.ycombinator.com/hide?id=28937484&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28937484">52 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28921083"> + <td class="title" valign="top" align="right"><span class="rank">55.</span></td> <td class="votelinks" valign="top"><center><a id="up_28921083" href="https://news.ycombinator.com/vote?id=28921083&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://spectrum.ieee.org/recycled-batteries-good-as-newly-mined" class="titlelink">Study: Recycled Lithium Batteries as Good as Newly Mined</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=ieee.org"><span class="sitestr">ieee.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28921083">623 points</span> by <a href="https://news.ycombinator.com/user?id=mpweiher" class="hnuser">mpweiher</a> <span class="age" title="2021-10-19T17:45:07"><a href="https://news.ycombinator.com/item?id=28921083">1 day ago</a></span> <span id="unv_28921083"></span> | <a href="https://news.ycombinator.com/hide?id=28921083&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28921083">179 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28934715"> + <td class="title" valign="top" align="right"><span class="rank">56.</span></td> <td class="votelinks" valign="top"><center><a id="up_28934715" href="https://news.ycombinator.com/vote?id=28934715&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://americasfuture.org/eliminating-gifted-programs-wont-make-education-fair/" class="titlelink">Eliminating gifted programs won’t make education fair</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=americasfuture.org"><span class="sitestr">americasfuture.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28934715">180 points</span> by <a href="https://news.ycombinator.com/user?id=paulpauper" class="hnuser">paulpauper</a> <span class="age" title="2021-10-20T19:03:44"><a href="https://news.ycombinator.com/item?id=28934715">19 hours ago</a></span> <span id="unv_28934715"></span> | <a href="https://news.ycombinator.com/hide?id=28934715&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28934715">400 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28939407"> + <td class="title" valign="top" align="right"><span class="rank">57.</span></td> <td class="votelinks" valign="top"><center><a id="up_28939407" href="https://news.ycombinator.com/vote?id=28939407&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://github.com/ToshioCP/Gtk4-tutorial/blob/main/Readme.md" class="titlelink">Gtk4 Tutorial</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=github.com/toshiocp"><span class="sitestr">github.com/toshiocp</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28939407">53 points</span> by <a href="https://news.ycombinator.com/user?id=marcodiego" class="hnuser">marcodiego</a> <span class="age" title="2021-10-21T01:59:18"><a href="https://news.ycombinator.com/item?id=28939407">12 hours ago</a></span> <span id="unv_28939407"></span> | <a href="https://news.ycombinator.com/hide?id=28939407&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28939407">73 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940334"> + <td class="title" valign="top" align="right"><span class="rank">58.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940334" href="https://news.ycombinator.com/vote?id=28940334&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://obua.com/publications/cosmo-id/3/" class="titlelink" rel="nofollow">Cosmopolitan Identiï¬ers</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=obua.com"><span class="sitestr">obua.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940334">10 points</span> by <a href="https://news.ycombinator.com/user?id=BeefySwain" class="hnuser">BeefySwain</a> <span class="age" title="2021-10-21T04:39:41"><a href="https://news.ycombinator.com/item?id=28940334">9 hours ago</a></span> <span id="unv_28940334"></span> | <a href="https://news.ycombinator.com/hide?id=28940334&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940334">2 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28929840"> + <td class="title" valign="top" align="right"><span class="rank">59.</span></td> <td class="votelinks" valign="top"><center><a id="up_28929840" href="https://news.ycombinator.com/vote?id=28929840&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://madned.substack.com/p/a-talk-with-computer-gaming-pioneer" class="titlelink">A talk with Walter Bright about Empire</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=madned.substack.com"><span class="sitestr">madned.substack.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28929840">218 points</span> by <a href="https://news.ycombinator.com/user?id=mad_ned" class="hnuser">mad_ned</a> <span class="age" title="2021-10-20T12:29:16"><a href="https://news.ycombinator.com/item?id=28929840">1 day ago</a></span> <span id="unv_28929840"></span> | <a href="https://news.ycombinator.com/hide?id=28929840&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28929840">86 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28934833"> + <td class="title" valign="top" align="right"><span class="rank">60.</span></td> <td class="votelinks" valign="top"><center><a id="up_28934833" href="https://news.ycombinator.com/vote?id=28934833&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.youtube.com/watch?v=NjrYk546uBA" class="titlelink">Bioelektryczność – Polish Robotics (1968) [video]</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=youtube.com"><span class="sitestr">youtube.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28934833">123 points</span> by <a href="https://news.ycombinator.com/user?id=danielEM" class="hnuser">danielEM</a> <span class="age" title="2021-10-20T19:11:59"><a href="https://news.ycombinator.com/item?id=28934833">19 hours ago</a></span> <span id="unv_28934833"></span> | <a href="https://news.ycombinator.com/hide?id=28934833&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28934833">27 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="morespace" style="height:10px"></tr><tr><td colspan="2"></td><td class="title"><a href="https://news.ycombinator.com/news?p=3" class="morelink" rel="next">More</a></td></tr> + </tbody></table> +</td></tr> +<tr><td><img src="02_files/s.gif" width="0" height="10"><table width="100%" cellspacing="0" cellpadding="1"><tbody><tr><td bgcolor="#ff6600"></td></tr></tbody></table><br><center><span class="yclinks"><a href="https://news.ycombinator.com/newsguidelines.html">Guidelines</a> + | <a href="https://news.ycombinator.com/newsfaq.html">FAQ</a> + | <a href="https://news.ycombinator.com/lists">Lists</a> + | <a href="https://github.com/HackerNews/API">API</a> + | <a href="https://news.ycombinator.com/security.html">Security</a> + | <a href="http://www.ycombinator.com/legal/">Legal</a> + | <a href="http://www.ycombinator.com/apply/">Apply to YC</a> + | <a href="mailto:hn@ycombinator.com">Contact</a></span><br><br><form method="get" action="//hn.algolia.com/">Search: + <input type="text" name="q" size="17" autocorrect="off" spellcheck="false" autocapitalize="none" autocomplete="false"></form> + </center></td></tr> + </tbody></table></center><script type="text/javascript" src="02_files/hn.js"></script> +</body></html>
\ No newline at end of file diff --git a/rushs/evalexpr/hacker_news/news.sed b/rushs/evalexpr/hacker_news/news.sed new file mode 100644 index 0000000..91b76d6 --- /dev/null +++ b/rushs/evalexpr/hacker_news/news.sed @@ -0,0 +1 @@ +s/^.*"\(https\?:\/\/.*\)" class="titlelink"\( rel="nofollow"\)\?>\([^<]*\).*$/**\3**\n\1\n/p diff --git a/rushs/evalexpr/hacker_news/output.txt b/rushs/evalexpr/hacker_news/output.txt new file mode 100644 index 0000000..68cc714 --- /dev/null +++ b/rushs/evalexpr/hacker_news/output.txt @@ -0,0 +1,90 @@ +**Sinclair Broadcast Group identifies data breach** +https://apnews.com/article/technology-business-arts-and-entertainment-be48d7582fdd5604664fff33ed81ca80 + +**A gentle introduction to the FFT (2002)** +https://www.earlevel.com/main/2002/08/31/a-gentle-introduction-to-the-fft/ + +**Jon Ingold on translating archeology into video games** +https://thebrowser.com/notes/jon-ingold/ + +**Ask HN: How to Sell a Website** +https://news.ycombinator.com/item?id=28943611 + +**We analyzed 425k favicons** +https://iconmap.io/blog + +**Machu Picchu was built over major fault zones (2019)** +https://www.science.org/content/article/machu-picchu-was-built-over-major-fault-zones-now-researchers-think-they-know-why + +**Goggles: Democracy dies in darkness, and so does the Web [pdf]** +https://brave.com/wp-content/uploads/2021/03/goggles.pdf + +**Apple M1 Max Geekbench Score** +https://browser.geekbench.com/v5/cpu/10496766 + +**U.S. tightens export controls on items used in surveillance of private citizens** +https://www.commerce.gov/news/press-releases/2021/10/commerce-tightens-export-controls-items-used-surveillance-private + +**WeWork is trying to go public – again** +https://www.wsj.com/articles/wework-set-to-go-public-via-spac-deal-two-years-after-failed-ipo-11634808600 + +**Playstation 3 Architecture** +https://www.copetti.org/writings/consoles/playstation-3/ + +**About that time I had an outburst during the Y Combinator Interview** +https://owlpal.substack.com/p/about-that-time-i-had-an-outburst + +**One Man's Pest** +https://www.guernicamag.com/one-mans-pest/ + +**Brave Search replaces Google as default search engine in the Brave browser** +https://brave.com/search-and-web-discovery/ + +**I reverse engineered mcdonald's internal API** +https://twitter.com//rashiq/status/1319346264992026624 + +**Injury response to DNA damage in live tumor cells promotes antitumor immunity** +https://www.science.org/doi/10.1126/scisignal.abc4764 + +**India Counting Down to 1B Doses** +https://www.cowin.gov.in/ + +**Time to get worried about Tether, the “stablecoin†at center of cryptocurrency** +https://slate.com/technology/2021/10/tether-crypto-danger-ben-mckenzie.html + +**The History of Surveying** +https://www.alifewithoutlimits.com.au/the-history-of-surveying/ + +**The FDA wants you to be able to buy a hearing aid without a prescription** +https://www.npr.org/2021/10/19/1047303559/fda-hearing-aid-prescription-over-the-counter + +**Windows 11 will hobble gaming performance by default on some prebuilt PCs** +https://www.pcgamer.com/windows-11-pcs-can-hobble-gaming-performance/ + +**Development version: GIMP 2.99.8 Released** +https://www.gimp.org/news/2021/10/20/gimp-2-99-8-released/ + +**I couldn't debug the code because of my name** +https://mikolaj-kaminski.com/jetbrains-rider-docker-compose-unicodedecodeerror-issue-fix/ + +**Getting the best out of OpenSCAD** +https://calbryant.uk/blog/10-ways-to-get-the-best-out-of-openscad/ + +**Study: Recycled Lithium Batteries as Good as Newly Mined** +https://spectrum.ieee.org/recycled-batteries-good-as-newly-mined + +**Eliminating gifted programs won’t make education fair** +https://americasfuture.org/eliminating-gifted-programs-wont-make-education-fair/ + +**Gtk4 Tutorial** +https://github.com/ToshioCP/Gtk4-tutorial/blob/main/Readme.md + +**Cosmopolitan Identiï¬ers** +https://obua.com/publications/cosmo-id/3/ + +**A talk with Walter Bright about Empire** +https://madned.substack.com/p/a-talk-with-computer-gaming-pioneer + +**Bioelektryczność – Polish Robotics (1968) [video]** +https://www.youtube.com/watch?v=NjrYk546uBA + diff --git a/rushs/evalexpr/handling_complex/complex.c b/rushs/evalexpr/handling_complex/complex.c new file mode 100644 index 0000000..79a10be --- /dev/null +++ b/rushs/evalexpr/handling_complex/complex.c @@ -0,0 +1,51 @@ +#include "complex.h" + +#include <stdio.h> + +void print_complex(struct complex a) +{ + printf("complex(%.2f ", a.real); + + if (a.img < 0) + { + printf("- %.2fi", -a.img); + } + else + { + printf("+ %.2fi", a.img); + } + printf(")\n"); +} + +struct complex neg_complex(struct complex a) +{ + struct complex z = { -a.real, -a.img }; + return z; +} + +struct complex add_complex(struct complex a, struct complex b) +{ + struct complex z = { a.real + b.real, a.img + b.img }; + return z; +} + +struct complex sub_complex(struct complex a, struct complex b) +{ + return add_complex(a, neg_complex(b)); +} + +struct complex mul_complex(struct complex a, struct complex b) +{ + struct complex z = { a.real * b.real - a.img * b.img, + a.real * b.img + a.img * b.real }; + return z; +} + +struct complex div_complex(struct complex a, struct complex b) +{ + struct complex z = { + (a.real * b.real + a.img * b.img) / (b.real * b.real + b.img * b.img), + (a.img * b.real - a.real * b.img) / (b.real * b.real + b.img * b.img) + }; + return z; +} diff --git a/rushs/evalexpr/handling_complex/complex.h b/rushs/evalexpr/handling_complex/complex.h new file mode 100644 index 0000000..c562810 --- /dev/null +++ b/rushs/evalexpr/handling_complex/complex.h @@ -0,0 +1,20 @@ +#ifndef COMPLEX_H +#define COMPLEX_H + +struct complex +{ + float real; + float img; +}; + +// Print +void print_complex(struct complex a); + +// Operations +struct complex neg_complex(struct complex a); +struct complex add_complex(struct complex a, struct complex b); +struct complex sub_complex(struct complex a, struct complex b); +struct complex mul_complex(struct complex a, struct complex b); +struct complex div_complex(struct complex a, struct complex b); + +#endif /* !COMPLEX_H */ diff --git a/rushs/evalexpr/hanoi/hanoi.c b/rushs/evalexpr/hanoi/hanoi.c new file mode 100644 index 0000000..6ac2b71 --- /dev/null +++ b/rushs/evalexpr/hanoi/hanoi.c @@ -0,0 +1,31 @@ +#include <stdio.h> + +void move(unsigned src, unsigned spare, unsigned dst, unsigned n) +{ + if (n == 0) + { + return; + } + + move(src, dst, spare, n - 1); + + printf("%u->%u\n", src, dst); + + move(spare, src, dst, n - 1); +} + +void hanoi(unsigned n) +{ + if (n == 0) + { + return; + } + + move(1, 2, 3, n); +} + +int main(void) +{ + hanoi(3); + return 0; +} diff --git a/rushs/evalexpr/hash_map/hash.c b/rushs/evalexpr/hash_map/hash.c new file mode 100644 index 0000000..434616f --- /dev/null +++ b/rushs/evalexpr/hash_map/hash.c @@ -0,0 +1,13 @@ +#include <stddef.h> + +size_t hash(const char *key) +{ + size_t i = 0; + size_t hash = 0; + + for (i = 0; key[i] != '\0'; ++i) + hash += key[i]; + hash += i; + + return hash; +} diff --git a/rushs/evalexpr/hash_map/hash_map.c b/rushs/evalexpr/hash_map/hash_map.c new file mode 100644 index 0000000..4690e8b --- /dev/null +++ b/rushs/evalexpr/hash_map/hash_map.c @@ -0,0 +1,177 @@ +#include "hash_map.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct hash_map *hash_map_init(size_t size) +{ + struct hash_map *new; + if ((new = malloc(sizeof(struct hash_map))) == NULL) + { + return NULL; + } + if ((new->data = malloc(size * sizeof(struct pair_list *))) == NULL) + { + return NULL; + } + new->size = size; + + for (size_t i = 0; i < size; i++) + { + new->data[i] = NULL; + } + + return new; +} + +bool hash_map_insert(struct hash_map *hash_map, const char *key, char *value, + bool *updated) +{ + if (hash_map == NULL || updated == NULL || hash_map->size == 0) + { + return false; + } + *updated = false; + + size_t h = hash(key); + if (h >= hash_map->size) + { + h %= hash_map->size; + } + + struct pair_list *new = malloc(sizeof(struct pair_list)); + if (new == NULL) + { + return false; + } + + for (struct pair_list *p = hash_map->data[h]; p; p = p->next) + { + if (strcmp(p->key, key) == 0) + { + p->value = value; + *updated = true; + free(new); + return true; + } + } + + new->next = hash_map->data[h]; + new->key = key; + new->value = value; + hash_map->data[h] = new; + return true; +} + +void hash_map_free(struct hash_map *hash_map) +{ + if (hash_map == NULL) + { + return; + } + + if (hash_map->data == NULL) + { + free(hash_map); + return; + } + + for (size_t i = 0; i < hash_map->size; i++) + { + while (hash_map->data[i]) + { + struct pair_list *tmp = hash_map->data[i]->next; + free(hash_map->data[i]); + hash_map->data[i] = tmp; + } + } + + free(hash_map->data); + free(hash_map); +} + +void hash_map_dump(struct hash_map *hash_map) +{ + if (hash_map == NULL || hash_map->data == NULL) + { + return; + } + + for (size_t i = 0; i < hash_map->size; i++) + { + if (hash_map->data[i] != NULL) + { + printf("%s: %s", hash_map->data[i]->key, hash_map->data[i]->value); + for (struct pair_list *p = hash_map->data[i]->next; p; p = p->next) + { + printf(", %s: %s", p->key, p->value); + } + printf("\n"); + } + } +} + +const char *hash_map_get(const struct hash_map *hash_map, const char *key) +{ + if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) + { + return NULL; + } + + size_t h = hash(key); + if (h >= hash_map->size) + { + h %= hash_map->size; + } + struct pair_list *p; + for (p = hash_map->data[h]; p && strcmp(p->key, key) != 0; p = p->next) + { + continue; + } + + if (p) + { + return p->value; + } + return NULL; +} + +bool hash_map_remove(struct hash_map *hash_map, const char *key) +{ + if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) + { + return false; + } + + size_t h = hash(key); + if (h >= hash_map->size) + { + h %= hash_map->size; + } + if (hash_map->data[h] == NULL) + { + return false; + } + + if (strcmp(hash_map->data[h]->key, key) == 0) + { + struct pair_list *tmp = hash_map->data[h]->next; + free(hash_map->data[h]); + hash_map->data[h] = tmp; + return true; + } + + struct pair_list *p; + for (p = hash_map->data[h]; p->next; p = p->next) + { + if (strcmp(p->next->key, key) == 0) + { + struct pair_list *tmp = p->next->next; + free(p->next); + p->next = tmp; + return true; + } + } + return false; +} diff --git a/rushs/evalexpr/hash_map/hash_map.h b/rushs/evalexpr/hash_map/hash_map.h new file mode 100644 index 0000000..c731eab --- /dev/null +++ b/rushs/evalexpr/hash_map/hash_map.h @@ -0,0 +1,29 @@ +#ifndef HASH_MAP_H +#define HASH_MAP_H + +#include <stdbool.h> +#include <stddef.h> + +struct pair_list +{ + const char *key; + char *value; + struct pair_list *next; +}; + +struct hash_map +{ + struct pair_list **data; + size_t size; +}; + +size_t hash(const char *str); +struct hash_map *hash_map_init(size_t size); +bool hash_map_insert(struct hash_map *hash_map, const char *key, char *value, + bool *updated); +void hash_map_free(struct hash_map *hash_map); +void hash_map_dump(struct hash_map *hash_map); +const char *hash_map_get(const struct hash_map *hash_map, const char *key); +bool hash_map_remove(struct hash_map *hash_map, const char *key); + +#endif /* ! HASH_MAP_H */ diff --git a/rushs/evalexpr/heap/Makefile b/rushs/evalexpr/heap/Makefile new file mode 100644 index 0000000..2ed972b --- /dev/null +++ b/rushs/evalexpr/heap/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wvla -Wextra -std=c99 -pedantic +SRC = add.c del.c print.c pop.c create.c +OBJ = $(SRC:.c=.o) + +.PHONY: library clean + +library: $(OBJ) + ar csr libheap.a $(OBJ) + +$(OBJ): $(SRC) + +clean: + $(RM) libheap.a $(OBJ) diff --git a/rushs/evalexpr/heap/add.c b/rushs/evalexpr/heap/add.c new file mode 100644 index 0000000..78a4db8 --- /dev/null +++ b/rushs/evalexpr/heap/add.c @@ -0,0 +1,39 @@ +#include <stdlib.h> + +#include "heap.h" + +void heapify(int arr[], int n, int i) +{ + if (i == 0) + return; + int parent = (i - 1) / 2; + if (parent >= 0) + { + if (arr[i] > arr[parent]) + { + int tmp = arr[i]; + arr[i] = arr[parent]; + arr[parent] = tmp; + heapify(arr, n, parent); + } + } +} + +void add(struct heap *heap, int val) +{ + if (heap->size == heap->capacity) + { + heap->array = realloc(heap->array, heap->capacity * 2 * sizeof(int)); + if (heap->array == NULL) + { + free(heap); + return; + } + heap->capacity *= 2; + } + + heap->array[heap->size] = val; + heap->size++; + + heapify(heap->array, heap->size, heap->size - 1); +} diff --git a/rushs/evalexpr/heap/create.c b/rushs/evalexpr/heap/create.c new file mode 100644 index 0000000..f0675ad --- /dev/null +++ b/rushs/evalexpr/heap/create.c @@ -0,0 +1,19 @@ +#include <stdlib.h> + +#include "heap.h" + +struct heap *create_heap(void) +{ + struct heap *res = malloc(sizeof(struct heap)); + if (res == NULL) + return NULL; + res->size = 0; + res->capacity = 8; + res->array = malloc(8 * sizeof(int)); + if (res->array == NULL) + { + free(res); + return NULL; + } + return res; +} diff --git a/rushs/evalexpr/heap/del.c b/rushs/evalexpr/heap/del.c new file mode 100644 index 0000000..4d2ae35 --- /dev/null +++ b/rushs/evalexpr/heap/del.c @@ -0,0 +1,9 @@ +#include <stdlib.h> + +#include "heap.h" + +void delete_heap(struct heap *heap) +{ + free(heap->array); + free(heap); +} diff --git a/rushs/evalexpr/heap/heap.h b/rushs/evalexpr/heap/heap.h new file mode 100644 index 0000000..085f436 --- /dev/null +++ b/rushs/evalexpr/heap/heap.h @@ -0,0 +1,20 @@ +#ifndef HEAP_H +#define HEAP_H + +// size_t +#include <stddef.h> + +struct heap +{ + size_t size; + size_t capacity; + int *array; +}; + +struct heap *create_heap(void); +void add(struct heap *heap, int val); +int pop(struct heap *heap); +void delete_heap(struct heap *heap); +void print_heap(const struct heap *heap); + +#endif /* !HEAP_H */ diff --git a/rushs/evalexpr/heap/pop.c b/rushs/evalexpr/heap/pop.c new file mode 100644 index 0000000..55e063f --- /dev/null +++ b/rushs/evalexpr/heap/pop.c @@ -0,0 +1,49 @@ +#include <assert.h> +#include <stdlib.h> + +#include "heap.h" + +void heapify2(struct heap *h, size_t i) +{ + size_t max = i; + if (2 * i + 1 < h->size && h->array[2 * i + 1] > h->array[max]) + max = 2 * i + 1; + if (2 * i + 2 < h->size && h->array[2 * i + 2] > h->array[max]) + max = 2 * i + 2; + if (max != i) + { + int tmp = h->array[i]; + h->array[i] = h->array[max]; + h->array[max] = tmp; + heapify2(h, max); + } +} + +int pop(struct heap *heap) +{ + assert(heap->size != 0); + if (heap->size == 1) + { + heap->size--; + return heap->array[0]; + } + else + { + int res = heap->array[0]; + heap->array[0] = heap->array[heap->size - 1]; + heap->size--; + heapify2(heap, 0); + if (heap->size < heap->capacity / 2 && heap->capacity > 8) + { + heap->array = + realloc(heap->array, (heap->capacity / 2) * sizeof(int)); + if (heap->array == NULL) + { + free(heap); + return -1; + } + heap->capacity /= 2; + } + return res; + } +} diff --git a/rushs/evalexpr/heap/print.c b/rushs/evalexpr/heap/print.c new file mode 100644 index 0000000..f5bbe95 --- /dev/null +++ b/rushs/evalexpr/heap/print.c @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "heap.h" + +void print_rec(const struct heap *h, size_t i, int root) +{ + if (i >= h->size) + return; + if (!root) + printf(" "); + else + root = 0; + printf("%d", h->array[i]); + if (i == h->size - 1) + { + return; + } + print_rec(h, i * 2 + 1, root); + print_rec(h, i * 2 + 2, root); +} + +void print_heap(const struct heap *heap) +{ + print_rec(heap, 0, 1); + printf("\n"); +} diff --git a/rushs/evalexpr/hello_friends/hello.c b/rushs/evalexpr/hello_friends/hello.c new file mode 100644 index 0000000..63df2f1 --- /dev/null +++ b/rushs/evalexpr/hello_friends/hello.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +int main(int argc, char **argv) +{ + if (argc == 1) + printf("Hello World!\n"); + else + for (int i = 1; i < argc; i++) + { + printf("Hello %s!\n", argv[i]); + } + return 0; +} diff --git a/rushs/evalexpr/hello_world/hello.c b/rushs/evalexpr/hello_world/hello.c new file mode 100644 index 0000000..0681c18 --- /dev/null +++ b/rushs/evalexpr/hello_world/hello.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int main(void) +{ + puts("Hello World!"); + return 0; +} diff --git a/rushs/evalexpr/hello_world_shebang/hello.sh b/rushs/evalexpr/hello_world_shebang/hello.sh new file mode 100755 index 0000000..8dc4f64 --- /dev/null +++ b/rushs/evalexpr/hello_world_shebang/hello.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Hello World!" diff --git a/rushs/evalexpr/hill_array/hill_array.c b/rushs/evalexpr/hill_array/hill_array.c new file mode 100644 index 0000000..14d3a85 --- /dev/null +++ b/rushs/evalexpr/hill_array/hill_array.c @@ -0,0 +1,43 @@ +#include "hill_array.h" + +int top_of_the_hill(int tab[], size_t len) +{ + if (len == 0) + { + return -1; + } + + int top = 0; + size_t i = 0; + + while (i + 1 < len && tab[i] <= tab[i + 1]) + { + if (tab[i] < 0 || tab[i + 1] < 0) + { + return -1; + } + if (tab[i] != tab[i + 1]) + { + top = i + 1; + } + i++; + } + + while (i + 1 < len && tab[i] >= tab[i + 1]) + { + if (tab[i] < 0 || tab[i + 1] < 0) + { + return -1; + } + i++; + } + + if (i + 1 == len) + { + return top; + } + else + { + return -1; + } +} diff --git a/rushs/evalexpr/hill_array/hill_array.h b/rushs/evalexpr/hill_array/hill_array.h new file mode 100644 index 0000000..3152c19 --- /dev/null +++ b/rushs/evalexpr/hill_array/hill_array.h @@ -0,0 +1,8 @@ +#ifndef HILL_ARRAY_H +#define HILL_ARRAY_H + +#include <stddef.h> + +int top_of_the_hill(int tab[], size_t len); + +#endif /* !HILL_ARRAY_H */ diff --git a/rushs/evalexpr/insertion_sort/insertion_sort.c b/rushs/evalexpr/insertion_sort/insertion_sort.c new file mode 100644 index 0000000..2edd195 --- /dev/null +++ b/rushs/evalexpr/insertion_sort/insertion_sort.c @@ -0,0 +1,20 @@ +#include "insertion_sort.h" + +#include <stddef.h> + +void insertion_sort(void **array, f_cmp comp) +{ + if (array == NULL || *array == NULL) + { + return; + } + for (int i = 1; array[i]; i++) + { + for (int j = i; j > 0 && comp(array[j - 1], array[j]) > 0; j--) + { + void *tmp = array[j]; + array[j] = array[j - 1]; + array[j - 1] = tmp; + } + } +} diff --git a/rushs/evalexpr/insertion_sort/insertion_sort.h b/rushs/evalexpr/insertion_sort/insertion_sort.h new file mode 100644 index 0000000..a7ba674 --- /dev/null +++ b/rushs/evalexpr/insertion_sort/insertion_sort.h @@ -0,0 +1,8 @@ +#ifndef INSERTION_SORT_H +#define INSERTION_SORT_H + +typedef int (*f_cmp)(const void *, const void *); + +void insertion_sort(void **array, f_cmp comp); + +#endif /* ! INSERTION_SORT_H */ diff --git a/rushs/evalexpr/inside/inside.sh b/rushs/evalexpr/inside/inside.sh new file mode 100755 index 0000000..c6872fa --- /dev/null +++ b/rushs/evalexpr/inside/inside.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +if [ $# -ne 1 ]; then + echo Sorry, expected 1 argument but $# were passed + exit 1 +fi + +if [ -f $1 ]; then + cat $1 + exit 0 +else + echo "$1: + is not a valid file" + exit 2 +fi diff --git a/rushs/evalexpr/inside_noif/inside_noif.sh b/rushs/evalexpr/inside_noif/inside_noif.sh new file mode 100755 index 0000000..d4ed8c9 --- /dev/null +++ b/rushs/evalexpr/inside_noif/inside_noif.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +[ $# -ne 1 ] && echo Sorry, expected 1 argument but $# were passed && exit 1 + +[ -f $1 ] && cat $1 && exit 0 || echo "$1: + is not a valid file" && exit 2 diff --git a/rushs/evalexpr/int_palindrome/int_palindrome.c b/rushs/evalexpr/int_palindrome/int_palindrome.c new file mode 100644 index 0000000..6d6847f --- /dev/null +++ b/rushs/evalexpr/int_palindrome/int_palindrome.c @@ -0,0 +1,18 @@ +int int_palindrome(int n) +{ + if (n < 0) + { + return 0; + } + + int reversed = 0; + int m = n; + + while (m > 0) + { + reversed = reversed * 10 + m % 10; + m /= 10; + } + + return n == reversed; +} diff --git a/rushs/evalexpr/int_sqrt/int_sqrt.c b/rushs/evalexpr/int_sqrt/int_sqrt.c new file mode 100644 index 0000000..4b2e5db --- /dev/null +++ b/rushs/evalexpr/int_sqrt/int_sqrt.c @@ -0,0 +1,20 @@ +int int_sqrt(int n) +{ + if (n < 0) + { + return -1; + } + + if (n == 0 || n == 1) + { + return n; + } + + int i; + for (i = 1; i * i < n; i++) + { + continue; + } + + return i - (i * i != n); +} diff --git a/rushs/evalexpr/io_count_words/count_words.c b/rushs/evalexpr/io_count_words/count_words.c new file mode 100644 index 0000000..8b8c9a5 --- /dev/null +++ b/rushs/evalexpr/io_count_words/count_words.c @@ -0,0 +1,33 @@ +#include <stdio.h> + +int count_words(const char *file_in) +{ + if (file_in == NULL) + { + return -1; + } + + FILE *f = fopen(file_in, "r"); + if (f == NULL) + { + return -1; + } + + int word = 0; + int count = 0; + int c; + while ((c = fgetc(f)) != EOF) + { + if ((c == ' ' || c == '\n' || c == '\t') && word == 1) + { + word = 0; + } + if (c != ' ' && c != '\n' && c != '\t' && word == 0) + { + word = 1; + count++; + } + } + + return count; +} diff --git a/rushs/evalexpr/io_merge_files/merge_files.c b/rushs/evalexpr/io_merge_files/merge_files.c new file mode 100644 index 0000000..26ac9cf --- /dev/null +++ b/rushs/evalexpr/io_merge_files/merge_files.c @@ -0,0 +1,31 @@ +#define _POSIX_C_SOURCE 200809L + +#include <stdio.h> + +int merge_files(const char *file_1, const char *file_2) +{ + FILE *a = fopen(file_1, "a"); + if (a == NULL) + { + return -1; + } + FILE *r = fopen(file_2, "r"); + if (r == NULL) + { + return -1; + } + + int c; + while ((c = fgetc(r)) != EOF) + { + if (fputc(c, a) == EOF) + { + return -1; + } + } + + fclose(a); + fclose(r); + + return 0; +} diff --git a/rushs/evalexpr/io_replace_line/replace_line.c b/rushs/evalexpr/io_replace_line/replace_line.c new file mode 100644 index 0000000..7fd0e2a --- /dev/null +++ b/rushs/evalexpr/io_replace_line/replace_line.c @@ -0,0 +1,50 @@ +#define _POSIX_C_SOURCE 200809L + +#include <stdio.h> +#include <stdlib.h> + +int replace_line(const char *file_in, const char *file_out, const char *content, + int n) +{ + FILE *a = fopen(file_out, "w"); + if (a == NULL) + { + return -1; + } + FILE *r = fopen(file_in, "r"); + if (r == NULL) + { + return -1; + } + + char *buf = NULL; + ssize_t e; + int l = 0; + size_t count = 0; + while ((e = getline(&buf, &count, r)) != 0 && e != -1) + { + if (l == n) + { + if (fputs(content, a) == EOF) + { + free(buf); + return -1; + } + } + else + { + if (fputs(buf, a) == EOF) + { + free(buf); + return -1; + } + } + l++; + } + + fclose(a); + fclose(r); + free(buf); + + return 0; +} diff --git a/rushs/evalexpr/levenshtein/levenshtein.c b/rushs/evalexpr/levenshtein/levenshtein.c new file mode 100644 index 0000000..4da9397 --- /dev/null +++ b/rushs/evalexpr/levenshtein/levenshtein.c @@ -0,0 +1,72 @@ +#include "levenshtein.h" + +#include <stdio.h> + +size_t max(size_t a, size_t b) +{ + if (a >= b) + { + return a; + } + return b; +} + +size_t min(size_t a, size_t b) +{ + if (a <= b) + { + return a; + } + return b; +} + +size_t min_3(size_t a, size_t b, size_t c) +{ + if (a <= b) + { + if (a <= c) + { + return a; + } + return c; + } + else + { + if (b <= c) + { + return b; + } + return c; + } +} + +size_t my_strlen(const char *s) +{ + size_t i; + for (i = 0; s[i]; i++) + { + continue; + } + return i; +} + +size_t levenshtein(const char *s1, const char *s2) +{ + size_t l1 = my_strlen(s1); + size_t l2 = my_strlen(s2); + if (min(l1, l2) == 0) + { + return max(l1, l2); + } + + if (s1[0] == s2[0]) + { + return levenshtein(s1 + 1, s2 + 1); + } + + size_t lev1 = levenshtein(s1 + 1, s2); + size_t lev2 = levenshtein(s1, s2 + 1); + size_t lev3 = levenshtein(s1 + 1, s2 + 1); + + return 1 + min_3(lev1, lev2, lev3); +} diff --git a/rushs/evalexpr/levenshtein/levenshtein.h b/rushs/evalexpr/levenshtein/levenshtein.h new file mode 100644 index 0000000..70a5a7b --- /dev/null +++ b/rushs/evalexpr/levenshtein/levenshtein.h @@ -0,0 +1,8 @@ +#ifndef LEVENSHTEIN_H +#define LEVENSHTEIN_H + +#include <stddef.h> + +size_t levenshtein(const char *s1, const char *s2); + +#endif /* !LEVENSHTEIN_H */ diff --git a/rushs/evalexpr/main.c b/rushs/evalexpr/main.c new file mode 100644 index 0000000..4062426 --- /dev/null +++ b/rushs/evalexpr/main.c @@ -0,0 +1,15 @@ +#include <stdio.h> +#include <stdlib.h> + +//#include "traffic_lights/traffic_lights.h" +unsigned char rol(unsigned char value, unsigned char roll); + +int main(void) +{ + unsigned char l1 = 0b01010101; + unsigned char l2 = 3; + + printf("l1: %b", rol(l1, l2)); + + return 0; +} diff --git a/rushs/evalexpr/my_abs/my_abs.c b/rushs/evalexpr/my_abs/my_abs.c new file mode 100644 index 0000000..fc89d2f --- /dev/null +++ b/rushs/evalexpr/my_abs/my_abs.c @@ -0,0 +1,11 @@ +int my_abs(int n) +{ + if (n < 0) + { + return -n; + } + else + { + return n; + } +} diff --git a/rushs/evalexpr/my_atoi/my_atoi.c b/rushs/evalexpr/my_atoi/my_atoi.c new file mode 100644 index 0000000..ca185a5 --- /dev/null +++ b/rushs/evalexpr/my_atoi/my_atoi.c @@ -0,0 +1,61 @@ +#include "my_atoi.h" + +int my_atoi(const char *str) +{ + int res = 0; + + // str error check + if (str == NULL || *str == '0') + { + return 0; + } + + // trim whitespaces + for (; *str && *str == ' '; str++) + { + continue; + } + + // move to end of str + size_t l; + for (l = 0; str[l]; l++) + { + continue; + } + l--; + + // prepare for calculations + int factor = 1; + + // actual conversion of up to the second element of str (potential sign) + for (; l > 0; l--) + { + char val = str[l]; + if (val < '0' || val > '9') + { + return 0; + } + val -= '0'; + res += val * factor; + + factor *= 10; + } + + // l should be 0 by now + if (str[l] == '-') + { + return -res; + } + else if (str[l] != '+') + { + int val = str[l]; + if (val < '0' || val > '9') + { + return 0; + } + val -= '0'; + return res + val * factor; + } + + return res; +} diff --git a/rushs/evalexpr/my_atoi/my_atoi.h b/rushs/evalexpr/my_atoi/my_atoi.h new file mode 100644 index 0000000..b520d09 --- /dev/null +++ b/rushs/evalexpr/my_atoi/my_atoi.h @@ -0,0 +1,8 @@ +#ifndef MY_ATOI_H +#define MY_ATOI_H + +#include <stddef.h> + +int my_atoi(const char *str); + +#endif /* ! MY_ATOI_H */ diff --git a/rushs/evalexpr/my_atoi_base/my_atoi_base.c b/rushs/evalexpr/my_atoi_base/my_atoi_base.c new file mode 100644 index 0000000..46b4560 --- /dev/null +++ b/rushs/evalexpr/my_atoi_base/my_atoi_base.c @@ -0,0 +1,86 @@ +#include "my_atoi_base.h" + +int val_in_base(char c, const char *base) +{ + size_t i; + for (i = 0; base[i] && base[i] != c; i++) + { + continue; + } + + if (base[i]) + { + return i; + } + + return -1; +} + +int base_size(const char *base) +{ + int res; + for (res = 0; base[res]; res++) + { + continue; + } + return res; +} + +int my_atoi_base(const char *str, const char *base) +{ + int res = 0; + + // str error check + if (str == NULL || *str == '0') + { + return 0; + } + + // trim whitespaces + for (; *str && *str == ' '; str++) + { + continue; + } + + // move to end of str + size_t l; + for (l = 0; str[l]; l++) + { + continue; + } + l--; + + // prepare for calculations + int b = base_size(base); + int factor = 1; + + // actual conversion of up to the second element of str (potential sign) + for (; l > 0; l--) + { + int val = val_in_base(str[l], base); + if (val == -1) + { + return 0; + } + res += val * factor; + + factor *= b; + } + + // l should be 0 by now + if (str[l] == '-') + { + return -res; + } + else if (str[l] != '+') + { + int val = val_in_base(str[l], base); + if (val == -1) + { + return 0; + } + return res + val * factor; + } + + return res; +} diff --git a/rushs/evalexpr/my_atoi_base/my_atoi_base.h b/rushs/evalexpr/my_atoi_base/my_atoi_base.h new file mode 100644 index 0000000..296ae23 --- /dev/null +++ b/rushs/evalexpr/my_atoi_base/my_atoi_base.h @@ -0,0 +1,8 @@ +#ifndef MY_ATOI_BASE_H +#define MY_ATOI_BASE_H + +#include <stddef.h> + +int my_atoi_base(const char *str, const char *base); + +#endif /* ! MY_ATOI_BASE_H */ diff --git a/rushs/evalexpr/my_bc/my_bc.sh b/rushs/evalexpr/my_bc/my_bc.sh new file mode 100755 index 0000000..f675838 --- /dev/null +++ b/rushs/evalexpr/my_bc/my_bc.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +[ -n "$1" ] && echo "$(($1))" && exit 0 + +while IFS='' read -r line; do + [ -z "$line" ] && exit 0 || echo "$(($line))" +done diff --git a/rushs/evalexpr/my_c_tail/main.c b/rushs/evalexpr/my_c_tail/main.c new file mode 100644 index 0000000..ba33337 --- /dev/null +++ b/rushs/evalexpr/my_c_tail/main.c @@ -0,0 +1,10 @@ +#include <stdlib.h> + +#include "my_c_tail.h" + +int main(int argc, char *argv[]) +{ + if (argc > 1) + stdintail(atoi(argv[1])); + return 0; +} diff --git a/rushs/evalexpr/my_c_tail/my_c_tail.c b/rushs/evalexpr/my_c_tail/my_c_tail.c new file mode 100644 index 0000000..790240c --- /dev/null +++ b/rushs/evalexpr/my_c_tail/my_c_tail.c @@ -0,0 +1,46 @@ +#include "my_c_tail.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+void stdintail(unsigned int n)
+{
+ char **lines = calloc(2000, sizeof(char *));
+ lines[0] = malloc(350 * sizeof(char));
+ size_t m = 0;
+ char c;
+ size_t i = 0;
+ while (read(STDIN_FILENO, &c, 1))
+ {
+ if (c == '\n')
+ {
+ lines[m][i] = '\0';
+ lines[++m] = malloc(350 * sizeof(char));
+ i = 0;
+ }
+ else
+ {
+ lines[m][i++] = c;
+ }
+ }
+
+ size_t j;
+ if (m > n)
+ {
+ for (size_t i = 0; i < m - n; i++)
+ free(lines[i]);
+ j = m - n;
+ }
+ else
+ j = 0;
+
+ for (; j < m; j++)
+ {
+ for (size_t i = 0; lines[j][i]; i++)
+ write(STDOUT_FILENO, &(lines[j][i]), 1);
+ write(STDOUT_FILENO, "\n", 1);
+ free(lines[j]);
+ }
+ free(lines[m]);
+ free(lines);
+}
diff --git a/rushs/evalexpr/my_c_tail/my_c_tail.h b/rushs/evalexpr/my_c_tail/my_c_tail.h new file mode 100644 index 0000000..172c844 --- /dev/null +++ b/rushs/evalexpr/my_c_tail/my_c_tail.h @@ -0,0 +1,6 @@ +#ifndef MY_C_TAIL_H +#define MY_C_TAIL_H + +void stdintail(unsigned int n); + +#endif // MY_C_TAIL_H diff --git a/rushs/evalexpr/my_calloc/my_calloc.c b/rushs/evalexpr/my_calloc/my_calloc.c new file mode 100644 index 0000000..5a2f7f2 --- /dev/null +++ b/rushs/evalexpr/my_calloc/my_calloc.c @@ -0,0 +1,11 @@ +#include <stdlib.h> + +void *my_calloc(size_t n, size_t size) +{ + char *res = malloc(n * size); + for (size_t i = 0; i < n * size; i++) + { + res[i] = 0; + } + return res; +} diff --git a/rushs/evalexpr/my_calloc/my_calloc.h b/rushs/evalexpr/my_calloc/my_calloc.h new file mode 100644 index 0000000..44bf9a2 --- /dev/null +++ b/rushs/evalexpr/my_calloc/my_calloc.h @@ -0,0 +1,8 @@ +#ifndef MY_CALLOC_H +#define MY_CALLOC_H + +#include <stdlib.h> + +void *my_calloc(size_t n, size_t size); + +#endif /* ! MY_CALLOC_H */ diff --git a/rushs/evalexpr/my_file/my_file.sh b/rushs/evalexpr/my_file/my_file.sh new file mode 100755 index 0000000..93c0c20 --- /dev/null +++ b/rushs/evalexpr/my_file/my_file.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +for arg; do + if [ -f "$arg" ]; then + echo $arg: file + elif [ -d "$arg" ]; then + echo $arg: directory + else + echo $arg: unknown + fi +done diff --git a/rushs/evalexpr/my_first_variable/create.sh b/rushs/evalexpr/my_first_variable/create.sh new file mode 100755 index 0000000..d9264db --- /dev/null +++ b/rushs/evalexpr/my_first_variable/create.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +my_local_frais="Javotte" + +echo My frais is $my_local_frais diff --git a/rushs/evalexpr/my_first_variable/edit.sh b/rushs/evalexpr/my_first_variable/edit.sh new file mode 100755 index 0000000..e47e0c3 --- /dev/null +++ b/rushs/evalexpr/my_first_variable/edit.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +my_local_frais="Javotte" + +echo My frais is $my_local_frais + +my_local_frais="Pulpa" + +echo My frais is now $my_local_frais diff --git a/rushs/evalexpr/my_first_variable/use.sh b/rushs/evalexpr/my_first_variable/use.sh new file mode 100755 index 0000000..f9d462e --- /dev/null +++ b/rushs/evalexpr/my_first_variable/use.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "My frais is $MY_ENV_FRAIS" diff --git a/rushs/evalexpr/my_itoa/my_itoa.c b/rushs/evalexpr/my_itoa/my_itoa.c new file mode 100644 index 0000000..cbb6f73 --- /dev/null +++ b/rushs/evalexpr/my_itoa/my_itoa.c @@ -0,0 +1,38 @@ +#include "my_itoa.h" + +char *my_itoa(int value, char *s) +{ + if (value == 0) + { + s[0] = '0'; + s[1] = '\0'; + return s; + } + char *head = s; + if (value < 0) + { + s[0] = '-'; + s++; + value = -value; + } + + // count numbers + int t = value; + int n = 0; + while (t > 0) + { + t /= 10; + n++; + } + + // n = number count + s[n] = '\0'; + n--; + for (; n >= 0; n--) + { + s[n] = value % 10 + '0'; + value /= 10; + } + + return head; +} diff --git a/rushs/evalexpr/my_itoa/my_itoa.h b/rushs/evalexpr/my_itoa/my_itoa.h new file mode 100644 index 0000000..8e84c72 --- /dev/null +++ b/rushs/evalexpr/my_itoa/my_itoa.h @@ -0,0 +1,6 @@ +#ifndef MY_ITOA_H +#define MY_ITOA_H + +char *my_itoa(int value, char *s); + +#endif /* ! MY_ITOA_H */ diff --git a/rushs/evalexpr/my_itoa_base/my_itoa_base.c b/rushs/evalexpr/my_itoa_base/my_itoa_base.c new file mode 100644 index 0000000..29b3042 --- /dev/null +++ b/rushs/evalexpr/my_itoa_base/my_itoa_base.c @@ -0,0 +1,49 @@ +#include "my_itoa_base.h" + +int base_count(const char *base) +{ + int i; + for (i = 0; base[i]; i++) + { + continue; + } + return i; +} + +char *my_itoa_base(int n, char *s, const char *base) +{ + if (n == 0) + { + s[0] = base[0]; + s[1] = '\0'; + return s; + } + char *head = s; + if (n < 0) + { + s[0] = '-'; + s++; + n = -n; + } + + // count numbers + int t = n; + int m = 0; + int b = base_count(base); + while (t > 0) + { + t /= b; + m++; + } + + // n = number count + s[m] = '\0'; + m--; + for (; m >= 0; m--) + { + s[m] = base[n % b]; + n /= b; + } + + return head; +} diff --git a/rushs/evalexpr/my_itoa_base/my_itoa_base.h b/rushs/evalexpr/my_itoa_base/my_itoa_base.h new file mode 100644 index 0000000..0be6314 --- /dev/null +++ b/rushs/evalexpr/my_itoa_base/my_itoa_base.h @@ -0,0 +1,6 @@ +#ifndef MY_ITOA_BASE_H +#define MY_ITOA_BASE_H + +char *my_itoa_base(int n, char *s, const char *base); + +#endif /* ! MY_ITOA_BASE_H */ diff --git a/rushs/evalexpr/my_memcmp/my_memcmp.c b/rushs/evalexpr/my_memcmp/my_memcmp.c new file mode 100644 index 0000000..d498360 --- /dev/null +++ b/rushs/evalexpr/my_memcmp/my_memcmp.c @@ -0,0 +1,18 @@ +#include "my_memcmp.h" + +int my_memcmp(const void *s1, const void *s2, size_t num) +{ + if (num == 0) + { + return 0; + } + const unsigned char *a = s1; + const unsigned char *b = s2; + + for (; num - 1 && *a == *b; a++, b++, num--) + { + continue; + } + + return *a - *b; +} diff --git a/rushs/evalexpr/my_memcmp/my_memcmp.h b/rushs/evalexpr/my_memcmp/my_memcmp.h new file mode 100644 index 0000000..d17cbe6 --- /dev/null +++ b/rushs/evalexpr/my_memcmp/my_memcmp.h @@ -0,0 +1,8 @@ +#ifndef MY_MEMCMP_H +#define MY_MEMCMP_H + +#include <stddef.h> + +int my_memcmp(const void *s1, const void *s2, size_t num); + +#endif /* !MY_MEMCMP_H */ diff --git a/rushs/evalexpr/my_memcpy/my_memcpy.c b/rushs/evalexpr/my_memcpy/my_memcpy.c new file mode 100644 index 0000000..a6a48d4 --- /dev/null +++ b/rushs/evalexpr/my_memcpy/my_memcpy.c @@ -0,0 +1,28 @@ +#include "my_memcpy.h" + +void *my_memcpy(void *dest, const void *source, size_t num) +{ + char *d = dest; + const char *s = source; + if (dest > source) // reverse array + { + size_t l = num; + for (; l > 0; l--) + { + d[l - 1] = s[l - 1]; + } + } + else + { + for (size_t i = 0; i < num; i++) + { + d[i] = s[i]; + } + } + return dest; +} + +int main(void) +{ + return 0; +} diff --git a/rushs/evalexpr/my_memcpy/my_memcpy.h b/rushs/evalexpr/my_memcpy/my_memcpy.h new file mode 100644 index 0000000..bc1b926 --- /dev/null +++ b/rushs/evalexpr/my_memcpy/my_memcpy.h @@ -0,0 +1,8 @@ +#ifndef MY_MEMCPY_H +#define MY_MEMCPY_H + +#include <stddef.h> + +void *my_memcpy(void *dest, const void *source, size_t num); + +#endif /* ! MY_MEMCPY_H */ diff --git a/rushs/evalexpr/my_memmove/my_memmove.c b/rushs/evalexpr/my_memmove/my_memmove.c new file mode 100644 index 0000000..bb360a5 --- /dev/null +++ b/rushs/evalexpr/my_memmove/my_memmove.c @@ -0,0 +1,23 @@ +#include "my_memmove.h" + +void *my_memmove(void *dest, const void *src, size_t n) +{ + char *d = dest; + const char *s = src; + if (dest > src) // reverse array + { + size_t l = n; + for (; l > 0; l--) + { + d[l - 1] = s[l - 1]; + } + } + else + { + for (size_t i = 0; i < n; i++) + { + d[i] = s[i]; + } + } + return dest; +} diff --git a/rushs/evalexpr/my_memmove/my_memmove.h b/rushs/evalexpr/my_memmove/my_memmove.h new file mode 100644 index 0000000..cb253b7 --- /dev/null +++ b/rushs/evalexpr/my_memmove/my_memmove.h @@ -0,0 +1,8 @@ +#ifndef MY_MEMMOVE_H +#define MY_MEMMOVE_H + +#include <stddef.h> + +void *my_memmove(void *dest, const void *src, size_t n); + +#endif /* ! MY_MEMMOVE_H */ diff --git a/rushs/evalexpr/my_memset/my_memset.c b/rushs/evalexpr/my_memset/my_memset.c new file mode 100644 index 0000000..243a5ac --- /dev/null +++ b/rushs/evalexpr/my_memset/my_memset.c @@ -0,0 +1,12 @@ +#include "my_memset.h" + +void *my_memset(void *s, int c, size_t n) +{ + unsigned char *t = s; + for (size_t i = 0; i < n; i++) + { + t[i] = c; + } + + return t; +} diff --git a/rushs/evalexpr/my_memset/my_memset.h b/rushs/evalexpr/my_memset/my_memset.h new file mode 100644 index 0000000..e5ed0f0 --- /dev/null +++ b/rushs/evalexpr/my_memset/my_memset.h @@ -0,0 +1,6 @@ +#ifndef MY_MEMSET_H +#define MY_MEMSET_H + +#include <stddef.h> + +#endif /* ! MY_MEMSET_H */ diff --git a/rushs/evalexpr/my_pow/my_pow.c b/rushs/evalexpr/my_pow/my_pow.c new file mode 100644 index 0000000..f529d87 --- /dev/null +++ b/rushs/evalexpr/my_pow/my_pow.c @@ -0,0 +1,13 @@ +int my_pow(int a, int b) +{ + if (!a) + return b == 0; + int res = 1; + for (int i = 0; i < b / 2; i++) + { + res *= a * a; + } + if (b % 2) + res *= a; + return res; +} diff --git a/rushs/evalexpr/my_round/my_round.c b/rushs/evalexpr/my_round/my_round.c new file mode 100644 index 0000000..324bc1d --- /dev/null +++ b/rushs/evalexpr/my_round/my_round.c @@ -0,0 +1,6 @@ +int my_round(float n) +{ + if (n < 0) + return n - 0.5; + return n + 0.5; +} diff --git a/rushs/evalexpr/my_strcmp/my_strcmp.c b/rushs/evalexpr/my_strcmp/my_strcmp.c new file mode 100644 index 0000000..d3ef3e3 --- /dev/null +++ b/rushs/evalexpr/my_strcmp/my_strcmp.c @@ -0,0 +1,11 @@ +#include "my_strcmp.h" + +int my_strcmp(const char *s1, const char *s2) +{ + for (; *s1 && *s1 == *s2; s1++, s2++) + { + continue; + } + + return *s1 - *s2; +} diff --git a/rushs/evalexpr/my_strcmp/my_strcmp.h b/rushs/evalexpr/my_strcmp/my_strcmp.h new file mode 100644 index 0000000..d89a00b --- /dev/null +++ b/rushs/evalexpr/my_strcmp/my_strcmp.h @@ -0,0 +1,6 @@ +#ifndef MY_STRCMP_H +#define MY_STRCMP_H + +#include <stddef.h> + +#endif /* ! MY_STRCMP_H */ diff --git a/rushs/evalexpr/my_strcpy/my_strcpy.c b/rushs/evalexpr/my_strcpy/my_strcpy.c new file mode 100644 index 0000000..69ad5ee --- /dev/null +++ b/rushs/evalexpr/my_strcpy/my_strcpy.c @@ -0,0 +1,13 @@ +#include <stdlib.h> + +char *my_strcpy(char *dest, const char *source) +{ + size_t i; + for (i = 0; source[i]; i++) + { + dest[i] = source[i]; + } + dest[i] = '\0'; + + return dest; +} diff --git a/rushs/evalexpr/my_strlen/my_strlen.c b/rushs/evalexpr/my_strlen/my_strlen.c new file mode 100644 index 0000000..ec80d0b --- /dev/null +++ b/rushs/evalexpr/my_strlen/my_strlen.c @@ -0,0 +1,12 @@ +#include "my_strlen.h" + +size_t my_strlen(const char *s) +{ + size_t i; + for (i = 0; s[i]; i++) + { + continue; + } + + return i; +} diff --git a/rushs/evalexpr/my_strlen/my_strlen.h b/rushs/evalexpr/my_strlen/my_strlen.h new file mode 100644 index 0000000..02806cc --- /dev/null +++ b/rushs/evalexpr/my_strlen/my_strlen.h @@ -0,0 +1,6 @@ +#ifndef MY_STRLEN_H +#define MY_STRLEN_H + +#include <stddef.h> + +#endif /* ! MY_STRLEN_H */ diff --git a/rushs/evalexpr/my_strlowcase/my_strlowcase.c b/rushs/evalexpr/my_strlowcase/my_strlowcase.c new file mode 100644 index 0000000..e52ea32 --- /dev/null +++ b/rushs/evalexpr/my_strlowcase/my_strlowcase.c @@ -0,0 +1,13 @@ +#include "my_strlowcase.h" + +void my_strlowcase(char *s) +{ + size_t i; + for (i = 0; s[i]; i++) + { + if (s[i] >= 'A' && s[i] <= 'Z') + { + s[i] += ('a' - 'A'); + } + } +} diff --git a/rushs/evalexpr/my_strlowcase/my_strlowcase.h b/rushs/evalexpr/my_strlowcase/my_strlowcase.h new file mode 100644 index 0000000..d4996b8 --- /dev/null +++ b/rushs/evalexpr/my_strlowcase/my_strlowcase.h @@ -0,0 +1,8 @@ +#ifndef MY_STRLOWCASE_H +#define MY_STRLOWCASE_H + +#include <stddef.h> + +void my_strlowcase(char *str); + +#endif /* ! MY_STRLOWCASE_H */ diff --git a/rushs/evalexpr/my_strspn/my_strspn.c b/rushs/evalexpr/my_strspn/my_strspn.c new file mode 100644 index 0000000..18bba0f --- /dev/null +++ b/rushs/evalexpr/my_strspn/my_strspn.c @@ -0,0 +1,26 @@ +#include "my_strspn.h" + +int is_in(char c, const char *accept) +{ + for (; *accept && *accept != c; accept++) + { + continue; + } + return *accept != '\0'; +} + +size_t my_strspn(const char *s, const char *accept) +{ + if (s == NULL || *s == '\0') + { + return 0; + } + + size_t res; + for (res = 0; *s && is_in(*s, accept) != 0; res++, s++) + { + continue; + } + + return res; +} diff --git a/rushs/evalexpr/my_strspn/my_strspn.h b/rushs/evalexpr/my_strspn/my_strspn.h new file mode 100644 index 0000000..f2d7759 --- /dev/null +++ b/rushs/evalexpr/my_strspn/my_strspn.h @@ -0,0 +1,8 @@ +#ifndef MY_STRSPN_H +#define MY_STRSPN_H + +#include <stddef.h> + +size_t my_strspn(const char *s, const char *accept); + +#endif /* ! MY_STRSPN_H */ diff --git a/rushs/evalexpr/my_strstr/my_strstr.c b/rushs/evalexpr/my_strstr/my_strstr.c new file mode 100644 index 0000000..36ac439 --- /dev/null +++ b/rushs/evalexpr/my_strstr/my_strstr.c @@ -0,0 +1,34 @@ +#include "my_strstr.h" + +#include <stddef.h> + +int my_strstr(const char *haystack, const char *needle) +{ + if (needle == NULL || *needle == '\0') + { + return 0; + } + + for (int i = 0; haystack[i]; i++) + { + if (haystack[i] == needle[0]) + { + int j; + for (j = 0; + haystack[i + j] && needle[j] && needle[j] == haystack[i + j]; + j++) + { + continue; + } + if (needle[j] == '\0') + { + return i; + } + if (haystack[i + j] == '\0') + { + return -1; + } + } + } + return -1; +} diff --git a/rushs/evalexpr/my_strstr/my_strstr.h b/rushs/evalexpr/my_strstr/my_strstr.h new file mode 100644 index 0000000..1b734b2 --- /dev/null +++ b/rushs/evalexpr/my_strstr/my_strstr.h @@ -0,0 +1,6 @@ +#ifndef MY_STRSTR_H +#define MY_STRSTR_H + +int my_strstr(const char *haystack, const char *needle); + +#endif /* ! MY_STRSTR_H */ diff --git a/rushs/evalexpr/my_strtok_r/my_strtok_r.c b/rushs/evalexpr/my_strtok_r/my_strtok_r.c new file mode 100644 index 0000000..ec052b7 --- /dev/null +++ b/rushs/evalexpr/my_strtok_r/my_strtok_r.c @@ -0,0 +1,51 @@ +#include "my_strtok_r.h" + +#include <stddef.h> + +static int is_delim(char c, const char *delims) +{ + for (const char *d = delims; *d; d++) + { + if (*d == c) + return 1; + } + return 0; +} + +char *my_strtok_r(char *str, const char *delim, char **saveptr) +{ + if (str == NULL) + { + if (*saveptr == NULL) + { + return NULL; + } + str = *saveptr; + } + + size_t i = 0; + while (str[i] != '\0' && is_delim(str[i], delim)) + { + i++; + } + if (str[i] == '\0') + { + *saveptr = NULL; + return NULL; + } + + char *res = str + i; + + while (str[i] != '\0' && !is_delim(str[i], delim)) + { + i++; + } + if (str[i] == '\0') + { + *saveptr = NULL; + return res; + } + *saveptr = str + i + 1; + str[i] = '\0'; + return res; +} diff --git a/rushs/evalexpr/my_strtok_r/my_strtok_r.h b/rushs/evalexpr/my_strtok_r/my_strtok_r.h new file mode 100644 index 0000000..5603729 --- /dev/null +++ b/rushs/evalexpr/my_strtok_r/my_strtok_r.h @@ -0,0 +1,6 @@ +#ifndef MY_STRTOK_R_H +#define MY_STRTOK_R_H + +char *my_strtok_r(char *str, const char *delim, char **saveptr); + +#endif /* ! MY_STRTOK_R_H */ diff --git a/rushs/evalexpr/null_terminated_arrays/null_terminated_arrays.c b/rushs/evalexpr/null_terminated_arrays/null_terminated_arrays.c new file mode 100644 index 0000000..32d2a17 --- /dev/null +++ b/rushs/evalexpr/null_terminated_arrays/null_terminated_arrays.c @@ -0,0 +1,50 @@ +#include "null_terminated_arrays.h" + +#include <assert.h> +#include <stddef.h> +#include <stdio.h> + +void reverse_array(const char **arr) +{ + const char **p; + for (p = arr; *p; p++) + { + continue; + } + p--; + + while (p > arr) + { + const char *tmp = *p; + *p = *arr; + *arr = tmp; + arr++; + p--; + } +} + +void reverse_matrix(const char ***matrix) +{ + const char ***p; + for (p = matrix; *p; p++) + { + continue; + } + p--; + + while (p > matrix) + { + reverse_array(*p); + reverse_array(*matrix); + const char **tmp = *p; + *p = *matrix; + *matrix = tmp; + matrix++; + p--; + } + + if (p == matrix) + { + reverse_array(*matrix); + } +} diff --git a/rushs/evalexpr/null_terminated_arrays/null_terminated_arrays.h b/rushs/evalexpr/null_terminated_arrays/null_terminated_arrays.h new file mode 100644 index 0000000..31fccc5 --- /dev/null +++ b/rushs/evalexpr/null_terminated_arrays/null_terminated_arrays.h @@ -0,0 +1,6 @@ +#ifndef NULL_TERMINATED_ARRAYS_H_ +#define NULL_TERMINATED_ARRAYS_H_ + +void reverse_matrix(const char ***matrix); + +#endif /* !NULL_TERMINATED_ARRAYS_H_ */ diff --git a/rushs/evalexpr/number_digits_rec/number_digits_rec.c b/rushs/evalexpr/number_digits_rec/number_digits_rec.c new file mode 100644 index 0000000..94de296 --- /dev/null +++ b/rushs/evalexpr/number_digits_rec/number_digits_rec.c @@ -0,0 +1,8 @@ +unsigned int number_digits_rec(unsigned int n) +{ + if (n / 10 == 0) + { + return 1; + } + return 1 + number_digits_rec(n / 10); +} diff --git a/rushs/evalexpr/palindrome/palindrome.c b/rushs/evalexpr/palindrome/palindrome.c new file mode 100644 index 0000000..2ecacfd --- /dev/null +++ b/rushs/evalexpr/palindrome/palindrome.c @@ -0,0 +1,47 @@ +#include "palindrome.h" + +#include <stddef.h> + +int palindrome(const char *s) +{ + if (s == NULL) + { + return 0; + } + + if (*s == '\0') + { + return 1; + } + + const char *p = s; + while (*p) + { + p++; + } + p--; + + while (p > s) + { + while ((*p < '0' || (*p > '9' && *p < 'A') || (*p > 'Z' && *p < 'a') + || *p > 'z') + && p > s) + { + p--; + } + while ((*s < '0' || (*s > '9' && *s < 'A') || (*s > 'Z' && *s < 'a') + || *s > 'z') + && p > s) + { + s++; + } + if (*p != *s) + { + return 0; + } + p--; + s++; + } + + return 1; +} diff --git a/rushs/evalexpr/palindrome/palindrome.h b/rushs/evalexpr/palindrome/palindrome.h new file mode 100644 index 0000000..8595911 --- /dev/null +++ b/rushs/evalexpr/palindrome/palindrome.h @@ -0,0 +1,6 @@ +#ifndef PALINDROME_H +#define PALINDROME_H + +int palindrome(const char *s); + +#endif /* !PALINDROME_H */ diff --git a/rushs/evalexpr/pine/pine.c b/rushs/evalexpr/pine/pine.c new file mode 100644 index 0000000..9d48761 --- /dev/null +++ b/rushs/evalexpr/pine/pine.c @@ -0,0 +1,36 @@ +#include <stdio.h> + +int pine(unsigned n) +{ + if (n < 3) + { + return 1; + } + + for (unsigned i = 0; i < n; i++) + { + for (unsigned j = 0; j < n - i - 1; j++) + { + putchar(' '); + } + + for (unsigned j = 0; j < 2 * i + 1; j++) + { + putchar('*'); + } + + putchar('\n'); + } + + for (unsigned i = 0; i < n / 2; i++) + { + for (unsigned j = 0; j < n - 1; j++) + { + putchar(' '); + } + putchar('*'); + putchar('\n'); + } + + return 0; +} diff --git a/rushs/evalexpr/pointer_swap/pointer_swap.c b/rushs/evalexpr/pointer_swap/pointer_swap.c new file mode 100644 index 0000000..32ceb84 --- /dev/null +++ b/rushs/evalexpr/pointer_swap/pointer_swap.c @@ -0,0 +1,6 @@ +void pointer_swap(int **a, int **b) +{ + int *tmp = *a; + *a = *b; + *b = tmp; +} diff --git a/rushs/evalexpr/prototypes/prototypes.sh b/rushs/evalexpr/prototypes/prototypes.sh new file mode 100755 index 0000000..3c80468 --- /dev/null +++ b/rushs/evalexpr/prototypes/prototypes.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +sed -En 's/^(([a-zA-Z]* ){0,2}([a-zA-Z]*) *\**([a-z][a-z0-9_]*)\((([a-zA-Z]* )?([a-zA-Z]* )?([a-z][a-z0-9_]* *)(\**[a-z][a-z0-9_]*|[a-z][a-z0-9_]*\[([0-9][0-9]*)?\])(, ([a-zA-Z]* )?([a-zA-Z]* )?([a-z][a-z0-9_]* *)(\**[a-z][a-z0-9_]*|[a-z][a-z0-9_]*\[([0-9][0-9]*)?\])){0,3}|void)\))$/\1;/p' "$1" diff --git a/rushs/evalexpr/quick_sort/quick_sort.c b/rushs/evalexpr/quick_sort/quick_sort.c new file mode 100644 index 0000000..6c61fc3 --- /dev/null +++ b/rushs/evalexpr/quick_sort/quick_sort.c @@ -0,0 +1,18 @@ +#include <stddef.h> + +void quicksort(int *tab, size_t len) +{ + if (tab == NULL) + { + return; + } + for (size_t i = 1; i < len; i++) + { + for (size_t j = i; j > 0 && tab[j - 1] > tab[j]; j--) + { + int tmp = tab[j]; + tab[j] = tab[j - 1]; + tab[j - 1] = tmp; + } + } +} diff --git a/rushs/evalexpr/quick_sort/quick_sort_example.c b/rushs/evalexpr/quick_sort/quick_sort_example.c new file mode 100644 index 0000000..2a5228f --- /dev/null +++ b/rushs/evalexpr/quick_sort/quick_sort_example.c @@ -0,0 +1,19 @@ +#include <stdio.h> + +void quicksort(int *tab, int len); + +int main(void) +{ + unsigned i = 0; + int tab[] = { 10, 11, 2, 3, 8, 5, 7, 6, 26, 30, 2, 1, 17, 13, 14 }; + + unsigned size = sizeof(tab) / sizeof(int); + + quicksort(tab, size); + + for (; i < size - 1; ++i) + printf("%d ", tab[i]); + printf("%d\n", tab[i]); + + return 0; +} diff --git a/rushs/evalexpr/repeat/repeat.c b/rushs/evalexpr/repeat/repeat.c new file mode 100644 index 0000000..06d0b43 --- /dev/null +++ b/rushs/evalexpr/repeat/repeat.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +int main(int argc, char **argv) +{ + if (argc != 3) + return 1; + + for (int i = 0; i < argv[2][0] - '0'; i++) + puts(argv[1]); + return 0; +} diff --git a/rushs/evalexpr/right_tarball/my_tarball.tar.gz b/rushs/evalexpr/right_tarball/my_tarball.tar.gz Binary files differnew file mode 100644 index 0000000..eb6acfc --- /dev/null +++ b/rushs/evalexpr/right_tarball/my_tarball.tar.gz diff --git a/rushs/evalexpr/rotx/rotx.c b/rushs/evalexpr/rotx/rotx.c new file mode 100644 index 0000000..a2cb820 --- /dev/null +++ b/rushs/evalexpr/rotx/rotx.c @@ -0,0 +1,59 @@ +#include <stdlib.h> +#include <unistd.h> + +#define BUFFER_SIZE 10 + +int main(int argc, char **argv) +{ + if (argc != 2) + { + return 0; + } + + int rot = atoi(argv[1]); + int rod = rot; + if (rot < 0) + { + rot = (rot % 26) + 26; + rod = (rod % 10) + 10; + } + + char buf[BUFFER_SIZE]; + ssize_t r; + + while ((r = read(STDIN_FILENO, buf, BUFFER_SIZE))) + { + if (r == -1) + { + return 1; + } + + for (ssize_t i = 0; i < r; i++) + { + if (buf[i] >= 'a' && buf[i] <= 'z') + { + buf[i] = ((buf[i] - 'a') + rot) % 26 + 'a'; + } + else if (buf[i] >= 'A' && buf[i] <= 'Z') + { + buf[i] = ((buf[i] - 'A') + rot) % 26 + 'A'; + } + else if (buf[i] >= '0' && buf[i] <= '9') + { + buf[i] = ((buf[i] - '0') + rod) % 10 + '0'; + } + } + + ssize_t w = write(STDOUT_FILENO, buf, r); + while (w != r) + { + w += write(STDOUT_FILENO, buf, r); + if (w == -1) + { + return 1; + } + } + } + + return 0; +} diff --git a/rushs/evalexpr/sed_trailing_whitespaces/whitespaces.sed b/rushs/evalexpr/sed_trailing_whitespaces/whitespaces.sed new file mode 100644 index 0000000..46b7017 --- /dev/null +++ b/rushs/evalexpr/sed_trailing_whitespaces/whitespaces.sed @@ -0,0 +1 @@ +s/[ \t]*$// diff --git a/rushs/evalexpr/selection_sort/selection_sort.c b/rushs/evalexpr/selection_sort/selection_sort.c new file mode 100644 index 0000000..98adc7e --- /dev/null +++ b/rushs/evalexpr/selection_sort/selection_sort.c @@ -0,0 +1,30 @@ +#include <stddef.h> + +void swap(int *a, int *b) +{ + int tmp = *a; + *a = *b; + *b = tmp; +} + +unsigned array_min(const int arr[], unsigned start, unsigned size) +{ + unsigned min = start; + for (; start < size; start++) + { + if (arr[min] > arr[start]) + { + min = start; + } + } + return min; +} + +void selection_sort(int arr[], unsigned size) +{ + for (size_t i = 0; i < size; i++) + { + unsigned j = array_min(arr, i, size); + swap(&(arr[i]), &(arr[j])); + } +} diff --git a/rushs/evalexpr/seq/seq.sh b/rushs/evalexpr/seq/seq.sh new file mode 100755 index 0000000..9721432 --- /dev/null +++ b/rushs/evalexpr/seq/seq.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +if [ $# -ne 3 ]; then + echo "Usage: ./seq.sh FIRST INCREMENT LAST" 1>&2 + exit 1 +fi + +if [ "$2" -eq 0 ]; then + exit 1 +fi + +if [ "$1" -eq "$3" ]; then + echo "$1" + exit 0 +fi + +if [ "$1" -lt "$3" ]; then + [ 0 -gt "$2" ] && exit 1 + i="$1" + while [ "$3" -ge "$i" ]; do + echo "$i" + i=$(($i + $2)) + done + exit 0 +fi + +[ "$2" -gt 0 ] && exit 1 +i="$1" +while [ "$i" -ge "$3" ]; do + echo "$i" + i=$(($i + $2)) +done +exit 0 diff --git a/rushs/evalexpr/sieve_eratosthenes_advanced/Makefile b/rushs/evalexpr/sieve_eratosthenes_advanced/Makefile new file mode 100644 index 0000000..c7e35f9 --- /dev/null +++ b/rushs/evalexpr/sieve_eratosthenes_advanced/Makefile @@ -0,0 +1,13 @@ +CC=gcc +CFLAGS=-std=c99 -Wall -Wextra -Werror -Wvla -pedantic +LDLIBS= + +all: sieve.o + +sieve.o: sieve.c + $(CC) $(CFLAGS) -c -o sieve.o sieve.c + +.PHONY: clean + +clean: + rm sieve.o diff --git a/rushs/evalexpr/sieve_eratosthenes_advanced/sieve.c b/rushs/evalexpr/sieve_eratosthenes_advanced/sieve.c new file mode 100644 index 0000000..7dd4816 --- /dev/null +++ b/rushs/evalexpr/sieve_eratosthenes_advanced/sieve.c @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <stdlib.h> + +void sieve(int n) +{ + if (n <= 2) + { + return; + } + + // Generate array + int *a = calloc(n, sizeof(int)); + int count = 0; + + // Actual sieve and count + for (int i = 2; i < n; i++) + { + if (a[i] == 0) + { + for (int k = 2 * i; k < n; k += i) + { + a[k] = 1; + } + } + } + + for (int i = 2; i < n; i++) + { + if (a[i] == 0) + { + count++; + } + } + + // Print the count + printf("%d\n", count); + + free(a); +} diff --git a/rushs/evalexpr/simple_fnmatch/simple_fnmatch.c b/rushs/evalexpr/simple_fnmatch/simple_fnmatch.c new file mode 100644 index 0000000..d40353f --- /dev/null +++ b/rushs/evalexpr/simple_fnmatch/simple_fnmatch.c @@ -0,0 +1,46 @@ +#include "simple_fnmatch.h" + +int simple_fnmatch(const char *pattern, const char *string) +{ + if (!pattern || !string) + return FNM_NOMATCH; + if (*pattern == '*' && pattern[1] == '\0') + return 0; + while (*pattern && *string) + { + if (*pattern == '?') + { + pattern++; + string++; + } + else if (*pattern == '\\') + { + pattern++; + if (!pattern || *pattern != *string) + return FNM_NOMATCH; + string++; + pattern++; + } + else if (*pattern == '*') + { + pattern++; + while (*string && simple_fnmatch(pattern, string)) + string++; + if (*string) + return 0; + } + else if (*pattern != *string) + return FNM_NOMATCH; + else + { + string++; + pattern++; + } + } + + if (*pattern == '*' && pattern[1] == '\0') + return 0; + if (*string || *pattern) + return FNM_NOMATCH; + return 0; +} diff --git a/rushs/evalexpr/simple_fnmatch/simple_fnmatch.h b/rushs/evalexpr/simple_fnmatch/simple_fnmatch.h new file mode 100644 index 0000000..e1ae166 --- /dev/null +++ b/rushs/evalexpr/simple_fnmatch/simple_fnmatch.h @@ -0,0 +1,8 @@ +#ifndef SIMPLE_FNMATCH_H +#define SIMPLE_FNMATCH_H + +#define FNM_NOMATCH 1 + +int simple_fnmatch(const char *pattern, const char *string); + +#endif /* !SIMPLE_FNMATCH_H */ diff --git a/rushs/evalexpr/stack/stack.c b/rushs/evalexpr/stack/stack.c new file mode 100644 index 0000000..0498abc --- /dev/null +++ b/rushs/evalexpr/stack/stack.c @@ -0,0 +1,30 @@ +#include "stack.h" + +#include <stdlib.h> + +struct stack *stack_push(struct stack *s, int e) +{ + struct stack *new = malloc(sizeof(struct stack)); + new->data = e; + new->next = NULL; + + new->next = s; + return new; +} + +struct stack *stack_pop(struct stack *s) +{ + if (s == NULL) + { + return NULL; + } + + struct stack *res = s->next; + free(s); + return res; +} + +int stack_peek(struct stack *s) +{ + return s->data; +} diff --git a/rushs/evalexpr/stack/stack.h b/rushs/evalexpr/stack/stack.h new file mode 100644 index 0000000..bd5dd24 --- /dev/null +++ b/rushs/evalexpr/stack/stack.h @@ -0,0 +1,14 @@ +#ifndef STACK_H +#define STACK_H + +struct stack +{ + int data; + struct stack *next; +}; + +struct stack *stack_push(struct stack *s, int e); +struct stack *stack_pop(struct stack *s); +int stack_peek(struct stack *s); + +#endif /* !STACK_H */ diff --git a/rushs/evalexpr/str_revert/str_revert.c b/rushs/evalexpr/str_revert/str_revert.c new file mode 100644 index 0000000..31f7f3d --- /dev/null +++ b/rushs/evalexpr/str_revert/str_revert.c @@ -0,0 +1,25 @@ +#include "str_revert.h" + +#include <stddef.h> + +void str_revert(char str[]) +{ + if (*str == '\0') + { + return; + } + + size_t len = 0; + for (; str[len]; len++) + { + continue; + } + len--; + + for (size_t i = 0; i <= len / 2; i++) + { + char tmp = str[i]; + str[i] = str[len - i]; + str[len - i] = tmp; + } +} diff --git a/rushs/evalexpr/str_revert/str_revert.h b/rushs/evalexpr/str_revert/str_revert.h new file mode 100644 index 0000000..daa23d4 --- /dev/null +++ b/rushs/evalexpr/str_revert/str_revert.h @@ -0,0 +1,6 @@ +#ifndef STR_REVERT_H +#define STR_REVERT_H + +void str_revert(char str[]); + +#endif /* ! STR_REVERT_H */ diff --git a/rushs/evalexpr/test.txt b/rushs/evalexpr/test.txt new file mode 100644 index 0000000..958cdbc --- /dev/null +++ b/rushs/evalexpr/test.txt @@ -0,0 +1,3 @@ +This is a short line. +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +This is another short line. diff --git a/rushs/evalexpr/test_a_bit/is_set.c b/rushs/evalexpr/test_a_bit/is_set.c new file mode 100644 index 0000000..38fccf8 --- /dev/null +++ b/rushs/evalexpr/test_a_bit/is_set.c @@ -0,0 +1,6 @@ +#include "is_set.h" + +unsigned int is_set(unsigned int value, unsigned char n) +{ + return (value & (1 << (n - 1))) != 0; +} diff --git a/rushs/evalexpr/test_a_bit/is_set.h b/rushs/evalexpr/test_a_bit/is_set.h new file mode 100644 index 0000000..8f2fd9a --- /dev/null +++ b/rushs/evalexpr/test_a_bit/is_set.h @@ -0,0 +1,6 @@ +#ifndef IS_SET_H +#define IS_SET_H + +unsigned int is_set(unsigned int value, unsigned char n); + +#endif /* ! IS_SET_H */ diff --git a/rushs/evalexpr/test_a_bit/test.c b/rushs/evalexpr/test_a_bit/test.c new file mode 100644 index 0000000..e3403e4 --- /dev/null +++ b/rushs/evalexpr/test_a_bit/test.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +#include "is_set.h" + +int main(void) +{ + printf("%d\n", is_set(24, 4)); + printf("%d\n", is_set(24, 3)); + + return 0; +} diff --git a/rushs/evalexpr/tinylibstream/Makefile b/rushs/evalexpr/tinylibstream/Makefile new file mode 100644 index 0000000..b060495 --- /dev/null +++ b/rushs/evalexpr/tinylibstream/Makefile @@ -0,0 +1,13 @@ +CC = gcc +CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla + +.PHONY: library clean + +library: src/tinylibstream.o + ar csr libstream.a src/tinylibstream.o + +clean: + rm libstream.a src/tinylibstream.o + +check: + $(CC) $(CFLAGS) -lcriterion src/tinylibstream.c tests/tests.c diff --git a/rushs/evalexpr/tinylibstream/include/libstream.h b/rushs/evalexpr/tinylibstream/include/libstream.h new file mode 100644 index 0000000..459432d --- /dev/null +++ b/rushs/evalexpr/tinylibstream/include/libstream.h @@ -0,0 +1,167 @@ +#ifndef LIBSTREAM_H +#define LIBSTREAM_H + +#include <fcntl.h> +#include <stdbool.h> +#include <stddef.h> +#include <unistd.h> + +/* +** /!\ DO NOT MODIFY THIS FILE, AS IT WILL BE OVERRIDDEN DURING CORRECTION. /!\ +** +** You can add your own functions declarations to OTHER HEADER FILES. +*/ + +/* the value returned when end of file is reached */ +#define LBS_EOF (-1) + +/* the size of the buffer */ +#define LBS_BUFFER_SIZE 32 + +/* +** Describes the current operation: +** - if reading, the buffer contains read-buffered data +** - if writing, the buffer contains write-buffered data +*/ +enum stream_io_operation +{ + STREAM_READING = 0, + STREAM_WRITING, +}; + +/* +** Controls when to flush the buffer: +** - when unbuffered, flush every time a character is written +** - when buffered, flush when the buffer is full +** - when line buffered, flush when the buffer is full or when a \n +** character is written +*/ +enum stream_buffering +{ + STREAM_UNBUFFERED = 0, + STREAM_LINE_BUFFERED, + STREAM_BUFFERED, +}; + +struct stream +{ + /* the flags passed to open */ + int flags; + + /* + ** Initially, this variable is 0. + ** When a function such as fgetc fails, it is set to 1 to indicate + ** something went wrong. This is useful to make the difference between + ** reaching the end of file and read errors while using fgetc and + ** some others. + ** It is often referred to as the error indicator. + */ + int error; + + /* the file descriptor, as returned by open(2) */ + int fd; + + /* + ** the kind of data stored by the buffer. + ** The default value shouldn't matter. + */ + enum stream_io_operation io_operation; + + /* + ** defines when to flush **output**. + ** This field does not control input buffering (which is always fully + ** buffered). + ** + ** The default value is LINE_BUFFERED if isatty(fd), BUFFERED otherwise. + */ + enum stream_buffering buffering_mode; + + /* the amount of used bytes in the buffer */ + size_t buffered_size; + + /* + ** /!\ This field only makes sense when io_operation is STREAM_READING /!\ + ** the amount of data already read from the buffer by the user. + */ + size_t already_read; + + /* + ** buffer + ** --------------> + ** +==============+====================+---------------------+ + ** | already_read | remaining_buffered | unused_buffer_space | + ** +==============+====================+---------------------+ + ** \_______________________________/ + ** buffered_size + ** + ** /!\ The buffer can contain either read-buffered or write-buffered data, + ** depending on the value of io_operation /!\ + */ + char buffer[LBS_BUFFER_SIZE]; +}; + +/* +** These functions are defined in a header for optimization reasons: +** each .c file that includes this header will get its own copy of the +** function's code, thus easily make optimizations. +** +** ``static`` means each compilation unit (.c file) will have its own copy +** of the function without them clashing. +** +** ``inline`` means the content of the function should be "copy pasted" +** where it's called. It also tells the compiler not to complain when the +** function isn't used. +** +** They're just like a macro, except the type of arguments is checked. +*/ + +static inline size_t stream_remaining_buffered(struct stream *stream) +{ + return stream->buffered_size - stream->already_read; +} + +static inline size_t stream_unused_buffer_space(struct stream *stream) +{ + return sizeof(stream->buffer) - stream->buffered_size; +} + +static inline bool stream_readable(struct stream *stream) +{ + int access_mode = stream->flags & O_ACCMODE; + if (access_mode == O_RDWR) + return true; + return access_mode == O_RDONLY; +} + +static inline bool stream_writable(struct stream *stream) +{ + int access_mode = stream->flags & O_ACCMODE; + if (access_mode == O_RDWR) + return true; + return access_mode == O_WRONLY; +} + +static inline int lbs_ferror(struct stream *stream) +{ + return stream->error; +} + +static inline void lbs_clearerr(struct stream *stream) +{ + stream->error = 0; +} + +static inline void lbs_setbufmode(struct stream *stream, + enum stream_buffering mode) +{ + stream->buffering_mode = mode; +} + +struct stream *lbs_fopen(const char *path, const char *mode); +struct stream *lbs_fdopen(int fd, const char *mode); +int lbs_fflush(struct stream *stream); +int lbs_fclose(struct stream *stream); +int lbs_fputc(int c, struct stream *stream); +int lbs_fgetc(struct stream *stream); + +#endif /* !LIBSTREAM_H */ diff --git a/rushs/evalexpr/tinylibstream/src/tinylibstream.c b/rushs/evalexpr/tinylibstream/src/tinylibstream.c new file mode 100644 index 0000000..dca1c01 --- /dev/null +++ b/rushs/evalexpr/tinylibstream/src/tinylibstream.c @@ -0,0 +1,221 @@ +#include <stdlib.h> +#include <string.h> + +#include "../include/libstream.h" + +int get_flags(const char *mode) +{ + int flags; + if (strcmp(mode, "r") == 0) + { + flags = O_RDONLY; + } + else if (strcmp(mode, "r+") == 0) + { + flags = O_RDWR; + } + else if (strcmp(mode, "w") == 0) + { + flags = O_WRONLY | O_TRUNC | O_CREAT; + } + else + { + flags = O_RDWR | O_TRUNC | O_CREAT; + } + + return flags; +} + +struct stream *lbs_fopen(const char *path, const char *mode) +{ + int fd = open(path, get_flags(mode)); + + return lbs_fdopen(fd, mode); +} + +struct stream *lbs_fdopen(int fd, const char *mode) +{ + if (fd == -1) + { + return NULL; + } + + struct stream *s = malloc(sizeof(struct stream)); + if (s == NULL) + { + return NULL; + } + + s->flags = get_flags(mode); + s->error = 0; + s->fd = fd; + if (isatty(fd)) + { + s->buffering_mode = STREAM_LINE_BUFFERED; + } + else + { + s->buffering_mode = STREAM_BUFFERED; + } + s->buffered_size = 0; + s->already_read = 0; + + return s; +} + +int lbs_fflush(struct stream *stream) +{ + if (stream == NULL || stream->buffered_size == 0) + { + return 0; + } + + if (stream->io_operation == STREAM_READING) + { + if (!stream_readable(stream)) + { + stream->error = 1; + return LBS_EOF; + } + if (stream_remaining_buffered(stream) != 0 + && lseek(stream->fd, -stream_remaining_buffered(stream), SEEK_CUR) + == -1) + { + stream->error = 1; + return LBS_EOF; + } + stream->buffered_size = 0; + stream->already_read = 0; + } + else + { + if (!stream_writable(stream)) + { + stream->error = 1; + return LBS_EOF; + } + ssize_t w; + if ((w = write(stream->fd, stream->buffer, stream->buffered_size)) + == -1) + { + stream->error = 1; + return LBS_EOF; + } + stream->buffered_size = 0; + stream->already_read = 0; + } + return 0; +} + +int lbs_fclose(struct stream *stream) +{ + if (stream == NULL) + { + return 1; + } + + lbs_fflush(stream); + if (close(stream->fd) == -1) + { + return 1; + } + + free(stream); + + return 0; +} + +int lbs_fputc(int c, struct stream *stream) +{ + if (!stream_writable(stream)) + { + stream->error = 1; + return -1; + } + + if (stream->io_operation == STREAM_READING) + { + if (lbs_fflush(stream) != 0) + { + return -1; + } + stream->buffered_size = 0; + stream->already_read = 0; + } + stream->io_operation = STREAM_WRITING; + + if (stream_unused_buffer_space(stream) == 0 + || stream->buffering_mode == STREAM_UNBUFFERED) + { + if (lbs_fflush(stream) != 0) + { + return -1; + } + } + + stream->buffer[stream->buffered_size] = c; + stream->buffered_size++; + if (stream_unused_buffer_space(stream) == 0 + || stream->buffering_mode == STREAM_UNBUFFERED + || (stream->buffering_mode == STREAM_LINE_BUFFERED && c == '\n')) + { + if (lbs_fflush(stream) != 0) + { + return -1; + } + } + + return c; +} + +int refill_buffer(struct stream *stream) +{ + stream->already_read = 0; + ssize_t r; + if ((r = read(stream->fd, stream->buffer, LBS_BUFFER_SIZE)) == -1) + { + stream->error = 1; + return -1; + } + if (r == 0) + { + return -1; + } + stream->buffered_size = r; + return r; +} + +int lbs_fgetc(struct stream *stream) +{ + if (!stream_readable(stream)) + { + stream->error = 1; + return -1; + } + if (stream->io_operation == STREAM_WRITING) + { + if (lbs_fflush(stream) != 0) + { + stream->error = 1; + return -1; + } + stream->already_read = 0; + } + stream->io_operation = STREAM_READING; + + if (stream_remaining_buffered(stream) == 0) + { + int r; + if ((r = refill_buffer(stream)) == -1) + { + stream->error = 1; + return -1; + } + } + + int res = stream->buffer[stream->already_read++]; + + unsigned char c = res; + + return c; +} diff --git a/rushs/evalexpr/tinylibstream/stdin_buffering_test.c b/rushs/evalexpr/tinylibstream/stdin_buffering_test.c new file mode 100644 index 0000000..6d3361b --- /dev/null +++ b/rushs/evalexpr/tinylibstream/stdin_buffering_test.c @@ -0,0 +1,70 @@ +#define _GNU_SOURCE +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +struct slow_cookie +{ + int fd; +}; + +static ssize_t slow_read(void *vcookie, char *buf, size_t count) +{ + struct slow_cookie *cookie = vcookie; + usleep(500000); // sleep for half of a second + + ssize_t res; + + while ((res = read(cookie->fd, buf, count)) < 0) + if (errno != EINTR && errno != EAGAIN) + break; + + return res; +} + +static int slow_close(void *vcookie) +{ + struct slow_cookie *cookie = vcookie; + return close(cookie->fd); +} + +cookie_io_functions_t slow_stdio = { + .read = slow_read, + .close = slow_close, +}; + +int main(void) +{ + /* setup a custom stdin stream with a slow read function */ + struct slow_cookie cookie = { + .fd = STDIN_FILENO, + }; + + FILE *input_stream = fopencookie(&cookie, "r", slow_stdio); + + /* change the buffer size to the one given by stdbuf. + ** it doesn't work out of the box as stdbuf only does + ** this for the already existing stdin stream. + */ + char *buffer = NULL; + char *buffer_size = getenv("_STDBUF_I"); + if (buffer_size) + { + size_t size = atoi(buffer_size); + buffer = malloc(size); + setvbuf(input_stream, buffer, _IOFBF, size); + } + + /* forward all characters from stdin to stdout */ + int c; + while ((c = fgetc(input_stream)) != EOF) + { + fputc(c, stdout); + fflush(stdout); + } + + fclose(input_stream); + free(buffer); + return 0; +} diff --git a/rushs/evalexpr/tinylibstream/stdout_buffering_test.c b/rushs/evalexpr/tinylibstream/stdout_buffering_test.c new file mode 100644 index 0000000..45c0a83 --- /dev/null +++ b/rushs/evalexpr/tinylibstream/stdout_buffering_test.c @@ -0,0 +1,13 @@ +#define _XOPEN_SOURCE 500 +#include <stdio.h> +#include <unistd.h> + +int main(void) +{ + const char test_string[] = "Robin\nloves\nBatman\n"; + for (size_t i = 0; test_string[i]; i++) + { + usleep(100000); // wait a tenth of a second + putchar(test_string[i]); + } +} diff --git a/rushs/evalexpr/tinyprintf/Makefile b/rushs/evalexpr/tinyprintf/Makefile new file mode 100644 index 0000000..6a07d90 --- /dev/null +++ b/rushs/evalexpr/tinyprintf/Makefile @@ -0,0 +1,17 @@ +CC=gcc +CFLAGS=-std=c99 -Wall -Wextra -Werror -Wvla -pedantic +LDLIBS=-lcriterion + +all: src/tinyprintf.o + +check: src/tinyprintf.o + $(CC) $(CFLAGS) -o tinytests src/tinyprintf.o tests/tests.c $(LDLIBS) + ./tinytests + +src/tinyprintf.o: src/tinyprintf.c + $(CC) $(CFLAGS) -c -o src/tinyprintf.o src/tinyprintf.c + +.PHONY: clean + +clean: + rm src/tinyprintf.o tinytests diff --git a/rushs/evalexpr/tinyprintf/src/tinyprintf.c b/rushs/evalexpr/tinyprintf/src/tinyprintf.c new file mode 100644 index 0000000..d005db7 --- /dev/null +++ b/rushs/evalexpr/tinyprintf/src/tinyprintf.c @@ -0,0 +1,251 @@ +#include "tinyprintf.h" + +#include <stdio.h> +#include <stdlib.h> + +int tinyprintf(const char *format, ...) +{ + if (format == NULL || *format == '\0') + { + return 0; + } + + va_list ap; + va_start(ap, format); + int res = 0; + + size_t i = 0; + while (format[i]) + { + if (format[i] != '%') + { + putchar(format[i]); + res++; + } + else + { + dispatch(format[i + 1], ap, &res); + format++; + } + format++; + } + va_end(ap); + return res; +} + +void dispatch(char c, va_list ap, int *res) +{ + switch (c) + { + case '%': + putchar('%'); + (*res)++; + break; + case 'd': + handle_d(va_arg(ap, int), res); + break; + case 'u': + handle_u(va_arg(ap, unsigned int), res); + break; + case 'x': + handle_x(va_arg(ap, unsigned int), res); + break; + case 'o': + handle_o(va_arg(ap, unsigned int), res); + break; + case 'c': + putchar(va_arg(ap, int)); + (*res)++; + break; + case 's': + handle_s(va_arg(ap, char *), res); + break; + default: + putchar('%'); + putchar(c); + *res += 2; + break; + } +} + +void handle_d(int val, int *res) +{ + if (val < 0) + { + putchar('-'); + (*res)++; + val = -val; + } + + if (val == 0) + { + putchar('0'); + (*res)++; + } + + int t = val; + int n = 0; + while (t > 0) + { + t /= 10; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 10 + '0'; + val /= 10; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_s(char *s, int *res) +{ + if (s == NULL) + { + char *text = "(null)"; + for (; *text; text++) + { + putchar(*text); + (*res)++; + } + return; + } + for (; *s; s++) + { + putchar(*s); + (*res)++; + } +} + +void handle_u(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 10; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 10 + '0'; + val /= 10; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_x(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 16; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 16 + '0'; + if (s[n] > '9') + { + s[n] = (s[n] - '0') % 10 + 'a'; + } + val /= 16; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_o(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 8; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 8 + '0'; + val /= 8; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} diff --git a/rushs/evalexpr/tinyprintf/src/tinyprintf.h b/rushs/evalexpr/tinyprintf/src/tinyprintf.h new file mode 100644 index 0000000..fd1f0b4 --- /dev/null +++ b/rushs/evalexpr/tinyprintf/src/tinyprintf.h @@ -0,0 +1,15 @@ +#ifndef TINYPRINTF_H +#define TINYPRINTF_H + +#include <stdarg.h> +#include <stddef.h> + +int tinyprintf(const char *format, ...); +void handle_d(int val, int *res); +void handle_u(unsigned int val, int *res); +void handle_x(unsigned int val, int *res); +void handle_o(unsigned int val, int *res); +void handle_s(char *s, int *res); +void dispatch(char c, va_list ap, int *res); + +#endif /* ! TINYPRINTF_H */ diff --git a/rushs/evalexpr/tinyprintf/tests/tests.c b/rushs/evalexpr/tinyprintf/tests/tests.c new file mode 100644 index 0000000..4235203 --- /dev/null +++ b/rushs/evalexpr/tinyprintf/tests/tests.c @@ -0,0 +1,213 @@ +#include <criterion/criterion.h> +#include <criterion/assert.h> +#include <criterion/redirect.h> +#include <stdio.h> + +#include "../src/tinyprintf.h" + +TestSuite(TestHandleD); + +Test(TestHandleD, handle_d42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("42"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleD, handle_d0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleD, handle_dminus42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(-42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("-42"); + cr_expect(res == 3, "Expected: %d. Got: %d", 3, res); +} + +Test(TestHandleD, simple_print, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%d] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [42] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleX); + +Test(TestHandleX, handle_x42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("2a"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleX, handle_x0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleX, handle_x15, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(15, &res); + fflush(stdout); + cr_assert_stdout_eq_str("f"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleX, handle_0xdeadc0de, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(0xdeadc0de, &res); + fflush(stdout); + cr_assert_stdout_eq_str("deadc0de"); + cr_expect(res == 8, "Expected: %d. Got: %d", 8, res); +} + +Test(TestHandleX, simple_print_hexa, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%x] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [2a] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleU); + +Test(TestHandleU, handle_u42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("42"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleU, handle_u0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleU, handle_u15, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(15, &res); + fflush(stdout); + cr_assert_stdout_eq_str("15"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleU, simple_print_unsigned, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%u] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [42] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleO); + +Test(TestHandleO, handle_o42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("52"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleO, handle_o0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleO, handle_o7, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(7, &res); + fflush(stdout); + cr_assert_stdout_eq_str("7"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleO, simple_print_octal, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%o] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [52] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestPrint); + +Test(TestPrint, print_percent, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%%s", "in your head"); + fflush(stdout); + cr_assert_stdout_eq_str("%s"); + cr_expect(retval == 2, "Expected: %d. Got: %d", 2, retval); +} + +Test(TestPrint, print_unknown_option, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("Good morning ACU! %t Tinyprintf is cool", 12); + fflush(stdout); + cr_assert_stdout_eq_str("Good morning ACU! %t Tinyprintf is cool"); + cr_expect(retval == 39, "Expected: %d. Got: %d", 39, retval); +} + +Test(TestPrint, print_tricky, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%c%c is %s... %d too.", '4', '2', "the answer", '*'); + fflush(stdout); + cr_assert_stdout_eq_str("42 is the answer... 42 too."); + cr_expect(retval == 27, "Expected: %d. Got: %d", 27, retval); +} + +Test(TestPrint, print_null, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%c%c is %s... %d too.", '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str("42 is (null)... 42 too."); + cr_expect(retval == 23, "Expected: %d. Got: %d", 23, retval); +} + +Test(TestPrint, print_null_fmt, .init = cr_redirect_stdout) +{ + int retval = tinyprintf(NULL, '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str(""); + cr_expect(retval == 0, "Expected: %d. Got: %d", 0, retval); +} + +Test(TestPrint, print_empty_fmt, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("", '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str(""); + cr_expect(retval == 0, "Expected: %d. Got: %d", 0, retval); +} diff --git a/rushs/evalexpr/traffic_lights/traffic_lights.c b/rushs/evalexpr/traffic_lights/traffic_lights.c new file mode 100644 index 0000000..76ea94f --- /dev/null +++ b/rushs/evalexpr/traffic_lights/traffic_lights.c @@ -0,0 +1,38 @@ +#include "traffic_lights.h" + +void init(unsigned char *lights) +{ + *lights <<= 4; +} + +void turn_on(unsigned char *lights, unsigned char light_num) +{ + *lights |= 1 << (light_num - 1); +} + +void turn_off(unsigned char *lights, unsigned char light_num) +{ + *lights &= ~(1 << (light_num - 1)); +} + +void next_step(unsigned char *lights) +{ + *lights <<= 1; + *lights += *lights >> 4; +} + +void reverse(unsigned char *lights) +{ + *lights = ~*lights; +} + +void swap(unsigned char *lights_1, unsigned char *lights_2) +{ + if (lights_1 == lights_2) + { + return; + } + *lights_1 = *lights_2 ^ *lights_1; + *lights_2 = *lights_1 ^ *lights_2; + *lights_1 = *lights_2 ^ *lights_1; +} diff --git a/rushs/evalexpr/traffic_lights/traffic_lights.h b/rushs/evalexpr/traffic_lights/traffic_lights.h new file mode 100644 index 0000000..7c803ea --- /dev/null +++ b/rushs/evalexpr/traffic_lights/traffic_lights.h @@ -0,0 +1,11 @@ +#ifndef TRAFFIC_LIGHTS_H +#define TRAFFIC_LIGHTS_H + +void init(unsigned char *lights); +void turn_on(unsigned char *lights, unsigned char light_num); +void turn_off(unsigned char *lights, unsigned char light_num); +void next_step(unsigned char *lights); +void reverse(unsigned char *lights); +void swap(unsigned char *lights_1, unsigned char *lights_2); + +#endif /* !TRAFFIC_LIGHTS_H */ diff --git a/rushs/evalexpr/user_ids/get_ids.sh b/rushs/evalexpr/user_ids/get_ids.sh new file mode 100644 index 0000000..2a1668b --- /dev/null +++ b/rushs/evalexpr/user_ids/get_ids.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cut --delimiter=: --fields=3 -s /etc/passwd | sort -rgu diff --git a/rushs/evalexpr/using_special_variables/print.sh b/rushs/evalexpr/using_special_variables/print.sh new file mode 100755 index 0000000..c24bebd --- /dev/null +++ b/rushs/evalexpr/using_special_variables/print.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +echo $# +echo $* +echo $1 +echo $2 +echo $3 +echo ${13} +echo $0 diff --git a/rushs/evalexpr/variant/variant.c b/rushs/evalexpr/variant/variant.c new file mode 100644 index 0000000..eb2f8a8 --- /dev/null +++ b/rushs/evalexpr/variant/variant.c @@ -0,0 +1,96 @@ +#include "variant.h" + +#include <stdio.h> +#include <string.h> + +void variant_display(const struct variant *e) +{ + switch (e->type) + { + case (TYPE_INT): + printf("%d\n", e->value.int_v); + break; + case (TYPE_FLOAT): + printf("%f\n", e->value.float_v); + break; + case (TYPE_CHAR): + printf("%c\n", e->value.char_v); + break; + default: + printf("%s\n", e->value.str_v); + break; + } +} + +bool variant_equal(const struct variant *left, const struct variant *right) +{ + if (left == NULL || right == NULL) + { + return true; + } + switch (left->type) + { + case (TYPE_INT): + if (right->type != TYPE_INT) + { + return false; + } + return left->value.int_v == right->value.int_v; + case (TYPE_FLOAT): + if (right->type != TYPE_FLOAT) + { + return false; + } + return left->value.float_v == right->value.float_v; + case (TYPE_CHAR): + if (right->type != TYPE_CHAR) + { + return false; + } + return left->value.char_v == right->value.char_v; + default: + if (right->type != TYPE_STRING) + { + return false; + } + return strcmp(left->value.str_v, right->value.str_v) == 0; + } +} + +int variant_find(const struct variant *array, size_t len, enum type type, + union type_any value) +{ + size_t i; + struct variant cmp = { type, value }; + for (i = 0; i < len && variant_equal(array + i, &cmp) == false; i++) + { + continue; + } + + if (i == len) + { + return -1; + } + return i; +} + +float variant_sum(const struct variant *array, size_t len) +{ + if (array == NULL) + { + return 0; + } + float sum = 0; + for (size_t i = 0; i < len; i++) + { + if (array[i].type == TYPE_FLOAT) + { + sum += array[i].value.float_v; + } + else if (array[i].type == TYPE_INT) + { + sum += array[i].value.int_v; + } + } + return sum; +} diff --git a/rushs/evalexpr/variant/variant.h b/rushs/evalexpr/variant/variant.h new file mode 100644 index 0000000..9983bc1 --- /dev/null +++ b/rushs/evalexpr/variant/variant.h @@ -0,0 +1,35 @@ +#ifndef VARIANT_H +#define VARIANT_H + +#include <stdbool.h> +#include <stddef.h> + +enum type +{ + TYPE_INT, + TYPE_FLOAT, + TYPE_CHAR, + TYPE_STRING +}; + +union type_any +{ + int int_v; + float float_v; + char char_v; + const char *str_v; +}; + +struct variant +{ + enum type type; + union type_any value; +}; + +void variant_display(const struct variant *e); +bool variant_equal(const struct variant *left, const struct variant *right); +int variant_find(const struct variant *array, size_t len, enum type type, + union type_any value); +float variant_sum(const struct variant *array, size_t len); + +#endif /* !VARIANT_H */ diff --git a/rushs/evalexpr/vector/Makefile b/rushs/evalexpr/vector/Makefile new file mode 100644 index 0000000..744241f --- /dev/null +++ b/rushs/evalexpr/vector/Makefile @@ -0,0 +1,13 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wvla -Wextra -std=c99 -pedantic + +.PHONY: library clean + +library: vector.o + ar csr libvector.a vector.o + +vector.o: vector.c + $(CC) $(CFLAGS) -c -o vector.o vector.c + +clean: + $(RM) libvector.a vector.o diff --git a/rushs/evalexpr/vector/vector.c b/rushs/evalexpr/vector/vector.c new file mode 100644 index 0000000..cbd19aa --- /dev/null +++ b/rushs/evalexpr/vector/vector.c @@ -0,0 +1,152 @@ +#include "vector.h" + +#include <stdio.h> +#include <stdlib.h> + +struct vector *vector_init(size_t n) +{ + struct vector *res = malloc(sizeof(struct vector)); + if (res == NULL) + { + return NULL; + } + + res->size = 0; + res->capacity = n; + res->data = malloc(n * sizeof(int)); + if (res->data == NULL) + { + return NULL; + } + return res; +} + +void vector_destroy(struct vector *v) +{ + if (v) + { + free(v->data); + free(v); + } +} + +struct vector *vector_resize(struct vector *v, size_t n) +{ + if (!v) + { + return NULL; + } + if (n == v->capacity) + { + return v; + } + if (v) + { + int *tmp = realloc(v->data, n * sizeof(int)); + if (tmp == NULL) + { + return NULL; + } + v->data = tmp; + + if (n < v->size) + { + v->size = n; + } + v->capacity = n; + return v; + } + return NULL; +} + +struct vector *vector_append(struct vector *v, int elt) +{ + if (v == NULL) + { + return NULL; + } + + if (v->size == v->capacity) + { + if (vector_resize(v, v->capacity * 2) == NULL) + { + return NULL; + } + } + v->data[v->size] = elt; + v->size++; + return v; +} + +void vector_print(const struct vector *v) +{ + if (v == NULL || v->size == 0) + { + printf("\n"); + return; + } + for (size_t i = 0; i < v->size - 1; i++) + { + printf("%d,", v->data[i]); + } + printf("%d\n", v->data[v->size - 1]); +} + +struct vector *vector_reset(struct vector *v, size_t n) +{ + if (vector_resize(v, n) == NULL) + { + return NULL; + } + + v->size = 0; + return v; +} + +struct vector *vector_insert(struct vector *v, size_t i, int elt) +{ + if (v == NULL || i > v->size) + return NULL; + if (i == v->size) + { + return vector_append(v, elt); + } + if (v->size == v->capacity) + { + if (vector_resize(v, v->capacity * 2) == NULL) + { + return NULL; + } + } + for (size_t j = v->size; j > i; j--) + { + v->data[j] = v->data[j - 1]; + } + v->size++; + + v->data[i] = elt; + return v; +} + +struct vector *vector_remove(struct vector *v, size_t i) +{ + if (v == NULL || v->size == 0 || i >= v->size) + { + return NULL; + } + for (size_t j = i; j < v->size - 1; j++) + { + v->data[j] = v->data[j + 1]; + } + + v->size--; + + if (v->size < v->capacity / 2) + { + if (vector_resize(v, v->capacity / 2) == NULL) + { + return NULL; + } + } + return v; +} diff --git a/rushs/evalexpr/vector/vector.h b/rushs/evalexpr/vector/vector.h new file mode 100644 index 0000000..5afada7 --- /dev/null +++ b/rushs/evalexpr/vector/vector.h @@ -0,0 +1,64 @@ +#ifndef VECTOR_H +#define VECTOR_H + +#include <stddef.h> + +struct vector +{ + // The number of elements in the vector + size_t size; + // The maximum number of elements in the vector + size_t capacity; + // The elements themselves + int *data; +}; + +/* +** Initialize the vector with `n` capacity. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_init(size_t n); + +/* +** Release the memory used by the vector. +** Does nothing if `v` is `NULL`. +*/ +void vector_destroy(struct vector *v); + +/* +** Resize the vector to `n` capacity. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_resize(struct vector *v, size_t n); + +/* +** Append an element to the end of the vector. Expand the vector if needed. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_append(struct vector *v, int elt); + +/* +** Display the vector contents on `stdout`. +** Displays `\n` if `v` is `NULL`. +*/ +void vector_print(const struct vector *v); + +/* +** Remove all the elements of the vector, and resize it to `n` capacity. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_reset(struct vector *v, size_t n); + +/* +** Insert `n` at the index `i`. Expand the vector if needed. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_insert(struct vector *v, size_t i, int elt); + +/* +** Remove the element at the index `i`. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_remove(struct vector *v, size_t i); + +#endif /* !VECTOR_H */ diff --git a/rushs/libzork/libzork/CMakeLists.txt b/rushs/libzork/libzork/CMakeLists.txt new file mode 100644 index 0000000..f9fccbc --- /dev/null +++ b/rushs/libzork/libzork/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.21.2) +project(Zork) + +add_executable(zork_test) +target_compile_options(zork_test PRIVATE -Wall -Wextra -Werror -pedantic -std=c++20 -Wold-style-cast) +set_target_properties(zork_test PROPERTIES + CXX_STANDARD 20 + CXX_EXTENSIONS OFF) +add_subdirectory(src) +add_subdirectory(zorkxplorer) + +target_link_libraries(zork_test PUBLIC libzork) +target_include_directories(zork_test PUBLIC + "${PROJECT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_SOURCE_DIR}/src" +) +target_include_directories(libzork PUBLIC + "${PROJECT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_SOURCE_DIR}/src" +)
\ No newline at end of file diff --git a/rushs/libzork/libzork/client/flake.nix b/rushs/libzork/libzork/client/flake.nix new file mode 100644 index 0000000..b6eb844 --- /dev/null +++ b/rushs/libzork/libzork/client/flake.nix @@ -0,0 +1,23 @@ +{ + description = "Flake for libzork"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + }; + + outputs = { self, nixpkgs }: { + devShells.x86_64-linux.default = with nixpkgs.legacyPackages.x86_64-linux; mkShell { + buildInputs = [ + gcc + cmake + yaml-cpp + curl + nlohmann_json + openssl + cmake + pkg-config + ]; + + }; + }; +} diff --git a/rushs/libzork/libzork/src/CMakeLists.txt b/rushs/libzork/libzork/src/CMakeLists.txt new file mode 100644 index 0000000..4f4224d --- /dev/null +++ b/rushs/libzork/libzork/src/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.21.2) +project(Zork) +add_library(libzork SHARED) + +target_compile_options(libzork PUBLIC -Wall -Wextra -Werror -pedantic -std=c++20 -Wold-style-cast) +set_target_properties(libzork PROPERTIES + CXX_STANDARD 20 + CXX_EXTENSIONS OFF + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + OUTPUT_NAME "zork" ) +target_include_directories(libzork PRIVATE + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_SOURCE_DIR}/src" +) + +target_sources(libzork PRIVATE exceptions.cc) + +find_library(YAML-CPP NAMES yaml-cpp libyaml-cpp REQUIRED) +target_link_libraries(libzork PUBLIC yaml-cpp) + +add_subdirectory(runner) +add_subdirectory(store) +add_subdirectory(story) +add_subdirectory(vars)
\ No newline at end of file diff --git a/rushs/libzork/libzork/src/exceptions.cc b/rushs/libzork/libzork/src/exceptions.cc new file mode 100644 index 0000000..f24eb9b --- /dev/null +++ b/rushs/libzork/libzork/src/exceptions.cc @@ -0,0 +1,6 @@ +#include "exceptions.hh" + +#include <string> + +namespace libzork +{} // namespace libzork diff --git a/rushs/libzork/libzork/src/exceptions.hh b/rushs/libzork/libzork/src/exceptions.hh new file mode 100644 index 0000000..93c0a0b --- /dev/null +++ b/rushs/libzork/libzork/src/exceptions.hh @@ -0,0 +1,17 @@ +#pragma once + +#include <stdexcept> + +namespace libzork +{ + class NotImplemented : public std::runtime_error + { + public: + NotImplemented(const char* file = __builtin_FILE(), + int line = __builtin_LINE()) + : std::runtime_error(std::string{ "Unimplemented function: " } + + file + ":" + std::to_string(line)) + {} + }; + +} // namespace libzork diff --git a/rushs/libzork/libzork/src/runner/CMakeLists.txt b/rushs/libzork/libzork/src/runner/CMakeLists.txt new file mode 100644 index 0000000..5e472d4 --- /dev/null +++ b/rushs/libzork/libzork/src/runner/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.21.2) +project(Zork) +target_sources(libzork PRIVATE choice.cc choice_impl.cc html.cc html_impl.cc interactive.cc runner.cc smart.cc smart_impl.cc) +set_target_properties(libzork PROPERTIES + CXX_STANDARD 20 + CXX_EXTENSIONS OFF)
\ No newline at end of file diff --git a/rushs/libzork/libzork/src/runner/caca.caca b/rushs/libzork/libzork/src/runner/caca.caca new file mode 100644 index 0000000..2df4dd2 --- /dev/null +++ b/rushs/libzork/libzork/src/runner/caca.caca @@ -0,0 +1,13 @@ +#include <caca.h> + +void caca::caca(caca::Caca& caca, string caca) { + std::caca caca = caca.get_caca(); + for(auto caca : caca) { + if(!caca->caca.is_caca()) { + return caca; + } + caca = caca.caca; + } + caca.set_caca(caca.get_caca()); + return caca; +}
\ No newline at end of file diff --git a/rushs/libzork/libzork/src/runner/choice.cc b/rushs/libzork/libzork/src/runner/choice.cc new file mode 100644 index 0000000..1e677bb --- /dev/null +++ b/rushs/libzork/libzork/src/runner/choice.cc @@ -0,0 +1,17 @@ +#include <algorithm> +#include <libzork/runner/choice.hh> + +#include "exceptions.hh" +#include "runner/choice_impl.hh" + +namespace libzork::runner +{ + + std::unique_ptr<ChoiceRunner> + make_choice_runner(std::unique_ptr<story::Story> story, std::istream& is, + std::ostream& os) + { + return std::make_unique<ChoiceRunnerImpl>(std::move(story), is, os); + } + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/choice_impl.cc b/rushs/libzork/libzork/src/runner/choice_impl.cc new file mode 100644 index 0000000..2572ef3 --- /dev/null +++ b/rushs/libzork/libzork/src/runner/choice_impl.cc @@ -0,0 +1,40 @@ +#include "runner/choice_impl.hh" + +#include <libzork/exceptions.hh> +#include <sstream> + +#include "exceptions.hh" + +namespace libzork::runner +{ + + void ChoiceRunnerImpl::print_script() const + { + InteractiveRunner::print_script(); + os_ << "\n"; + size_t i = 1; + for (auto choice : story_->get_current()->list_choices()) + { + os_ << i << ". " << choice << "\n"; + i++; + } + os_ << "\n"; + } + + void ChoiceRunnerImpl::process_input() + { + int input; + std::string s; + std::getline(is_, s); + if (!is_) + throw RunnerInterrupt{ "Bad input." }; + std::istringstream ss{ s }; + ss >> input; + const story::Node* choice; + if (ss.fail() || !ss.eof() + || !((choice = story_->get_current()->get_choice(input - 1)))) + throw RunnerInterrupt{ "Bad input." }; + story_->set_current(choice); + } + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/choice_impl.hh b/rushs/libzork/libzork/src/runner/choice_impl.hh new file mode 100644 index 0000000..6818bab --- /dev/null +++ b/rushs/libzork/libzork/src/runner/choice_impl.hh @@ -0,0 +1,18 @@ +#pragma once + +#include <libzork/runner/choice.hh> + +namespace libzork::runner +{ + + class ChoiceRunnerImpl : public ChoiceRunner + { + public: + using ChoiceRunner::ChoiceRunner; + ~ChoiceRunnerImpl() override = default; + + void print_script() const override; + void process_input() override; + }; + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/html.cc b/rushs/libzork/libzork/src/runner/html.cc new file mode 100644 index 0000000..ec67f43 --- /dev/null +++ b/rushs/libzork/libzork/src/runner/html.cc @@ -0,0 +1,18 @@ +#include <libzork/runner/html.hh> + +#include "exceptions.hh" +#include "runner/html_impl.hh" + +namespace libzork::runner +{ + + std::unique_ptr<HTMLRunner> + make_html_runner(std::unique_ptr<story::Story> story, + const fs::path& output_dir) + { + (void)story; + (void)output_dir; + throw NotImplemented(); + } + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/html_impl.cc b/rushs/libzork/libzork/src/runner/html_impl.cc new file mode 100644 index 0000000..e7b982b --- /dev/null +++ b/rushs/libzork/libzork/src/runner/html_impl.cc @@ -0,0 +1,13 @@ +#include "runner/html_impl.hh" + +#include "exceptions.hh" + +namespace libzork::runner +{ + + void HTMLRunnerImpl::run() + { + throw NotImplemented(); + } + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/html_impl.hh b/rushs/libzork/libzork/src/runner/html_impl.hh new file mode 100644 index 0000000..3d47a3e --- /dev/null +++ b/rushs/libzork/libzork/src/runner/html_impl.hh @@ -0,0 +1,16 @@ +#pragma once + +#include <libzork/runner/html.hh> + +namespace libzork::runner +{ + + class HTMLRunnerImpl : public HTMLRunner + { + public: + ~HTMLRunnerImpl() override = default; + + void run() override; + }; + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/interactive.cc b/rushs/libzork/libzork/src/runner/interactive.cc new file mode 100644 index 0000000..85a76a8 --- /dev/null +++ b/rushs/libzork/libzork/src/runner/interactive.cc @@ -0,0 +1,40 @@ +#include <libzork/exceptions.hh> +#include <libzork/runner/interactive.hh> + +#include "exceptions.hh" + +namespace libzork::runner +{ + + InteractiveRunner::InteractiveRunner(std::unique_ptr<story::Story> story, + std::istream& is, std::ostream& os) + : Runner(std::move(story)) + , is_(is) + , os_(os) + {} + + void InteractiveRunner::print_script() const + { + os_ << story_->get_current()->get_text(); + } + + void InteractiveRunner::run() + { + print_script(); + while (story_->get_current()->list_choices().size() != 0) + { + try + { + os_ << "> "; + process_input(); + } + catch (RunnerInterrupt& i) + { + os_ << i.what() << "\n"; + continue; + } + print_script(); + } + } + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/runner.cc b/rushs/libzork/libzork/src/runner/runner.cc new file mode 100644 index 0000000..3968723 --- /dev/null +++ b/rushs/libzork/libzork/src/runner/runner.cc @@ -0,0 +1,12 @@ +#include <libzork/runner/runner.hh> + +#include "exceptions.hh" + +namespace libzork::runner +{ + + Runner::Runner(std::unique_ptr<story::Story> story) + : story_{ std::move(story) } + {} + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/smart.cc b/rushs/libzork/libzork/src/runner/smart.cc new file mode 100644 index 0000000..e99dd90 --- /dev/null +++ b/rushs/libzork/libzork/src/runner/smart.cc @@ -0,0 +1,21 @@ +#include <libzork/runner/smart.hh> + +#include "exceptions.hh" +#include "runner/smart_impl.hh" + +namespace libzork::runner +{ + + std::unique_ptr<SmartRunner> + make_smart_runner(std::unique_ptr<story::Story> story, + const fs::path& synonyms_path, std::istream& is, + std::ostream& os) + { + (void)story; + (void)synonyms_path; + (void)is; + (void)os; + throw NotImplemented(); + } + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/smart_impl.cc b/rushs/libzork/libzork/src/runner/smart_impl.cc new file mode 100644 index 0000000..022f07a --- /dev/null +++ b/rushs/libzork/libzork/src/runner/smart_impl.cc @@ -0,0 +1,29 @@ +#include "runner/smart_impl.hh" + +#include "exceptions.hh" + +namespace libzork::runner +{ + + void SmartRunnerImpl::process_input() + { + throw NotImplemented(); + } + + std::unordered_set<std::string> + SmartRunnerImpl::tokenize(const std::string& str) const + { + (void)str; + throw NotImplemented(); + } + + bool SmartRunnerImpl::has_unmatched_token( + const std::unordered_set<std::string>& user_tokens, + const std::unordered_set<std::string>& choice_tokens) const + { + (void)user_tokens; + (void)choice_tokens; + throw NotImplemented(); + } + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/runner/smart_impl.hh b/rushs/libzork/libzork/src/runner/smart_impl.hh new file mode 100644 index 0000000..201237f --- /dev/null +++ b/rushs/libzork/libzork/src/runner/smart_impl.hh @@ -0,0 +1,20 @@ +#pragma once + +#include <libzork/runner/smart.hh> + +namespace libzork::runner +{ + + class SmartRunnerImpl : public SmartRunner + { + public: + void process_input() override; + virtual std::unordered_set<std::string> + tokenize(const std::string& str) const override; + virtual bool + has_unmatched_token(const std::unordered_set<std::string>& user_tokens, + const std::unordered_set<std::string>& + choice_tokens) const override; + }; + +} // namespace libzork::runner diff --git a/rushs/libzork/libzork/src/store/CMakeLists.txt b/rushs/libzork/libzork/src/store/CMakeLists.txt new file mode 100644 index 0000000..420356d --- /dev/null +++ b/rushs/libzork/libzork/src/store/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.21.2) +project(Zork) +target_sources(libzork PRIVATE store.cc store_impl.cc) +set_target_properties(libzork PROPERTIES + CXX_STANDARD 20 + CXX_EXTENSIONS OFF)
\ No newline at end of file diff --git a/rushs/libzork/libzork/src/store/store.cc b/rushs/libzork/libzork/src/store/store.cc new file mode 100644 index 0000000..be91193 --- /dev/null +++ b/rushs/libzork/libzork/src/store/store.cc @@ -0,0 +1,14 @@ +#include <libzork/store/store.hh> + +#include "exceptions.hh" +#include "store/store_impl.hh" + +namespace libzork::store +{ + + std::unique_ptr<Store> make_store() + { + return std::make_unique<StoreImpl>(); + } + +} // namespace libzork::store diff --git a/rushs/libzork/libzork/src/store/store_impl.cc b/rushs/libzork/libzork/src/store/store_impl.cc new file mode 100644 index 0000000..3abcb55 --- /dev/null +++ b/rushs/libzork/libzork/src/store/store_impl.cc @@ -0,0 +1,42 @@ +#include "store/store_impl.hh" + +#include "exceptions.hh" + +namespace libzork::store +{ + + const story::Node* StoreImpl::get_active_node() const + { + return active_node_; + } + + void StoreImpl::set_active_node(const story::Node* node) + { + active_node_ = node; + } + + bool StoreImpl::has_variable(const std::string& name) const + { + (void)name; + throw NotImplemented(); + } + + int StoreImpl::get_variable(const std::string& name) const + { + (void)name; + throw NotImplemented(); + } + + void StoreImpl::set_variable(const std::string& name, int value) + { + (void)name; + (void)value; + throw NotImplemented(); + } + + std::map<std::string, int> StoreImpl::get_inventory() const + { + throw NotImplemented(); + } + +} // namespace libzork::store diff --git a/rushs/libzork/libzork/src/store/store_impl.hh b/rushs/libzork/libzork/src/store/store_impl.hh new file mode 100644 index 0000000..a978128 --- /dev/null +++ b/rushs/libzork/libzork/src/store/store_impl.hh @@ -0,0 +1,26 @@ +#pragma once + +#include <libzork/store/store.hh> + +namespace libzork::store +{ + + class StoreImpl : public Store + { + public: + StoreImpl() = default; + ~StoreImpl() override = default; + + const story::Node* get_active_node() const override; + void set_active_node(const story::Node* node) override; + + bool has_variable(const std::string& name) const override; + int get_variable(const std::string& name) const override; + void set_variable(const std::string& name, int value) override; + std::map<std::string, int> get_inventory() const override; + + private: + const story::Node* active_node_ = nullptr; + }; + +} // namespace libzork::store diff --git a/rushs/libzork/libzork/src/story/CMakeLists.txt b/rushs/libzork/libzork/src/story/CMakeLists.txt new file mode 100644 index 0000000..6549964 --- /dev/null +++ b/rushs/libzork/libzork/src/story/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.21.2) +project(Zork) +target_sources(libzork PRIVATE node.cc node_impl.cc story.cc story_impl.cc choice.cc) +set_target_properties(libzork PROPERTIES + CXX_STANDARD 20 + CXX_EXTENSIONS OFF)
\ No newline at end of file diff --git a/rushs/libzork/libzork/src/story/choice.cc b/rushs/libzork/libzork/src/story/choice.cc new file mode 100644 index 0000000..4b01983 --- /dev/null +++ b/rushs/libzork/libzork/src/story/choice.cc @@ -0,0 +1,16 @@ +// +// Created by martial.simon on 2/28/25. +// + +#include <story/choice.hh> +namespace libzork::story +{ + std::string Choice::get_text() const + { + return text_; + } + const Node* Choice::get_choice() const + { + return choice_; + } +} // namespace libzork::story
\ No newline at end of file diff --git a/rushs/libzork/libzork/src/story/choice.hh b/rushs/libzork/libzork/src/story/choice.hh new file mode 100644 index 0000000..08bbd29 --- /dev/null +++ b/rushs/libzork/libzork/src/story/choice.hh @@ -0,0 +1,25 @@ +// +// Created by martial.simon on 2/28/25. +// + +#pragma once +#include <libzork/story/node.hh> +#include <string> + +namespace libzork::story +{ + class Choice + { + public: + Choice(const std::string& text, const Node* choice) + : text_(text) + , choice_(choice) + {} + std::string get_text() const; + const Node* get_choice() const; + + private: + std::string text_; + const Node* choice_; + }; +} // namespace libzork::story diff --git a/rushs/libzork/libzork/src/story/node.cc b/rushs/libzork/libzork/src/story/node.cc new file mode 100644 index 0000000..416b902 --- /dev/null +++ b/rushs/libzork/libzork/src/story/node.cc @@ -0,0 +1,21 @@ +#include <fstream> +#include <libzork/story/node.hh> + +#include "exceptions.hh" +#include "story/node_impl.hh" + +namespace libzork::story +{ + + std::unique_ptr<Node> make_node(const std::string& name, + const fs::path& script_path) + { + auto stream = std::ifstream(script_path.c_str()); + if (!stream.is_open()) + throw std::invalid_argument{ "Invalid file, unable to open." }; + std::ostringstream o; + o << stream.rdbuf(); + return std::make_unique<NodeImpl>(name, o.str()); + } + +} // namespace libzork::story diff --git a/rushs/libzork/libzork/src/story/node_impl.cc b/rushs/libzork/libzork/src/story/node_impl.cc new file mode 100644 index 0000000..c9877e8 --- /dev/null +++ b/rushs/libzork/libzork/src/story/node_impl.cc @@ -0,0 +1,73 @@ +#include "story/node_impl.hh" + +#include <fstream> + +#include "exceptions.hh" + +namespace libzork::story +{ + NodeImpl::NodeImpl(const std::string& name, const std::string& text) + : name_(name) + , text_(text) + {} + + const std::string& NodeImpl::get_name() const + { + return name_; + } + + const std::string& NodeImpl::get_text() const + { + return text_; + } + + const Node* NodeImpl::get_choice(size_t index, bool check_conditions) const + { + (void)check_conditions; + if (choices_.size() <= index) + return nullptr; + return choices_.at(index).get_choice(); + } + + std::vector<std::string> NodeImpl::list_choices(bool check_conditions) const + { + (void)check_conditions; + std::vector<std::string> texts; + for (auto choice : choices_) + { + texts.push_back(choice.get_text()); + } + return texts; + } + + void NodeImpl::add_choice( + const Node* other, const std::string& text, + std::vector<std::unique_ptr<vars::Condition>> conditions, + std::vector<std::unique_ptr<vars::Action>> actions) + { + (void)conditions; + (void)actions; + Choice c{ text, other }; + choices_.push_back(std::move(c)); + } + + const NodeImpl& to_impl(const Node& node) + { + const NodeImpl* cast = dynamic_cast<const NodeImpl*>(&node); + if (!cast) + throw std::runtime_error{ + "Invalid conversion from const Node* to const NodeImpl*" + }; + return *cast; + } + + NodeImpl& to_impl(Node& node) + { + NodeImpl* cast = dynamic_cast<NodeImpl*>(&node); + if (!cast) + throw std::runtime_error{ + "Invalid conversion from const Node* to const NodeImpl*" + }; + return *cast; + } +} // namespace libzork::story diff --git a/rushs/libzork/libzork/src/story/node_impl.hh b/rushs/libzork/libzork/src/story/node_impl.hh new file mode 100644 index 0000000..f55de7c --- /dev/null +++ b/rushs/libzork/libzork/src/story/node_impl.hh @@ -0,0 +1,38 @@ +#pragma once + +#include <libzork/story/node.hh> +#include <story/choice.hh> + +namespace libzork::story +{ + class NodeImpl : public Node + { + public: + NodeImpl(const std::string& name, const std::string& text); + ~NodeImpl() override = default; + + const std::string& get_name() const override; + + const std::string& get_text() const override; + + const Node* get_choice(std::size_t index, + bool check_conditions = true) const override; + + std::vector<std::string> + list_choices(bool check_conditions = true) const override; + + void add_choice( + const Node* other, const std::string& text, + std::vector<std::unique_ptr<vars::Condition>> conditions = {}, + std::vector<std::unique_ptr<vars::Action>> actions = {}) override; + + private: + const std::string name_; + const std::string text_; + std::vector<Choice> choices_; + }; + + const NodeImpl& to_impl(const Node& node); + + NodeImpl& to_impl(Node& node); +} // namespace libzork::story diff --git a/rushs/libzork/libzork/src/story/story.cc b/rushs/libzork/libzork/src/story/story.cc new file mode 100644 index 0000000..4b26eff --- /dev/null +++ b/rushs/libzork/libzork/src/story/story.cc @@ -0,0 +1,15 @@ +#include <libzork/story/story.hh> +#include <store/store_impl.hh> + +#include "exceptions.hh" +#include "story/story_impl.hh" + +namespace libzork::story +{ + + std::unique_ptr<Story> make_story(const fs::path& path) + { + return std::make_unique<StoryImpl>(path); + } + +} // namespace libzork::story diff --git a/rushs/libzork/libzork/src/story/story_impl.cc b/rushs/libzork/libzork/src/story/story_impl.cc new file mode 100644 index 0000000..ad39d09 --- /dev/null +++ b/rushs/libzork/libzork/src/story/story_impl.cc @@ -0,0 +1,118 @@ +#include "story/story_impl.hh" + +#include "exceptions.hh" +#include "node_impl.hh" + +namespace libzork::story +{ + + StoryImpl::StoryImpl(const fs::path& path) + { + YAML::Node config = YAML::LoadFile(path); + title_ = config["title"].as<std::string>(); + auto dir = config["scripts-path"].as<std::string>(); + auto story = config["story"]; + for (auto script : story) + { + auto name = script["name"].as<std::string>(); + auto script_path = script["script"].as<std::string>(); + nodes_.push_back( + make_node(name, path.parent_path() / dir / script_path)); + } + size_t i = 0; + for (auto script : story) + { + for (auto choice : script["choices"]) + { + auto text = choice["text"].as<std::string>(); + auto matches = std::ranges::find_if( + nodes_.begin(), nodes_.end(), + [choice](const std::unique_ptr<Node>& c) -> bool { + return c->get_name() + == choice["target"].as<std::string>(); + }); + nodes_.at(i)->add_choice(matches->get(), text); + } + i++; + } + if (nodes_.empty()) + store_ = nullptr; + else + { + store_ = store::make_store(); + store_->set_active_node(nodes_.at(0).get()); + } + } + const std::string& StoryImpl::get_title() const + { + return title_; + } + + const Node* StoryImpl::get_current() const + { + if (!store_) + return nullptr; + return store_->get_active_node(); + } + + void StoryImpl::set_current(const Node* node) + { + store_->set_active_node(node); + } + + const store::Store* StoryImpl::get_store() const + { + return store_.get(); + } + + std::ostream& StoryImpl::display(std::ostream& os) const + { + os << "digraph story {\n"; + for (auto node = nodes_.begin(); node != nodes_.end(); node++) + { + auto choices = node->get()->list_choices(); + if (choices.size() == 0) + continue; + os << "\t\"" << node->get()->get_name() << "\" -> "; + if (choices.size() > 1) + { + os << "{"; + os << "\"" << to_impl(*node->get()->get_choice(0)).get_name() + << "\""; + for (size_t i = 1; i < choices.size(); i++) + { + os << " " << "\"" + << to_impl(*node->get()->get_choice(i)).get_name() + << "\""; + } + os << "}"; + } + else + { + os << "\"" << to_impl(*node->get()->get_choice(0)).get_name() + << "\""; + } + os << ";\n"; + } + os << "}\n"; + return os; + } + const StoryImpl& to_impl(const Story& story) + { + const StoryImpl* cast = dynamic_cast<const StoryImpl*>(&story); + if (!cast) + throw std::runtime_error{ + "Invalid conversion from const Node* to const NodeImpl*" + }; + return *cast; + } + StoryImpl& to_impl(Story& story) + { + StoryImpl* cast = dynamic_cast<StoryImpl*>(&story); + if (!cast) + throw std::runtime_error{ + "Invalid conversion from const Node* to const NodeImpl*" + }; + return *cast; + } +} // namespace libzork::story diff --git a/rushs/libzork/libzork/src/story/story_impl.hh b/rushs/libzork/libzork/src/story/story_impl.hh new file mode 100644 index 0000000..6062d2f --- /dev/null +++ b/rushs/libzork/libzork/src/story/story_impl.hh @@ -0,0 +1,31 @@ +#pragma once + +#include <libzork/story/story.hh> +#include <store/store_impl.hh> +#include <yaml-cpp/yaml.h> + +namespace libzork::story +{ + + class StoryImpl : public Story + { + public: + StoryImpl(const fs::path& path); + ~StoryImpl() override = default; + + const std::string& get_title() const override; + const Node* get_current() const override; + void set_current(const Node* node) override; + const store::Store* get_store() const override; + std::ostream& display(std::ostream& os) const override; + + private: + std::string title_; + std::vector<std::unique_ptr<Node>> nodes_; + std::unique_ptr<store::Store> store_; + }; + + const StoryImpl& to_impl(const Story& story); + StoryImpl& to_impl(Story& story); + +} // namespace libzork::story diff --git a/rushs/libzork/libzork/src/vars/CMakeLists.txt b/rushs/libzork/libzork/src/vars/CMakeLists.txt new file mode 100644 index 0000000..8e3e5d5 --- /dev/null +++ b/rushs/libzork/libzork/src/vars/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.21.2) + +target_sources(libzork PRIVATE action.cc action_impl.cc condition.cc condition_impl.cc) +set_target_properties(libzork PROPERTIES + CXX_STANDARD 20 + CXX_EXTENSIONS OFF)
\ No newline at end of file diff --git a/rushs/libzork/libzork/src/vars/action.cc b/rushs/libzork/libzork/src/vars/action.cc new file mode 100644 index 0000000..83d8c8e --- /dev/null +++ b/rushs/libzork/libzork/src/vars/action.cc @@ -0,0 +1,20 @@ +#include <libzork/vars/action.hh> + +#include "exceptions.hh" +#include "vars/action_impl.hh" + +namespace libzork::vars +{ + + std::unique_ptr<Action> make_action(store::Store& store, + const std::string& variable, + const std::string& action, int value) + { + (void)store; + (void)variable; + (void)action; + (void)value; + throw NotImplemented(); + } + +} // namespace libzork::vars diff --git a/rushs/libzork/libzork/src/vars/action_impl.cc b/rushs/libzork/libzork/src/vars/action_impl.cc new file mode 100644 index 0000000..d0abcf7 --- /dev/null +++ b/rushs/libzork/libzork/src/vars/action_impl.cc @@ -0,0 +1,13 @@ +#include "vars/action_impl.hh" + +#include "exceptions.hh" + +namespace libzork::vars +{ + + void ActionImpl::apply() const + { + throw NotImplemented(); + } + +} // namespace libzork::vars diff --git a/rushs/libzork/libzork/src/vars/action_impl.hh b/rushs/libzork/libzork/src/vars/action_impl.hh new file mode 100644 index 0000000..bc7f933 --- /dev/null +++ b/rushs/libzork/libzork/src/vars/action_impl.hh @@ -0,0 +1,16 @@ +#pragma once + +#include <libzork/vars/action.hh> + +namespace libzork::vars +{ + + class ActionImpl : public Action + { + public: + ~ActionImpl() override = default; + + void apply() const override; + }; + +} // namespace libzork::vars diff --git a/rushs/libzork/libzork/src/vars/condition.cc b/rushs/libzork/libzork/src/vars/condition.cc new file mode 100644 index 0000000..d0fb648 --- /dev/null +++ b/rushs/libzork/libzork/src/vars/condition.cc @@ -0,0 +1,21 @@ +#include <libzork/store/store.hh> +#include <libzork/vars/condition.hh> + +#include "exceptions.hh" + +namespace libzork::vars +{ + + std::unique_ptr<Condition> make_condition(const store::Store& store, + const std::string& variable, + const std::string& comparison, + int value) + { + (void)store; + (void)variable; + (void)comparison; + (void)value; + throw NotImplemented(); + } + +} // namespace libzork::vars diff --git a/rushs/libzork/libzork/src/vars/condition_impl.cc b/rushs/libzork/libzork/src/vars/condition_impl.cc new file mode 100644 index 0000000..7d11fdc --- /dev/null +++ b/rushs/libzork/libzork/src/vars/condition_impl.cc @@ -0,0 +1,16 @@ +#include "vars/condition_impl.hh" + +#include <algorithm> +#include <map> + +#include "exceptions.hh" + +namespace libzork::vars +{ + + bool ConditionImpl::apply() const + { + throw NotImplemented(); + } + +} // namespace libzork::vars diff --git a/rushs/libzork/libzork/src/vars/condition_impl.hh b/rushs/libzork/libzork/src/vars/condition_impl.hh new file mode 100644 index 0000000..c8b300c --- /dev/null +++ b/rushs/libzork/libzork/src/vars/condition_impl.hh @@ -0,0 +1,16 @@ +#pragma once + +#include <libzork/vars/condition.hh> + +namespace libzork::vars +{ + + class ConditionImpl : public Condition + { + public: + ~ConditionImpl() override = default; + + bool apply() const override; + }; + +} // namespace libzork::vars diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/castle.txt b/rushs/libzork/libzork/tests/scripts/little_quest/castle.txt new file mode 100644 index 0000000..23bef37 --- /dev/null +++ b/rushs/libzork/libzork/tests/scripts/little_quest/castle.txt @@ -0,0 +1,3 @@ +You enter the castle. +A large dragon blocks your path, preventing you from proceeding further. +A sword is on your left. diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/castle_weapon.txt b/rushs/libzork/libzork/tests/scripts/little_quest/castle_weapon.txt new file mode 100644 index 0000000..7e1d77f --- /dev/null +++ b/rushs/libzork/libzork/tests/scripts/little_quest/castle_weapon.txt @@ -0,0 +1,3 @@ +You enter the castle. +A large dragon blocks your path, preventing you from proceeding further. +To your right, there is a forge. Perhaps there are weapons there ? diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/forest.txt b/rushs/libzork/libzork/tests/scripts/little_quest/forest.txt new file mode 100644 index 0000000..e37ad98 --- /dev/null +++ b/rushs/libzork/libzork/tests/scripts/little_quest/forest.txt @@ -0,0 +1,4 @@ +You find yourself in a vast, lush forest. +In the distance, you spot a prince perched atop a tower of a castle. +He appears to be in desperate need of assistance. +To your right lies a house. diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/house.txt b/rushs/libzork/libzork/tests/scripts/little_quest/house.txt new file mode 100644 index 0000000..c285e6a --- /dev/null +++ b/rushs/libzork/libzork/tests/scripts/little_quest/house.txt @@ -0,0 +1,2 @@ +There is a bed, worn out from fatigue, you collapse onto it and take a nap. +The end. diff --git a/rushs/libzork/libzork/tests/scripts/little_quest/tower.txt b/rushs/libzork/libzork/tests/scripts/little_quest/tower.txt new file mode 100644 index 0000000..2e61000 --- /dev/null +++ b/rushs/libzork/libzork/tests/scripts/little_quest/tower.txt @@ -0,0 +1,2 @@ +You slay the dragon, climb the tower, and find the prince safe and sound. +The end. diff --git a/rushs/libzork/libzork/tests/scripts/short_static/cave.txt b/rushs/libzork/libzork/tests/scripts/short_static/cave.txt new file mode 100644 index 0000000..f77f4bf --- /dev/null +++ b/rushs/libzork/libzork/tests/scripts/short_static/cave.txt @@ -0,0 +1 @@ +This is a dark cave diff --git a/rushs/libzork/libzork/tests/scripts/short_static/forest.txt b/rushs/libzork/libzork/tests/scripts/short_static/forest.txt new file mode 100644 index 0000000..ac917ab --- /dev/null +++ b/rushs/libzork/libzork/tests/scripts/short_static/forest.txt @@ -0,0 +1 @@ +This is a large forest diff --git a/rushs/libzork/libzork/tests/scripts/short_static/welcome.txt b/rushs/libzork/libzork/tests/scripts/short_static/welcome.txt new file mode 100644 index 0000000..af5626b --- /dev/null +++ b/rushs/libzork/libzork/tests/scripts/short_static/welcome.txt @@ -0,0 +1 @@ +Hello, world! diff --git a/rushs/libzork/libzork/tests/stories/dynamic/story.yml b/rushs/libzork/libzork/tests/stories/dynamic/story.yml new file mode 100644 index 0000000..7d75431 --- /dev/null +++ b/rushs/libzork/libzork/tests/stories/dynamic/story.yml @@ -0,0 +1,51 @@ +title: A dynamic story +scripts-path: ../../scripts/little_quest +variables: + - name: health + value: 10 + - name: sword_taken + value: 0 +story: + - name: forest + script: forest.txt + choices: + - text: Enter the house + target: house + - text: Enter the castle + target: castle + - text: Eat a fruit + target: forest + actions: + - name: health + operation: add + value: 10 + - name: house + script: house.txt + choices: [] + - name: castle + script: castle_weapon.txt + choices: + - text: Flee + target: forest + - text: Take the sword + target: castle + conditions: + - name: sword_taken + comparison: equal + value: 0 + actions: + - name: sword_taken + operation: add + value: 1 + - text: Kill the dragon + target: tower + conditions: + - name: sword_taken + comparison: equal + value: 1 + - name: health + comparison: greater + value: 10 + - name: tower + script: tower.txt + choices: [] diff --git a/rushs/libzork/libzork/tests/stories/long_static/story.yml b/rushs/libzork/libzork/tests/stories/long_static/story.yml new file mode 100644 index 0000000..152fad8 --- /dev/null +++ b/rushs/libzork/libzork/tests/stories/long_static/story.yml @@ -0,0 +1,25 @@ +title: A long static story +scripts-path: ../../scripts/little_quest +story: + - name: forest + script: forest.txt + choices: + - text: Enter the house + target: house + - text: Enter the castle + target: castle + - text: Eat a fruit + target: forest + - name: house + script: house.txt + choices: [] + - name: castle + script: castle.txt + choices: + - text: Flee + target: forest + - text: Kill the dragon + target: tower + - name: tower + script: tower.txt + choices: [] diff --git a/rushs/libzork/libzork/tests/stories/short_static/story.yml b/rushs/libzork/libzork/tests/stories/short_static/story.yml new file mode 100644 index 0000000..701a954 --- /dev/null +++ b/rushs/libzork/libzork/tests/stories/short_static/story.yml @@ -0,0 +1,16 @@ +title: A short static story +scripts-path: ../../scripts/short_static +story: + - name: welcome + script: welcome.txt + choices: + - text: Explore the cave + target: cave + - text: Go in the forest + target: forest + - name: cave + script: cave.txt + choices: [] + - name: forest + script: forest.txt + choices: [] diff --git a/rushs/libzork/libzork/zorkxplorer/CMakeLists.txt b/rushs/libzork/libzork/zorkxplorer/CMakeLists.txt new file mode 100644 index 0000000..9633f06 --- /dev/null +++ b/rushs/libzork/libzork/zorkxplorer/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.21.2) +project(Zork) +add_subdirectory(src)
\ No newline at end of file diff --git a/rushs/libzork/libzork/zorkxplorer/src/CMakeLists.txt b/rushs/libzork/libzork/zorkxplorer/src/CMakeLists.txt new file mode 100644 index 0000000..88a75d1 --- /dev/null +++ b/rushs/libzork/libzork/zorkxplorer/src/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.21.2) +project(Zork) +target_sources(zork_test PUBLIC main.cc options.cc)
\ No newline at end of file diff --git a/rushs/libzork/libzork/zorkxplorer/src/hello.txt b/rushs/libzork/libzork/zorkxplorer/src/hello.txt new file mode 100644 index 0000000..05a682b --- /dev/null +++ b/rushs/libzork/libzork/zorkxplorer/src/hello.txt @@ -0,0 +1 @@ +Hello!
\ No newline at end of file diff --git a/rushs/libzork/libzork/zorkxplorer/src/main.cc b/rushs/libzork/libzork/zorkxplorer/src/main.cc new file mode 100644 index 0000000..2494d62 --- /dev/null +++ b/rushs/libzork/libzork/zorkxplorer/src/main.cc @@ -0,0 +1,63 @@ +#include <fstream> +#include <iostream> +#include <libzork/exceptions.hh> +#include <libzork/runner/choice.hh> +#include <libzork/runner/html.hh> +#include <libzork/runner/smart.hh> + +#include "options.hh" + +std::unique_ptr<libzork::story::Story> get_story(const Config& config) +{ + return libzork::story::make_story(config.story_path); +} + +std::unique_ptr<libzork::runner::Runner> +get_runner(const Config& config, std::unique_ptr<libzork::story::Story> story) +{ + switch (config.story_type) + { + case StoryType::Choice: + return libzork::runner::make_choice_runner(std::move(story)); + case StoryType::Smart: + return libzork::runner::make_smart_runner(std::move(story), + config.story_arg); + case StoryType::HTML: + return libzork::runner::make_html_runner(std::move(story), + config.story_arg); + default: + return nullptr; + } +} + +int main(int argc, char** argv) +{ + Config config; + try + { + config = parse_options(argc, argv); + } + catch (const std::invalid_argument& exc) + { + std::cerr << "invalid options: " << exc.what() << "\n"; + return 1; + } + + auto story = get_story(config); + auto output = std::ofstream( + "/home/martial.simon/afs/ing/zork/libzork/tests/output/dot.out"); + story->display(output); + + std::unique_ptr<libzork::runner::Runner> runner = + libzork::runner::make_choice_runner(std::move(story), std::cin, + std::cout); + + try + { + runner->run(); + } + catch (const libzork::RunnerQuit&) + {} + + return 0; +} diff --git a/rushs/libzork/libzork/zorkxplorer/src/options.cc b/rushs/libzork/libzork/zorkxplorer/src/options.cc new file mode 100644 index 0000000..e97a7ea --- /dev/null +++ b/rushs/libzork/libzork/zorkxplorer/src/options.cc @@ -0,0 +1,57 @@ +#include "options.hh" + +#include <getopt.h> +#include <iostream> + +namespace +{ + constexpr option options[] = { + { "story", required_argument, nullptr, 's' }, + { "smart", required_argument, nullptr, 'm' }, + { "html", required_argument, nullptr, 'h' }, + }; + + std::string usage(const std::string& name) + { + return "usage: " + name + + " (--story <story.yml>)" + " [--smart <synonyms.yml> | --html <directory/>]"; + }; +} // namespace + +Config parse_options(int argc, char** argv) +{ + Config config; + int opt; + while ((opt = getopt_long(argc, argv, "s:m:h:t:u:o:n:r:", options, nullptr)) + != -1) + { + switch (opt) + { + case 's': // --story + config.story_path = optarg; + break; + case 'm': // --smart + if (config.story_type == StoryType::HTML) + throw std::invalid_argument( + "incompatble options: `--smart` and `--html`"); + config.story_type = StoryType::Smart; + config.story_arg = optarg; + break; + case 'h': // --html + if (config.story_type == StoryType::Smart) + throw std::invalid_argument( + "incompatible options: `--smart` and `--html`"); + config.story_type = StoryType::HTML; + config.story_arg = optarg; + break; + default: + throw std::invalid_argument(usage(argv[0])); + } + }; + + if (config.story_path.empty()) + throw std::invalid_argument("option '--story' is mandatory"); + + return config; +} diff --git a/rushs/libzork/libzork/zorkxplorer/src/options.hh b/rushs/libzork/libzork/zorkxplorer/src/options.hh new file mode 100644 index 0000000..d3f919d --- /dev/null +++ b/rushs/libzork/libzork/zorkxplorer/src/options.hh @@ -0,0 +1,22 @@ +#pragma once + +#include <filesystem> +#include <optional> + +namespace fs = std::filesystem; + +enum class StoryType +{ + Choice, + Smart, + HTML, +}; + +struct Config +{ + std::filesystem::path story_path; + StoryType story_type = StoryType::Choice; + fs::path story_arg; /** Undefined if story_type is StoryType::BASIC */ +}; + +Config parse_options(int argc, char** argv); diff --git a/rushs/libzork/libzork/zorkxplorer/src/world.txt b/rushs/libzork/libzork/zorkxplorer/src/world.txt new file mode 100644 index 0000000..5dd01c1 --- /dev/null +++ b/rushs/libzork/libzork/zorkxplorer/src/world.txt @@ -0,0 +1 @@ +Hello, world!
\ No newline at end of file diff --git a/rushs/tinyprintf/80cols/80cols.sh b/rushs/tinyprintf/80cols/80cols.sh new file mode 100755 index 0000000..d66cf9b --- /dev/null +++ b/rushs/tinyprintf/80cols/80cols.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +[ $# -ne 1 ] && exit 1 +[ -f $1 ] || exit 1 + +while IFS='' read -r line; do + var=$(printf '%s' "$line" | wc -m) + [ "$var" -ge 80 ] && printf '%s\n' "$line" +done < "$1" + +exit 0 diff --git a/rushs/tinyprintf/80cols_grep/80cols.grep b/rushs/tinyprintf/80cols_grep/80cols.grep new file mode 100644 index 0000000..1fe0c1f --- /dev/null +++ b/rushs/tinyprintf/80cols_grep/80cols.grep @@ -0,0 +1 @@ +.\{80,\} diff --git a/rushs/tinyprintf/a.out b/rushs/tinyprintf/a.out Binary files differnew file mode 100755 index 0000000..33e84ed --- /dev/null +++ b/rushs/tinyprintf/a.out diff --git a/rushs/tinyprintf/add_int_ptr/add_int_ptr.c b/rushs/tinyprintf/add_int_ptr/add_int_ptr.c new file mode 100644 index 0000000..ad48639 --- /dev/null +++ b/rushs/tinyprintf/add_int_ptr/add_int_ptr.c @@ -0,0 +1,7 @@ +int *add_int_ptr(int *a, int *b) +{ + if (!a || !b) + return a; + *a += *b; + return a; +} diff --git a/rushs/tinyprintf/alphabet/alphabet.c b/rushs/tinyprintf/alphabet/alphabet.c new file mode 100644 index 0000000..9496c66 --- /dev/null +++ b/rushs/tinyprintf/alphabet/alphabet.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +int main(void) +{ + for (char i = 'a'; i < 'z'; i++) + { + putchar(i); + putchar(' '); + } + putchar('z'); + putchar('\n'); + return 0; +} diff --git a/rushs/tinyprintf/alphanum/alphanum.sh b/rushs/tinyprintf/alphanum/alphanum.sh new file mode 100755 index 0000000..e4c5aee --- /dev/null +++ b/rushs/tinyprintf/alphanum/alphanum.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +letters() +{ + grepped=$(echo "$1" | grep -E "^[a-zA-Z]+$") + [ "$1" = "$grepped" ] && return 0 || return 1 +} + +empty() +{ + if echo "$1" | grep -qE '^[[:space:]]+$'; then + return 0 + fi + return 1 +} + +digit() +{ + grepped=$(echo "$1" | grep -E "^[0-9]$") + [ "$1" = "$grepped" ] && return 0 || return 1 +} + +number() +{ + grepped=$(echo "$1" | grep -E "^[1-9][0-9]+$") + [ "$1" = "$grepped" ] && return 0 || return 1 +} + +alph() +{ + grepped=$(echo "$1" | grep -E "^[a-zA-Z0-9]+$") + [ "$1" = "$grepped" ] && return 0 || return 1 +} + +while IFS='' read -r str; do + if [ -z "$str" ]; then + echo it is empty + continue + elif letters "$str"; then + echo "it is a word" + elif number "$str"; then + echo "it is a number" + elif digit "$str"; then + echo "it is a digit" + elif empty "$str"; then + echo "it is empty" + elif alph "$str"; then + echo "it is an alphanum" + else + echo "it is too complicated" + exit + fi +done diff --git a/rushs/tinyprintf/array_max_min/array_max_min.c b/rushs/tinyprintf/array_max_min/array_max_min.c new file mode 100644 index 0000000..8b2d3a5 --- /dev/null +++ b/rushs/tinyprintf/array_max_min/array_max_min.c @@ -0,0 +1,23 @@ +#include <stddef.h> +#include <stdio.h> + +void array_max_min(int tab[], size_t len, int *max, int *min) +{ + if (tab && len) + { + *min = tab[0]; + *max = tab[0]; + + for (size_t i = 0; i < len; i++) + { + if (tab[i] > *max) + { + *max = tab[i]; + } + else if (tab[i] < *min) + { + *min = tab[i]; + } + } + } +} diff --git a/rushs/tinyprintf/ascii_carousel/rot_x.c b/rushs/tinyprintf/ascii_carousel/rot_x.c new file mode 100644 index 0000000..667106d --- /dev/null +++ b/rushs/tinyprintf/ascii_carousel/rot_x.c @@ -0,0 +1,26 @@ +#include <stddef.h> + +void rot_x(char *s, int x) +{ + if (s == NULL) + { + return; + } + + if (x < 0) + { + x = 26 + x; + } + + for (size_t i = 0; s[i]; i++) + { + if (s[i] >= 'a' && s[i] <= 'z') + { + s[i] = ((s[i] - 'a') + x) % 26 + 'a'; + } + else if (s[i] >= 'A' && s[i] <= 'Z') + { + s[i] = ((s[i] - 'A') + x) % 26 + 'A'; + } + } +} diff --git a/rushs/tinyprintf/ascii_house/ascii_house.sh b/rushs/tinyprintf/ascii_house/ascii_house.sh new file mode 100755 index 0000000..83d907e --- /dev/null +++ b/rushs/tinyprintf/ascii_house/ascii_house.sh @@ -0,0 +1,9 @@ +#!/bin/sh + + +echo ' /\' +echo ' / \' +echo -n "/____\\ \`" && echo "'\`" +echo -n "| | \`" && echo "'''\`" +echo "| | \`|\`" +echo '|_/\_|___|__' diff --git a/rushs/tinyprintf/assignment_operator/assignment_operator.c b/rushs/tinyprintf/assignment_operator/assignment_operator.c new file mode 100644 index 0000000..cae560f --- /dev/null +++ b/rushs/tinyprintf/assignment_operator/assignment_operator.c @@ -0,0 +1,37 @@ +void plus_equal(int *a, int *b) +{ + if (!a || !b) + { + return; + } + *a = *a + *b; +} + +void minus_equal(int *a, int *b) +{ + if (!a || !b) + { + return; + } + *a = *a - *b; +} + +void mult_equal(int *a, int *b) +{ + if (!a || !b) + { + return; + } + *a = *a * *b; +} + +int div_equal(int *a, int *b) +{ + if (!a || !b || *b == 0) + { + return 0; + } + int res = *a % *b; + *a = *a / *b; + return res; +} diff --git a/rushs/tinyprintf/binary_search_ptr/bsearch.c b/rushs/tinyprintf/binary_search_ptr/bsearch.c new file mode 100644 index 0000000..bdc189c --- /dev/null +++ b/rushs/tinyprintf/binary_search_ptr/bsearch.c @@ -0,0 +1,38 @@ +#include "bsearch.h" + +#include <stddef.h> + +int *binary_search(int *begin, int *end, int elt) +{ + if (begin == end) + { + return begin; + } + if (begin > end) + { + if (elt > *begin) + { + return begin + 1; + } + return begin; + } + + size_t m = (end - begin) / 2; + + if (begin[m] == elt) + { + return begin + m; + } + + if (begin[m] > elt) + { + return binary_search(begin, begin + m, elt); + } + + if (m == 0) + { + m++; + } + + return binary_search(begin + m, end, elt); +} diff --git a/rushs/tinyprintf/binary_search_ptr/bsearch.h b/rushs/tinyprintf/binary_search_ptr/bsearch.h new file mode 100644 index 0000000..e011744 --- /dev/null +++ b/rushs/tinyprintf/binary_search_ptr/bsearch.h @@ -0,0 +1,16 @@ +#ifndef BSEARCH_H_ +#define BSEARCH_H_ + +/* +** Search `elt` in the memory range of [`begin` - `end`[. +** `begin` is a pointer to the first element. +** `end` is a pointer **AFTER** the last element. +** The elements in the range [`begin` - `end`[ are sorted in ascending order. +** If the range is empty, `begin` == `end`. +** `begin` and `end` can't be `NULL`. +** Returns a pointer to the element if found, or a pointer to the memory +** location where the element could be inserted to keep the array sorted. +*/ +int *binary_search(int *begin, int *end, int elt); + +#endif /* !BSEARCH_H_ */ diff --git a/rushs/tinyprintf/binary_tree_dynamic/Makefile b/rushs/tinyprintf/binary_tree_dynamic/Makefile new file mode 100644 index 0000000..7fa9879 --- /dev/null +++ b/rushs/tinyprintf/binary_tree_dynamic/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wvla -Wextra -std=c99 -pedantic + +SRC = binary_tree.c binary_tree_print.c +OBJ = $(SRC:.c=.o) + +.PHONY: library clean + +library: $(OBJ) + ar csr libbinary_tree.a $(OBJ) + +$(OBJ): $(SRC) + +clean: + $(RM) libbinary_tree.a $(OBJ) diff --git a/rushs/tinyprintf/binary_tree_dynamic/binary_tree.c b/rushs/tinyprintf/binary_tree_dynamic/binary_tree.c new file mode 100644 index 0000000..6d99e99 --- /dev/null +++ b/rushs/tinyprintf/binary_tree_dynamic/binary_tree.c @@ -0,0 +1,95 @@ +#include "binary_tree.h" + +#include <stddef.h> +#include <stdio.h> + +int size(const struct binary_tree *tree) +{ + if (tree == NULL) + return 0; + + return 1 + size(tree->left) + size(tree->right); +} + +static int max(int a, int b) +{ + if (a > b) + return a; + return b; +} + +int height(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return -1; + } + + return 1 + max(height(tree->left), height(tree->right)); +} + +int is_perfect(const struct binary_tree *tree) +{ + if (tree == NULL) + return 1; + return height(tree->left) == height(tree->right) && is_perfect(tree->right) + && is_perfect(tree->right); +} + +int is_complete(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return 1; + } + + int hg = height(tree->left); + int hd = height(tree->right); + + if (hg - hd != 0 && hg - hd != 1) + { + return 0; + } + + return is_complete(tree->left) && is_complete(tree->right); +} + +int is_degenerate(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return 1; + } + + if (tree->left && tree->right) + { + return 0; + } + return is_degenerate(tree->left) && is_degenerate(tree->right); +} + +int is_full(const struct binary_tree *tree) +{ + if (tree == NULL) + return 1; + if ((tree->left && !tree->right) || (!tree->left && tree->right)) + return 0; + return is_full(tree->right) && is_full(tree->left); +} + +static int is_bzt(const struct binary_tree *tree, int min, int max) +{ + if (tree == NULL) + return 1; + if (tree->data > max || tree->data <= min) + return 0; + return is_bzt(tree->left, min, tree->data) + && is_bzt(tree->right, tree->data, max); +} + +int is_bst(const struct binary_tree *tree) +{ + if (tree == NULL) + return 1; + return is_bzt(tree, -2147483647, 2147483647); +} diff --git a/rushs/tinyprintf/binary_tree_dynamic/binary_tree.h b/rushs/tinyprintf/binary_tree_dynamic/binary_tree.h new file mode 100644 index 0000000..a08e4ef --- /dev/null +++ b/rushs/tinyprintf/binary_tree_dynamic/binary_tree.h @@ -0,0 +1,22 @@ +#ifndef BINARY_TREE_H +#define BINARY_TREE_H + +struct binary_tree +{ + int data; + struct binary_tree *left; + struct binary_tree *right; +}; + +int size(const struct binary_tree *tree); +int height(const struct binary_tree *tree); +void dfs_print_prefix(const struct binary_tree *tree); +void dfs_print_infix(const struct binary_tree *tree); +void dfs_print_postfix(const struct binary_tree *tree); +int is_perfect(const struct binary_tree *tree); +int is_complete(const struct binary_tree *tree); +int is_degenerate(const struct binary_tree *tree); +int is_full(const struct binary_tree *tree); +int is_bst(const struct binary_tree *tree); + +#endif /* !BINARY_TREE_H */ diff --git a/rushs/tinyprintf/binary_tree_dynamic/binary_tree_print.c b/rushs/tinyprintf/binary_tree_dynamic/binary_tree_print.c new file mode 100644 index 0000000..bce0f77 --- /dev/null +++ b/rushs/tinyprintf/binary_tree_dynamic/binary_tree_print.c @@ -0,0 +1,40 @@ +#include <stddef.h> +#include <stdio.h> + +#include "binary_tree.h" + +void dfs_print_prefix(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return; + } + + printf("%d ", tree->data); + dfs_print_prefix(tree->left); + dfs_print_prefix(tree->right); +} + +void dfs_print_infix(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return; + } + + dfs_print_infix(tree->left); + printf("%d ", tree->data); + dfs_print_infix(tree->right); +} + +void dfs_print_postfix(const struct binary_tree *tree) +{ + if (tree == NULL) + { + return; + } + + dfs_print_postfix(tree->left); + dfs_print_postfix(tree->right); + printf("%d ", tree->data); +} diff --git a/rushs/tinyprintf/bit_rotation/rol.c b/rushs/tinyprintf/bit_rotation/rol.c new file mode 100644 index 0000000..151ebb5 --- /dev/null +++ b/rushs/tinyprintf/bit_rotation/rol.c @@ -0,0 +1,5 @@ +unsigned char rol(unsigned char value, unsigned char roll) +{ + roll %= sizeof(unsigned char) * 8; + return (value << roll) | (value >> (8 * sizeof(unsigned char) - roll)); +} diff --git a/rushs/tinyprintf/bubble_sort/bubble_sort.c b/rushs/tinyprintf/bubble_sort/bubble_sort.c new file mode 100644 index 0000000..13d2ba3 --- /dev/null +++ b/rushs/tinyprintf/bubble_sort/bubble_sort.c @@ -0,0 +1,25 @@ +#include "bubble_sort.h" + +void bubble_sort(int array[], size_t size) +{ + if (!array || size == 0) + { + return; + } + + int mod; + do + { + mod = 0; + for (size_t i = 0; i < size - 1; i++) + { + if (array[i] > array[i + 1]) + { + mod = 1; + int tmp = array[i]; + array[i] = array[i + 1]; + array[i + 1] = tmp; + } + } + } while (mod); +} diff --git a/rushs/tinyprintf/bubble_sort/bubble_sort.h b/rushs/tinyprintf/bubble_sort/bubble_sort.h new file mode 100644 index 0000000..a33d531 --- /dev/null +++ b/rushs/tinyprintf/bubble_sort/bubble_sort.h @@ -0,0 +1,8 @@ +#ifndef BUBBLE_SORT_H +#define BUBBLE_SORT_H + +#include <stddef.h> + +void bubble_sort(int array[], size_t size); + +#endif /* !BUBBLE_SORT_H */ diff --git a/rushs/tinyprintf/check_alphabet/check_alphabet.c b/rushs/tinyprintf/check_alphabet/check_alphabet.c new file mode 100644 index 0000000..fc540b4 --- /dev/null +++ b/rushs/tinyprintf/check_alphabet/check_alphabet.c @@ -0,0 +1,25 @@ +#include "check_alphabet.h" + +#include <stddef.h> + +int check_alphabet(const char *str, const char *alphabet) +{ + if (alphabet == NULL || *alphabet == '\0') + { + return 1; + } + + for (int i = 0; alphabet[i]; i++) + { + int j; + for (j = 0; str[j] && str[j] != alphabet[i]; j++) + { + continue; + } + if (str[j] == '\0') + { + return 0; + } + } + return 1; +} diff --git a/rushs/tinyprintf/check_alphabet/check_alphabet.h b/rushs/tinyprintf/check_alphabet/check_alphabet.h new file mode 100644 index 0000000..667a20f --- /dev/null +++ b/rushs/tinyprintf/check_alphabet/check_alphabet.h @@ -0,0 +1,6 @@ +#ifndef CHECK_ALPHABET_H +#define CHECK_ALPHABET_H + +int check_alphabet(const char *str, const char *alphabet); + +#endif /* !CHECK_ALPHABET_H */ diff --git a/rushs/tinyprintf/clang-format/.clang-format b/rushs/tinyprintf/clang-format/.clang-format new file mode 100644 index 0000000..7ed8115 --- /dev/null +++ b/rushs/tinyprintf/clang-format/.clang-format @@ -0,0 +1,79 @@ +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: false +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterEnum: true + AfterClass: true + AfterControlStatement: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeComma +BreakStringLiterals: true +ColumnLimit: 80 +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +FixNamespaceComments: true +ForEachMacros: ['ILIST_FOREACH', 'ILIST_FOREACH_ENTRY'] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '<.*>' + Priority: 1 + - Regex: '.*' + Priority: 2 +IndentCaseLabels: false +IndentPPDirectives: AfterHash +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +NamespaceIndentation: All +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/rushs/tinyprintf/clang-format/zaza.c b/rushs/tinyprintf/clang-format/zaza.c new file mode 100644 index 0000000..a6eec9a --- /dev/null +++ b/rushs/tinyprintf/clang-format/zaza.c @@ -0,0 +1,78 @@ +#include <stdio.h> +#include <stdlib.h> +#define ZAZA_SIZE 4 + +static char get_zaza_char(size_t id) +{ + const int zaza[ZAZA_SIZE] = { + 10 * 10 + 2 * 10 + 2 * 10 / 10, + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 10 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + - (1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 + + 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1 * 1), + 122, + (38943 * 43 - 84393 / 34583 + + ) % 10 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + }; + switch (id * 2 + 4 - 2 + id * 4 - 2 + -5 * id) + + { + case (0): + return (zaza[0]); + case (1000 - 100 - 4 * 100 + 10 * 100 - 14 * 100 - (10 * 10 - 1)): + return (zaza[1]); + case (1 << 11 >> 3 << 5 >> 2 << 1 << 1 << 1 >> 1 >> 1 >> 1 << 5 >> 4 << 1 + >> 1 >> 2 >> 9): + return zaza[2]; + case (3 ^ 100) - (100 ^ 100) - (99 - 99) - (98 - 98) - (97 - 97) - (96 - 96) + - (95 - 95) - (94 - 94) - (93 - 93) - (92 - 92) - (91 - 91) - (90 - 90) + - (89 - 89) - (88 - 88) - (87 - 87) - (86 - 86) - (85 - 85) - (84 - 84) + - (83 - 83) - (82 - 82) - (81 - 81) - (80 - 80) - (79 - 79) - (78 - 78) + - (77 - 77) - (76 - 76) - (75 - 75) - (74 - 74) - (73 - 73) - (72 - 72) + - (71 - 71) - (70 - 70) - + + (69 - 69) - (68 - 68) - (67 - 67) - (66 - 66) - (65 - 65) - (64 - 64) + - (63 - 63) - (62 - 62) - (61 - 61) - (60 - 60) - (59 - 59) - (58 - 58) + - (57 - 57) - (56 - 56) - (55 - 55) - (54 - 54) - (53 - 53) - (52 - 52) + - (51 - 51) - 100 - (50 - 50) - (49 - 49) - (48 - 48) - (47 - 47) + - (46 - 46) - (45 - 45) - (44 - 44) - (43 - 43) - (42 - 42) - (41 - 41) + - (40 - 40) - (39 - 39) - (38 - 38) - (37 - 37) + + - (36 - 36) - (35 - 35) - (34 - 34) - (33 - 33) - (32 - 32) - (31 - 31) + - (30 - 30) - (29 - 29) - (28 - 28) - (27 - 27) - (26 - 26) - (25 - 25) + - (24 - 24) - (23 - 23) - (22 - 22) - (21 - 21) - (20 - 20) - (19 - 19) + - (18 - 18) - (17 - 17) - (16 - 16) - (15 - 15) - (14 - 14) - (13 - 13) + - (12 - 12) - (11 - 11) - (10 - 10) - (9 - 9) - (8 - 8) - (7 - 7) + - (6 - 6) - (5 - 5) - (4 - 4) - (3 - 3) - (2 - 2) - (1 - 1): + return (zaza[3]); + default: + return (0); + } +} +int main(void) +{ + for (size_t i = 0; i < ZAZA_SIZE; i += (i % 2 == 2 - 2) ? 1 % 2 : 1 % 2) + { + putchar(get_zaza_char(i)); + } + putchar('\n'); + return (0); +} diff --git a/rushs/tinyprintf/create_files/create_files.sh b/rushs/tinyprintf/create_files/create_files.sh new file mode 100755 index 0000000..28dba00 --- /dev/null +++ b/rushs/tinyprintf/create_files/create_files.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +touch ' ' +chmod 644 ' ' + +touch '\' +chmod 644 '\' + +touch -- -- +chmod 644 -- -- + +touch '|' +chmod 644 '|' + +touch '"' +chmod 644 '"' + +touch "'" +chmod 644 "'" + +touch -- --\$i*\'\"\\ +chmod 644 -- --\$i*\'\"\\ + +touch '# Exams are fun!' +chmod 644 '# Exams are fun!' + +touch ";\`kill -9 0\`" +chmod 644 ";\`kill -9 0\`" + +path="1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/41/42/43/44/45/46/47/48/49/50" + +mkdir -p "$path" +touch $path/farfaraway +chmod 644 $path/farfaraway diff --git a/rushs/tinyprintf/cut_csv/test.csv b/rushs/tinyprintf/cut_csv/test.csv new file mode 100644 index 0000000..d88282b --- /dev/null +++ b/rushs/tinyprintf/cut_csv/test.csv @@ -0,0 +1,15 @@ +James;Lebron;LABron;Lakers; +Davis;Anthony;Unibrow;Pelicans; +Mitchell;Donovan;Spida;Jazz; +Harden;James;TheBeard;Rockets; +Cousins;DeMarcus;Boogie;Wariors; +Embiid;Joel;TheProcess;76Sixers; +Bryant;Kobe;BlackMamba;Lakers; +Jordan;Michael;AirJordan;Bulls; +Johnson;Earvin;Magic;Lakers; +Howard;Dwight;Superman;Wizards; +Westbrook;Russel;MrTripleDouble;Thunder; +Durant;Kevin;KD;Wariors; +George;Paul;PG-13;Thunder; +Leonard;Kawhi;TheKlaw;Raptors; +Irving;Kyrie;UncleDrew;Celtics; diff --git a/rushs/tinyprintf/cut_csv/with_cut.sh b/rushs/tinyprintf/cut_csv/with_cut.sh new file mode 100755 index 0000000..9618f00 --- /dev/null +++ b/rushs/tinyprintf/cut_csv/with_cut.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +[ $# -ne 2 ] && exit 1 + +if ! [ -f "$1" ]; then + exit 1 +fi + +if ! [ "$2" -eq "$2" ] 2> /dev/null; then + exit 1 +fi + +[ "$2" -lt 0 ] && exit 1 + +if [ "$2" -gt "$(wc -l < "$1")" ]; then + exit 1 +fi + +line=$(head --lines="$2" "$1" 2> /dev/null | tail -n 1 | cut -d ';' -f 2-3 || exit 1) +c1=$(echo "$line" | cut -d ';' -f 1) +c2=$(echo "$line" | cut -d ';' -f 2) + +echo "$c1 is $c2" diff --git a/rushs/tinyprintf/cut_csv/with_sed.sh b/rushs/tinyprintf/cut_csv/with_sed.sh new file mode 100755 index 0000000..fb5e1f8 --- /dev/null +++ b/rushs/tinyprintf/cut_csv/with_sed.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +[ $# -ne 2 ] && exit 1 + +if ! [ -f "$1" ]; then + exit 1 +fi + +if ! [ "$2" -eq "$2" ] 2>/dev/null; then + exit 1 +fi + +[ "$2" -lt 0 ] && exit 1 + +if [ "$2" -gt $(wc -l < "$1") ]; then + exit 1 +fi + +i=1 + +while IFS= read -r line; do + [ "$i" -eq "$2" ] && echo "$line" | sed 's/^.*;\(.*\);\(.*\);.*;$/\1 is \2/' + i=$(($i + 1)) +done < "$1" diff --git a/rushs/tinyprintf/digit/digit.c b/rushs/tinyprintf/digit/digit.c new file mode 100644 index 0000000..5646b13 --- /dev/null +++ b/rushs/tinyprintf/digit/digit.c @@ -0,0 +1,13 @@ +unsigned int digit(int n, int k) +{ + if (n <= 0 || k <= 0) + { + return 0; + } + + for (int i = 0; i < k - 1; i++) + { + n /= 10; + } + return n % 10; +} diff --git a/rushs/tinyprintf/display_square/display_square.c b/rushs/tinyprintf/display_square/display_square.c new file mode 100644 index 0000000..9e834d7 --- /dev/null +++ b/rushs/tinyprintf/display_square/display_square.c @@ -0,0 +1,44 @@ +#include <stdio.h> + +void display_square(int width) +{ + if (width <= 0) + { + return; + } + + if (width % 2 == 0) + { + width++; + } + + if (width == 1) + { + putchar('*'); + putchar('\n'); + return; + } + + for (int i = 0; i < width; i++) + { + putchar('*'); + } + putchar('\n'); + + for (int i = 0; i < ((width - 3) / 2); i++) + { + putchar('*'); + for (int j = 0; j < width - 2; j++) + { + putchar(' '); + } + putchar('*'); + putchar('\n'); + } + + for (int i = 0; i < width; i++) + { + putchar('*'); + } + putchar('\n'); +} diff --git a/rushs/tinyprintf/dlist/Makefile b/rushs/tinyprintf/dlist/Makefile new file mode 100644 index 0000000..1251967 --- /dev/null +++ b/rushs/tinyprintf/dlist/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla + +SRC = dlist-1.c dlist-2.c dlist-3.c dlist-4.c +OBJ = $(SRC:.c=.o) + +.PHONY: library clean + +library: $(OBJ) + ar csr libdlist.a $(OBJ) + +clean: $(OBJ) + $(RM) *.a $(OBJ) + +$(OBJ): $(SRC) diff --git a/rushs/tinyprintf/dlist/dlist-1.c b/rushs/tinyprintf/dlist/dlist-1.c new file mode 100644 index 0000000..443ebca --- /dev/null +++ b/rushs/tinyprintf/dlist/dlist-1.c @@ -0,0 +1,78 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "dlist.h" + +struct dlist *dlist_init(void) +{ + struct dlist *res = malloc(sizeof(struct dlist)); + if (res == NULL) + return NULL; + + res->size = 0; + res->head = NULL; + res->tail = NULL; + return res; +} + +int dlist_push_front(struct dlist *list, int element) +{ + if (element < 0) + return 0; + struct dlist_item *new = malloc(sizeof(struct dlist_item)); + if (new == NULL) + return 0; + + new->data = element; + new->next = list->head; + new->prev = NULL; + + if (list->size == 0) + list->tail = new; + else + list->head->prev = new; + + list->head = new; + list->size++; + + return 1; +} + +void dlist_print(const struct dlist *list) +{ + if (list->size == 0) + return; + + for (struct dlist_item *i = list->head; i != list->tail; i = i->next) + { + printf("%d\n", i->data); + } + printf("%d\n", list->tail->data); +} + +int dlist_push_back(struct dlist *list, int element) +{ + if (element < 0) + return 0; + struct dlist_item *new = malloc(sizeof(struct dlist_item)); + if (new == NULL) + return 0; + + new->data = element; + new->prev = list->tail; + new->next = NULL; + + if (list->size == 0) + list->head = new; + else + list->tail->next = new; + list->tail = new; + list->size++; + + return 1; +} + +size_t dlist_size(const struct dlist *list) +{ + return list->size; +} diff --git a/rushs/tinyprintf/dlist/dlist-2.c b/rushs/tinyprintf/dlist/dlist-2.c new file mode 100644 index 0000000..5ccdaa3 --- /dev/null +++ b/rushs/tinyprintf/dlist/dlist-2.c @@ -0,0 +1,113 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "dlist.h" + +int dlist_get(const struct dlist *list, size_t index) +{ + if (index >= list->size) + return -1; + + struct dlist_item *i; + for (i = list->head; index; index--, i = i->next) + { + continue; + } + + return i->data; +} + +int dlist_insert_at(struct dlist *list, int element, size_t index) +{ + if (index > list->size || element < 0) + return 0; + else if (index == list->size) + dlist_push_back(list, element); + else if (index == 0) + dlist_push_front(list, element); + else + { + struct dlist_item *new = malloc(sizeof(struct dlist_item)); + if (new == NULL) + return 0; + new->data = element; + + struct dlist_item *i; + for (i = list->head; index - 1; index--, i = i->next) + continue; + new->next = i->next; + i->next->prev = new; + i->next = new; + new->prev = i; + list->size++; + } + return 1; +} + +int dlist_find(const struct dlist *list, int element) +{ + int index = 0; + struct dlist_item *i; + for (i = list->head; i && i->data != element; index++, i = i->next) + continue; + if (!i) + return -1; + return index; +} + +int dlist_remove_at(struct dlist *list, size_t index) +{ + if (index >= list->size) + return -1; + int res; + struct dlist_item *item; + if (list->size == 1) + { + item = list->head; + res = list->head->data; + list->head = NULL; + list->tail = NULL; + } + else if (index == 0) + { + item = list->head; + res = item->data; + item->next->prev = NULL; + list->head = item->next; + } + else if (index == list->size - 1) + { + item = list->tail; + res = item->data; + item->prev->next = NULL; + list->tail = item->prev; + } + else + { + for (item = list->head; index; index--, item = item->next) + continue; + + res = item->data; + item->prev->next = item->next; + item->next->prev = item->prev; + } + + free(item); + list->size--; + return res; +} + +void dlist_clear(struct dlist *list) +{ + if (list->size == 0) + return; + for (struct dlist_item *i = list->head; i;) + { + struct dlist_item *tmp = i->next; + free(i); + i = tmp; + } + list->size = 0; + list->head = NULL; + list->tail = NULL; +} diff --git a/rushs/tinyprintf/dlist/dlist-3.c b/rushs/tinyprintf/dlist/dlist-3.c new file mode 100644 index 0000000..22b4b52 --- /dev/null +++ b/rushs/tinyprintf/dlist/dlist-3.c @@ -0,0 +1,83 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "dlist.h" + +void dlist_map_square(struct dlist *list) +{ + for (struct dlist_item *i = list->head; i; i = i->next) + { + i->data *= i->data; + } +} + +void dlist_reverse(struct dlist *list) +{ + struct dlist_item *tmp; + for (struct dlist_item *i = list->head; i; i = i->prev) + { + tmp = i->next; + i->next = i->prev; + i->prev = tmp; + } + tmp = list->tail; + list->tail = list->head; + list->head = tmp; +} + +struct dlist *dlist_split_at(struct dlist *list, size_t index) +{ + if (list->size == 0) + return dlist_init(); + if (index >= list->size) + { + return NULL; + } + + struct dlist *new = dlist_init(); + if (new == NULL) + return NULL; + new->size = list->size - index; + list->size = index; + + struct dlist_item *i; + for (i = list->head; index; index--, i = i->next) + { + continue; + } + + new->head = i; + new->tail = list->tail; + list->tail = i->prev; + if (i->prev) + { + i->prev->next = NULL; + } + else + { + list->head = NULL; + } + i->prev = NULL; + return new; +} + +void dlist_concat(struct dlist *list1, struct dlist *list2) +{ + if (list2->head == NULL) + return; + if (list1->tail == NULL) + { + list1->head = list2->head; + list1->tail = list2->tail; + list1->size = list2->size; + return; + } + + list1->tail->next = list2->head; + list2->head->prev = list1->tail; + list1->tail = list2->tail; + list1->size += list2->size; + list2->size = 0; + list2->head = NULL; + list2->tail = NULL; +} diff --git a/rushs/tinyprintf/dlist/dlist-4.c b/rushs/tinyprintf/dlist/dlist-4.c new file mode 100644 index 0000000..9ed7aaa --- /dev/null +++ b/rushs/tinyprintf/dlist/dlist-4.c @@ -0,0 +1,97 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "dlist.h" + +size_t max(size_t a, size_t b) +{ + if (a >= b) + { + return a; + } + return b; +} + +size_t min(size_t a, size_t b) +{ + if (a <= b) + { + return a; + } + return b; +} + +size_t min_3(size_t a, size_t b, size_t c) +{ + if (a <= b) + { + if (a <= c) + { + return a; + } + return c; + } + else + { + if (b <= c) + { + return b; + } + return c; + } +} + +size_t my_strlen(const int *s) +{ + size_t i; + for (i = 0; s[i] != -1; i++) + { + continue; + } + return i; +} + +size_t levenshtein(const int *s1, const int *s2) +{ + size_t l1 = my_strlen(s1); + size_t l2 = my_strlen(s2); + if (min(l1, l2) == 0) + { + return max(l1, l2); + } + + if (s1[0] == s2[0]) + { + return levenshtein(s1 + 1, s2 + 1); + } + + size_t lev1 = levenshtein(s1 + 1, s2); + size_t lev2 = levenshtein(s1, s2 + 1); + size_t lev3 = levenshtein(s1 + 1, s2 + 1); + + return 1 + min_3(lev1, lev2, lev3); +} + +int *to_str(const struct dlist *l) +{ + int *res = malloc((l->size + 1) * sizeof(int)); + res[l->size] = -1; + size_t j = 0; + for (struct dlist_item *i = l->head; i; i = i->next, j++) + { + res[j] = i->data; + } + return res; +} + +unsigned int dlist_levenshtein(const struct dlist *list1, + const struct dlist *list2) +{ + int *l1 = to_str(list1); + int *l2 = to_str(list2); + + unsigned int res = levenshtein(l1, l2); + free(l1); + free(l2); + return res; +} diff --git a/rushs/tinyprintf/dlist/dlist.h b/rushs/tinyprintf/dlist/dlist.h new file mode 100644 index 0000000..97cde1a --- /dev/null +++ b/rushs/tinyprintf/dlist/dlist.h @@ -0,0 +1,44 @@ +#ifndef DLIST_H +#define DLIST_H + +#include <stddef.h> + +struct dlist_item +{ + int data; + struct dlist_item *next; + struct dlist_item *prev; +}; + +struct dlist +{ + size_t size; + struct dlist_item *head; + struct dlist_item *tail; +}; + +// Threshold 1 +struct dlist *dlist_init(void); +int dlist_push_front(struct dlist *list, int element); +void dlist_print(const struct dlist *list); +int dlist_push_back(struct dlist *list, int element); +size_t dlist_size(const struct dlist *list); + +// Threshold 2 +int dlist_get(const struct dlist *list, size_t index); +int dlist_insert_at(struct dlist *list, int element, size_t index); +int dlist_find(const struct dlist *list, int element); +int dlist_remove_at(struct dlist *list, size_t index); +void dlist_clear(struct dlist *list); + +// Threshold 3 +void dlist_map_square(struct dlist *list); +void dlist_reverse(struct dlist *list); +struct dlist *dlist_split_at(struct dlist *list, size_t index); +void dlist_concat(struct dlist *list1, struct dlist *list2); + +// Threshold 4 +unsigned int dlist_levenshtein(const struct dlist *list1, + const struct dlist *list2); + +#endif /* !DLIST_H */ diff --git a/rushs/tinyprintf/element_count/element_count.c b/rushs/tinyprintf/element_count/element_count.c new file mode 100644 index 0000000..cec47ae --- /dev/null +++ b/rushs/tinyprintf/element_count/element_count.c @@ -0,0 +1,10 @@ +#include "element_count.h" + +size_t element_count(int *begin, int *end) +{ + if (!begin || !end || begin >= end) + { + return 0; + } + return end - begin; +} diff --git a/rushs/tinyprintf/element_count/element_count.h b/rushs/tinyprintf/element_count/element_count.h new file mode 100644 index 0000000..57412ed --- /dev/null +++ b/rushs/tinyprintf/element_count/element_count.h @@ -0,0 +1,8 @@ +#ifndef ELEMENT_COUNT_H +#define ELEMENT_COUNT_H + +#include <stddef.h> + +size_t element_count(int *begin, int *end); + +#endif /* !ELEMENT_COUNT_H */ diff --git a/rushs/tinyprintf/evalexpr/Makefile b/rushs/tinyprintf/evalexpr/Makefile new file mode 100644 index 0000000..280f19c --- /dev/null +++ b/rushs/tinyprintf/evalexpr/Makefile @@ -0,0 +1,23 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wextra -pedantic -std=c99 -Wvla +AFLAGS = -fsanitize=address + +SRC=src/stack.c src/evalrpn.c src/shunting_yard.c src/fifo_access.c src/fifo_setup_destroy.c src/evalexpr.c +SRC_TEST=tests/unit_tests.c +#OBJ=src/stack.o src/evalrpn.o +OBJ=$(SRC:.c=.o) +#OBJ_TEST=$(SRC_TEST:.c=.o) + +all: $(OBJ) + $(CC) -o evalexpr $(OBJ) + +$(OBJ): $(SRC) + +check: #$(OBJ) $(OBJ_TEST) +# $(CC) $(CFLAGS) -o evaltest $(OBJ) $(OBJ_TEST) -lcriterion + tests/tests.sh + +.PHONY: clean + +clean: + rm $(OBJ) evalexpr diff --git a/rushs/tinyprintf/evalexpr/src/evalexpr.c b/rushs/tinyprintf/evalexpr/src/evalexpr.c new file mode 100644 index 0000000..5012355 --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/evalexpr.c @@ -0,0 +1,93 @@ +#include "evalexpr.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define BUFFER_SIZE 10 + +char *get_input(void) +{ + size_t r; + char buf[BUFFER_SIZE]; + size_t size = 0; + char *expr = malloc(size * sizeof(char) + 1); + if (expr == NULL) + return NULL; + expr[0] = '\0'; + do + { + r = fread(buf, sizeof(char), BUFFER_SIZE - 1, stdin); + if (r != 0) + { + buf[r] = '\0'; + size += r; + char *tmp = realloc(expr, size * sizeof(char) + 1); + if (tmp == NULL) + { + free(expr); + return NULL; + } + expr = tmp; + strcat(expr, buf); + } + } while (r != 0); + if (size == 0) + { + free(expr); + return NULL; + } + if (expr[size - 1] == '\n') + expr[size - 1] = '\0'; + return expr; +} + +void cleanup(char *expr, char *rpn) +{ + free(expr); + free(rpn); +} + +int main(int argc, char **argv) +{ + if ((argc == 2 && strcmp(argv[1], "-rpn") != 0) || (argc > 2)) + return 4; + char *expr = get_input(); + if (expr == NULL) + return 4; + if (argc == 1) + { + char *rpn; + int e = shunting_yard(expr, &rpn); + if (e != 0) + return e; + // call shunting yard + int retval; + e = evalrpn(rpn, &retval); + if (e != 0) + { + cleanup(expr, rpn); + return e; + } + // FREE RPN + printf("%d\n", retval); + cleanup(expr, rpn); + // return + return 0; + } + + if (argc == 2 && strcmp(argv[1], "-rpn") == 0) + { + // call rpn eval + int retval; + int e = evalrpn(expr, &retval); + printf("%d\n", retval); + // return + free(expr); + if (e != 0) + return e; + return 0; + } + + return 4; +} diff --git a/rushs/tinyprintf/evalexpr/src/evalexpr.h b/rushs/tinyprintf/evalexpr/src/evalexpr.h new file mode 100644 index 0000000..d440ae1 --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/evalexpr.h @@ -0,0 +1,43 @@ +#ifndef EVALEXPR_H +#define EVALEXPR_H + +#include <stddef.h> + +#include "fifo.h" +#include "stack.h" +#include "stack_struct.h" + +enum token_type +{ + NUMBER = 0, + SUB = 1, + ADD = 1, + MOD = 2, + DIV = 2, + MUL = 2, + EXP = 3, + UN_PLUS = 4, + UN_MINUS = 4, + PAR_LEFT = 5, + PAR_RIGHT = 5, + WRONG_TOKEN = -1, +}; + +struct token +{ + enum token_type type; + int value; +}; + +// evalrpn +int parse_number(const char *expr, size_t *offset); +int get_operands(struct stack **s, int *op1, int *op2); +int my_pow(int a, int b); +int evalrpn(const char *expr, int *retval); + +// shunting yard +int opcmp(struct token *op1, struct token *op2); +enum token_type get_type(char op); +int shunting_yard(const char *expr, char **rpn); + +#endif /* ! EVALEXPR_H */ diff --git a/rushs/tinyprintf/evalexpr/src/evalrpn.c b/rushs/tinyprintf/evalexpr/src/evalrpn.c new file mode 100644 index 0000000..db493eb --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/evalrpn.c @@ -0,0 +1,145 @@ +#include <ctype.h> + +#include "evalexpr.h" + +int parse_number(const char *expr, size_t *offset) +{ + for (*offset = 0; + expr[*offset] && expr[*offset] >= '0' && expr[*offset] <= '9'; + (*offset)++) + { + continue; + } + (*offset)--; + + int res = 0; + int pow = 1; + for (size_t n = 0; n <= *offset; n++, pow *= 10) + { + res += (expr[*offset - n] - '0') * pow; + } + + return res; +} + +int get_operands(struct stack **s, int *op1, int *op2) +{ + if (*s == NULL) + { + return 2; + } + *op1 = stack_peek(*s); + *s = stack_pop(*s); + if (*s == NULL) + { + return 2; + } + *op2 = stack_peek(*s); + *s = stack_pop(*s); + return 0; +} + +// Computes a to the bth +int my_pow(int a, int b) +{ + if (b == 0) + { + return 1; + } + if (a == 0) + { + return 0; + } + + int res = 1; + int c = b / 2; + while (c != 0) + { + res *= a * a; + c /= 2; + } + if (b % 2 != 0) + res *= a; + return res; +} + +int dispatch(const char c, struct stack **s, int op1, int op2) +{ + switch (c) + { + case '*': + *s = stack_push(*s, op1 * op2); + break; + case '+': + *s = stack_push(*s, op1 + op2); + break; + case '-': + *s = stack_push(*s, op2 - op1); + break; + case '/': + if (op1 == 0) + { + return 3; + } + *s = stack_push(*s, op2 / op1); + break; + case '%': + if (op1 == 0) + { + return 3; + } + *s = stack_push(*s, op2 % op1); + break; + case '^': + if (op1 < 0) + { + return 3; + } + *s = stack_push(*s, my_pow(op2, op1)); + break; + default: + return 1; + } + return 0; +} + +int evalrpn(const char *expr, int *retval) +{ + struct stack *s = NULL; + + for (size_t i = 0; expr[i]; i++) + { + if (expr[i] >= '0' && expr[i] <= '9') + { + size_t offset; + int val = parse_number(expr + i, &offset); + s = stack_push(s, val); + i += offset; + } + else if (isspace(expr[i])) + continue; + else + { + int op1; + int op2; + if (get_operands(&s, &op1, &op2) == 2) + { + return 2; + } + + int d = dispatch(expr[i], &s, op1, op2); + if (d != 0) + { + return d; + } + } + } + + if (s == NULL) + { + return 0; + } + *retval = stack_peek(s); + s = stack_pop(s); + return (!s) ? 0 : 2; +} diff --git a/rushs/tinyprintf/evalexpr/src/fifo.h b/rushs/tinyprintf/evalexpr/src/fifo.h new file mode 100644 index 0000000..b330eac --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/fifo.h @@ -0,0 +1,29 @@ +#ifndef FIFO_H +#define FIFO_H + +#include <stddef.h> + +#include "evalexpr.h" + +struct list +{ + struct token *data; + struct list *next; +}; + +struct fifo +{ + struct list *head; + struct list *tail; + size_t size; +}; + +struct fifo *fifo_init(void); +size_t fifo_size(struct fifo *fifo); +void fifo_push(struct fifo *fifo, struct token *elt); +struct token *fifo_head(struct fifo *fifo); +void fifo_pop(struct fifo *fifo); +void fifo_clear(struct fifo *fifo); +void fifo_destroy(struct fifo *fifo); + +#endif /* !FIFO_H */ diff --git a/rushs/tinyprintf/evalexpr/src/fifo_access.c b/rushs/tinyprintf/evalexpr/src/fifo_access.c new file mode 100644 index 0000000..1986a09 --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/fifo_access.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "fifo.h" + +size_t fifo_size(struct fifo *fifo) +{ + return fifo->size; +} + +void fifo_push(struct fifo *fifo, struct token *elt) +{ + struct list *new = malloc(sizeof(struct list)); + if (new == NULL) + { + return; + } + new->data = elt; + + if (fifo_size(fifo) == 0) + { + fifo->head = new; + } + new->next = NULL; + if (fifo_size(fifo) != 0) + { + fifo->tail->next = new; + } + fifo->tail = new; + + fifo->size++; +} + +struct token *fifo_head(struct fifo *fifo) +{ + return fifo->head->data; +} + +void fifo_pop(struct fifo *fifo) +{ + if (fifo_size(fifo) == 0) + { + return; + } + if (fifo_size(fifo) == 1) + { + free(fifo->head->data); + free(fifo->head); + fifo->head = NULL; + fifo->tail = NULL; + fifo->size = 0; + return; + } + + struct list *tmp = fifo->head->next; + free(fifo->head->data); + free(fifo->head); + fifo->head = tmp; + + fifo->size--; +} diff --git a/rushs/tinyprintf/evalexpr/src/fifo_setup_destroy.c b/rushs/tinyprintf/evalexpr/src/fifo_setup_destroy.c new file mode 100644 index 0000000..0f99ad0 --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/fifo_setup_destroy.c @@ -0,0 +1,44 @@ +#include <stdlib.h> + +#include "fifo.h" + +struct fifo *fifo_init(void) +{ + struct fifo *f = malloc(sizeof(struct fifo)); + if (f == NULL) + { + return NULL; + } + + f->size = 0; + f->head = NULL; + f->tail = NULL; + + return f; +} + +void fifo_clear(struct fifo *fifo) +{ + for (struct list *l = fifo->head; l != fifo->tail;) + { + struct list *tmp = l->next; + free(l->data); + free(l); + l = tmp; + } + if (fifo->tail) + { + free(fifo->tail->data); + free(fifo->tail); + } + + fifo->head = NULL; + fifo->tail = NULL; + fifo->size = 0; +} + +void fifo_destroy(struct fifo *fifo) +{ + fifo_clear(fifo); + free(fifo); +} diff --git a/rushs/tinyprintf/evalexpr/src/shunting_yard.c b/rushs/tinyprintf/evalexpr/src/shunting_yard.c new file mode 100644 index 0000000..2db5fc8 --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/shunting_yard.c @@ -0,0 +1,199 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "evalexpr.h" + +enum assoc +{ + NONE, + RIGHT, + LEFT, +}; + +int opcmp(struct token *op1, struct token *op2) +{ + return op1->type - op2->type; +} + +enum assoc get_assoc(struct token *op) +{ + if (op->type == EXP) + { + return RIGHT; + } + return LEFT; +} + +enum token_type get_type(char op) +{ + switch (op) + { + case '*': + return MUL; + case '/': + return DIV; + case '-': + return SUB; + case '+': + return ADD; + case '%': + return MOD; + case '^': + return EXP; + case '(': + return PAR_LEFT; + case ')': + return PAR_RIGHT; + default: + return WRONG_TOKEN; + } +} + +char *fifo_to_expr(struct fifo *output, size_t size_offset) +{ + char *res = malloc((2 * fifo_size(output) + size_offset) * sizeof(char)); + if (!res) + { + fifo_destroy(output); + return NULL; + } + res[2 * fifo_size(output) + size_offset - 1] = '\0'; + size_t i = 0; + while (fifo_size(output) > 0) + { + if (fifo_head(output)->type == NUMBER) + { + i += sprintf(res + i, "%d", fifo_head(output)->value) - 1; + } + else + { + res[i] = fifo_head(output)->value; + } + fifo_pop(output); + i++; + if (fifo_size(output) != 0) + { + res[i] = ' '; + i++; + } + } + fifo_destroy(output); + return res; +} + +int handle_rpar(struct tstack **opstack, struct fifo *output, struct token **t) +{ + while (*opstack) + { + struct token *o2 = tstack_peek(*opstack); + if (o2->value == '(') + { + free(o2); + break; + } + *opstack = tstack_pop(*opstack); + fifo_push(output, o2); + } + if (*opstack == NULL) + { + free(*t); + fifo_destroy(output); + return 2; + } + free(*t); + *opstack = tstack_pop(*opstack); + return 0; +} + +int empty_opstack(struct tstack **opstack, struct fifo *output) +{ + while (*opstack) + { + struct token *t = tstack_peek(*opstack); + if (t->value == '(' || t->value == ')') + { + fifo_destroy(output); + return 1; + } + *opstack = tstack_pop(*opstack); + fifo_push(output, t); + } + return 0; +} + +void pop_ops(struct tstack **opstack, struct fifo *output, struct token *t) +{ + while (*opstack) + { + struct token *o2 = tstack_peek(*opstack); + if (!(o2->value != '(' + && (opcmp(t, o2) < 0 + || (opcmp(t, o2) == 0 && get_assoc(t) == LEFT)))) + { + break; + } + + *opstack = tstack_pop(*opstack); + fifo_push(output, o2); + } +} + +void handle_numbers(struct fifo *output, size_t *i, int *size_offset, + const char *expr) +{ + size_t offset; + int val = parse_number(expr + *i, &offset); + struct token *t = malloc(sizeof(struct token)); + t->type = NUMBER; + t->value = val; + fifo_push(output, t); + *i += offset; + *size_offset += offset; +} + +int shunting_yard(const char *expr, char **rpn) +{ + struct fifo *output = fifo_init(); + struct tstack *opstack = NULL; + int size_offset = 0; + for (size_t i = 0; expr[i]; i++) + { + if (expr[i] >= '0' && expr[i] <= '9') + { + handle_numbers(output, &i, &size_offset, expr); + } + else if (expr[i] != ' ') + { + struct token *t = malloc(sizeof(struct token)); + t->value = expr[i]; + if ((t->type = get_type(expr[i])) == WRONG_TOKEN) + { + free(t); + return 1; + } + if (t->value == '(') + { + opstack = tstack_push(opstack, t); + continue; + } + else if (t->value == ')') + { + if (handle_rpar(&opstack, output, &t) != 0) + return 2; + continue; + } + pop_ops(&opstack, output, t); + opstack = tstack_push(opstack, t); + } + } + + if (empty_opstack(&opstack, output) != 0) + { + return 1; + } + *rpn = fifo_to_expr(output, size_offset); + if (!*rpn) + return 4; + + return 0; +} diff --git a/rushs/tinyprintf/evalexpr/src/stack.c b/rushs/tinyprintf/evalexpr/src/stack.c new file mode 100644 index 0000000..14f659e --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/stack.c @@ -0,0 +1,57 @@ +#include "stack.h" + +#include <stdlib.h> + +struct stack *stack_push(struct stack *s, int e) +{ + struct stack *new = malloc(sizeof(struct stack)); + new->data = e; + new->next = NULL; + + new->next = s; + return new; +} + +struct stack *stack_pop(struct stack *s) +{ + if (s == NULL) + { + return NULL; + } + + struct stack *res = s->next; + free(s); + return res; +} + +int stack_peek(struct stack *s) +{ + return s->data; +} + +struct tstack *tstack_push(struct tstack *s, struct token *e) +{ + struct tstack *new = malloc(sizeof(struct tstack)); + new->token = e; + new->next = NULL; + + new->next = s; + return new; +} + +struct tstack *tstack_pop(struct tstack *s) +{ + if (s == NULL) + { + return NULL; + } + + struct tstack *res = s->next; + free(s); + return res; +} + +struct token *tstack_peek(struct tstack *s) +{ + return s->token; +} diff --git a/rushs/tinyprintf/evalexpr/src/stack.h b/rushs/tinyprintf/evalexpr/src/stack.h new file mode 100644 index 0000000..d08e465 --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/stack.h @@ -0,0 +1,20 @@ +#ifndef STACK_H +#define STACK_H + +#include "evalexpr.h" +#include "stack_struct.h" + +struct tstack +{ + struct token *token; + struct tstack *next; +}; + +struct stack *stack_push(struct stack *s, int e); +struct stack *stack_pop(struct stack *s); +int stack_peek(struct stack *s); + +struct tstack *tstack_push(struct tstack *s, struct token *e); +struct tstack *tstack_pop(struct tstack *s); +struct token *tstack_peek(struct tstack *s); +#endif /* !STACK_H */ diff --git a/rushs/tinyprintf/evalexpr/src/stack_struct.h b/rushs/tinyprintf/evalexpr/src/stack_struct.h new file mode 100644 index 0000000..105cd5d --- /dev/null +++ b/rushs/tinyprintf/evalexpr/src/stack_struct.h @@ -0,0 +1,10 @@ +#ifndef STACK_STRUCT_H +#define STACK_STRUCT_H + +struct stack +{ + int data; + struct stack *next; +}; + +#endif /* ! STACK_STRUCT_H */ diff --git a/rushs/tinyprintf/evalexpr/tests/tests.sh b/rushs/tinyprintf/evalexpr/tests/tests.sh new file mode 100755 index 0000000..920f09b --- /dev/null +++ b/rushs/tinyprintf/evalexpr/tests/tests.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +REF_OUT="ref.out" +TEST_OUT="test.out" + +testrpn() +{ + echo "$2" > "$REF_OUT" + echo "Evaluating '$1' in RPN notation..." + echo "$1" | ./evalexpr -rpn > "$TEST_OUT" + diff "$REF_OUT" "$TEST_OUT" && echo "Success" +} + +testeval() +{ + echo "$1" | bc 2> /dev/null > "$REF_OUT" + echo "Evaluating '$1' in standard notation..." + echo "$1" | ./evalexpr > "$TEST_OUT" + diff "$REF_OUT" "$TEST_OUT" && echo "Success" +} + +testerror() +{ + echo "Testing error code '$2'..." + echo "$1" | ./evalexpr + error="$(echo $?)" + [ "$2" -eq "$error" ] && echo "Succesful failure" || echo "Wrong error $error" +} + +clean() +{ + rm "$REF_OUT" "$TEST_OUT" +} + +# RPN + +echo "Tests for RPN:" +echo "======" + +testrpn "1 1 +" 2 +testrpn "5 2 2 ^ 3 + *" 35 +testrpn "10 6 9 3 + 0 11 - * / * 17 + 5 +" 22 +testrpn "3 4 5 * 3 + -" "-20" +testrpn "3 2 % 9 3 1 2 + * / -" 0 + +echo +echo "=============================================" +echo + +# Standard + +echo "Tests for standard notation:" +echo "======" + +testeval "1 + 1" +testeval " 1 + 1 +1 " +testeval "2 * 2" +testeval "5 * (2 + 4)" +testeval "5 * (2 % 4)" +testeval " 5 *(2 ^4) " +testeval " 5 *(2 ^4 " + +echo +echo "=============================================" +echo + +# Errors + +echo "Error tests:" +echo "======" + +testerror "" 0 +testerror "a+1" 1 +testerror "1%0" 3 + +echo "Testing error code '4'..." +./evalexpr --toto 2> /dev/null +echo $? + +# Cleanup + +clean diff --git a/rushs/tinyprintf/evalexpr/tests/unit_tests.c b/rushs/tinyprintf/evalexpr/tests/unit_tests.c new file mode 100644 index 0000000..ed445a0 --- /dev/null +++ b/rushs/tinyprintf/evalexpr/tests/unit_tests.c @@ -0,0 +1,208 @@ +#include <criterion/criterion.h> +#include <criterion/assert.h> +#include <stddef.h> +#include <string.h> + +#include "../src/evalexpr.h" + +TestSuite(parse_number); + +Test(parse_number, parse_42) +{ + size_t o; + int actual = parse_number("42", &o); + cr_expect(actual == 42, "Attendu : %d, renvoyé : %d", 42, actual); + cr_expect(o == 1, "Décalage attendu : %d, renvoyé : %zu", 1, o); +} + +Test(parse_number, parse_4) +{ + size_t o; + int actual = parse_number("4", &o); + cr_expect(actual == 4, "Attendu : %d, renvoyé : %d", 4, actual); + cr_expect(o == 0, "Décalage attendu : %d, renvoyé : %zu", 0, o); +} + +TestSuite(my_pow); + +Test(my_pow, my_pow00) +{ + int actual = my_pow(0, 0); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} + +Test(my_pow, my_pown0) +{ + int actual = my_pow(50, 0); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} +Test(my_pow, my_pow0n) +{ + int actual = my_pow(0, 42); + cr_expect(actual == 0, "Attendu : %d, renvoyé : %d", 0, actual); +} +Test(my_pow, my_powab) +{ + int actual = my_pow(3,3); + cr_expect(actual == 27, "Attendu : %d, renvoyé : %d", 27, actual); +} +Test(my_pow, my_powab_2) +{ + int actual = my_pow(4, 2); + cr_expect(actual == 16, "Attendu : %d, renvoyé : %d", 16, actual); +} +Test(my_pow, my_powab_3) +{ + int actual = my_pow(10, 3); + cr_expect(actual == 1000, "Attendu : %d, renvoyé : %d", 1000, actual); +} +Test(my_pow, my_pow1n) +{ + int actual = my_pow(1, 50); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} + +TestSuite(RPN); + +Test(RPN, evalrpn_easiest) +{ + const char test[] = "1 1 +"; + int expected = 0; + int retval; + int res = 2; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_35) +{ + const char test[] = "5 2 2 ^ 3 + *"; + int expected = 0; + int retval; + int res = 35; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_22) +{ + const char test[] = "10 6 9 3 + 0 11 - * / * 17 + 5 +"; + int expected = 0; + int retval; + int res = 22; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_minus20) +{ + const char test[] = "3 4 5 * 3 + -"; + int expected = 0; + int retval; + int res = -20; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_zero) +{ + const char test[] = "3 2 % 9 3 1 2 + * / -"; + int expected = 0; + int retval; + int res = 0; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} + +TestSuite(Precedence); + +Test(Precedence, parenthesis_above_all) +{ + struct token pleft = { PAR_LEFT, '(' }; + struct token pright = { PAR_RIGHT, ')' }; + struct token unplus = { UN_PLUS, '+' }; + struct token exp = { EXP, '^' }; + struct token mul = { MUL, '*' }; + struct token minus = { SUB, '-' }; + int eq = opcmp(&pleft, &pright); + int sup = opcmp(&pleft, &unplus); + int inf = opcmp(&unplus, &pright); + int parftw = opcmp(&pleft, &exp); + int par4ever = opcmp(&pright, &mul); + int paragain = opcmp(&pright, &minus); + cr_expect(eq == 0, "Wrong order (equal)"); + cr_expect(sup > 0, "Wrong order (>)"); + cr_expect(inf < 0, "Wrong order (<)"); + cr_expect(parftw > 0, "Wrong order (>)"); + cr_expect(par4ever > 0, "Wrong order (>)"); + cr_expect(paragain > 0, "Wrong order (>)"); +} + +Test(Precedence, other_precedence_tests) +{ + struct token exp = { EXP, '^' }; + struct token mul = { MUL, '*' }; + struct token unplus = { UN_PLUS, '+' }; + struct token minus = { SUB, '-' }; + struct token plus = { ADD, '+' }; + int eq = opcmp(&minus, &plus); + int sup = opcmp(&exp, &mul); + int inf = opcmp(&plus, &unplus); + + cr_expect(eq == 0, "Wrong order (equal)"); + cr_expect(sup > 0, "Wrong order (>)"); + cr_expect(inf < 0, "Wrong order (<)"); +} + +TestSuite(ShuntingTests); + +Test(ShuntingTests, shunt_simplest) +{ + char *rpn; + const char *expr = "1 + 1"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "1 1 +") == 0, "Expected '1 1 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_nico) +{ + char *rpn; + const char *expr = "1 + 1 + 1"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "1 1 + 1 +") == 0, "Expected '1 1 + 1 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_harderdaddy) +{ + char *rpn; + const char *expr = "5*(2^2+3)"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "5 2 2 ^ 3 + *") == 0, "Expected '5 2 2 ^ 3 + *', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_numbers) +{ + char *rpn; + const char *expr = "42 + 50"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "42 50 +") == 0, "Expected '42 50 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_mod) +{ + char *rpn; + const char *expr = "42 % 50"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "42 50 %") == 0, "Expected '42 50 +', got %s", rpn); + free(rpn); +} diff --git a/rushs/tinyprintf/fact/fact.c b/rushs/tinyprintf/fact/fact.c new file mode 100644 index 0000000..1440c94 --- /dev/null +++ b/rushs/tinyprintf/fact/fact.c @@ -0,0 +1,8 @@ +unsigned long fact(unsigned n) +{ + if (n == 0) + { + return 1; + } + return n * fact(n - 1); +} diff --git a/rushs/tinyprintf/facto/facto.sh b/rushs/tinyprintf/facto/facto.sh new file mode 100755 index 0000000..350973a --- /dev/null +++ b/rushs/tinyprintf/facto/facto.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +[ $# -ne 1 ] && exit 1 +i=$1 +res=1 +while [ "$i" -gt 0 ]; do + res=$(($res * $i)) + i=$(($i - 1)) +done +echo "$res" diff --git a/rushs/tinyprintf/fibo/fibo.c b/rushs/tinyprintf/fibo/fibo.c new file mode 100644 index 0000000..99c0d79 --- /dev/null +++ b/rushs/tinyprintf/fibo/fibo.c @@ -0,0 +1,8 @@ +unsigned long fibonacci(unsigned long n) +{ + if (n == 0 || n == 1) + { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} diff --git a/rushs/tinyprintf/fibo_iter/fibo_iter.c b/rushs/tinyprintf/fibo_iter/fibo_iter.c new file mode 100644 index 0000000..36ebf46 --- /dev/null +++ b/rushs/tinyprintf/fibo_iter/fibo_iter.c @@ -0,0 +1,21 @@ +#include <stdio.h> + +unsigned long fibo_iter(unsigned long n) +{ + if (n == 0) + { + return 0; + } + unsigned long prev = 1; + unsigned long pprev = 0; + unsigned long i; + + for (i = 1; i < n; i++) + { + unsigned long next = pprev + prev; + pprev = prev; + prev = next; + } + + return prev; +} diff --git a/rushs/tinyprintf/fifo/Makefile b/rushs/tinyprintf/fifo/Makefile new file mode 100644 index 0000000..e5c9374 --- /dev/null +++ b/rushs/tinyprintf/fifo/Makefile @@ -0,0 +1,16 @@ +CC=gcc +CFLAGS=-std=c99 -Wall -Wextra -Wvla -Werror -pedantic + +.PHONY: library clean + +library: fifo_access.o fifo_setup_destroy.o + ar csr libfifo.a $^ + +fifo_access.o: fifo_access.c + $(CC) $(CFLAGS) -c -o fifo_access.o fifo_access.c + +fifo_setup_destroy.o: fifo_setup_destroy.c + $(CC) $(CFLAGS) -c -o fifo_setup_destroy.o fifo_setup_destroy.c + +clean: + rm *.o libfifo.a diff --git a/rushs/tinyprintf/fifo/fifo.h b/rushs/tinyprintf/fifo/fifo.h new file mode 100644 index 0000000..c4b0a6f --- /dev/null +++ b/rushs/tinyprintf/fifo/fifo.h @@ -0,0 +1,28 @@ +#ifndef FIFO_H +#define FIFO_H + +#include <stddef.h> + +struct list +{ + int data; + struct list *next; +}; + +struct fifo +{ + struct list *head; + struct list *tail; + size_t size; +}; + +struct fifo *fifo_init(void); +size_t fifo_size(struct fifo *fifo); +void fifo_push(struct fifo *fifo, int elt); +int fifo_head(struct fifo *fifo); +void fifo_pop(struct fifo *fifo); +void fifo_clear(struct fifo *fifo); +void fifo_destroy(struct fifo *fifo); +void fifo_print(const struct fifo *fifo); + +#endif /* !FIFO_H */ diff --git a/rushs/tinyprintf/fifo/fifo_access.c b/rushs/tinyprintf/fifo/fifo_access.c new file mode 100644 index 0000000..5d31586 --- /dev/null +++ b/rushs/tinyprintf/fifo/fifo_access.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "fifo.h" + +size_t fifo_size(struct fifo *fifo) +{ + return fifo->size; +} + +void fifo_push(struct fifo *fifo, int elt) +{ + struct list *new = malloc(sizeof(struct list)); + if (new == NULL) + { + return; + } + new->data = elt; + + if (fifo_size(fifo) == 0) + { + fifo->head = new; + } + new->next = NULL; + if (fifo_size(fifo) != 0) + { + fifo->tail->next = new; + } + fifo->tail = new; + + fifo->size++; +} + +int fifo_head(struct fifo *fifo) +{ + return fifo->head->data; +} + +void fifo_pop(struct fifo *fifo) +{ + if (fifo_size(fifo) == 0) + { + return; + } + if (fifo_size(fifo) == 1) + { + free(fifo->head); + fifo->head = NULL; + fifo->tail = NULL; + return; + } + + struct list *tmp = fifo->head->next; + free(fifo->head); + fifo->head = tmp; + + fifo->size--; +} + +void fifo_print(const struct fifo *fifo) +{ + for (struct list *l = fifo->head; l; l = l->next) + { + printf("%d\n", l->data); + } +} diff --git a/rushs/tinyprintf/fifo/fifo_setup_destroy.c b/rushs/tinyprintf/fifo/fifo_setup_destroy.c new file mode 100644 index 0000000..80820e1 --- /dev/null +++ b/rushs/tinyprintf/fifo/fifo_setup_destroy.c @@ -0,0 +1,39 @@ +#include <stdlib.h> + +#include "fifo.h" + +struct fifo *fifo_init(void) +{ + struct fifo *f = malloc(sizeof(struct fifo)); + if (f == NULL) + { + return NULL; + } + + f->size = 0; + f->head = NULL; + f->tail = NULL; + + return f; +} + +void fifo_clear(struct fifo *fifo) +{ + for (struct list *l = fifo->head; l != fifo->tail;) + { + struct list *tmp = l->next; + free(l); + l = tmp; + } + free(fifo->tail); + + fifo->head = NULL; + fifo->tail = NULL; + fifo->size = 0; +} + +void fifo_destroy(struct fifo *fifo) +{ + fifo_clear(fifo); + free(fifo); +} diff --git a/rushs/tinyprintf/find_ascii/find_ascii.sh b/rushs/tinyprintf/find_ascii/find_ascii.sh new file mode 100755 index 0000000..db31722 --- /dev/null +++ b/rushs/tinyprintf/find_ascii/find_ascii.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +for filename in $(ls "$1"); do + echo $1/$filename | file -f - | grep ASCII +done diff --git a/rushs/tinyprintf/freq_analysis/freq_analysis.c b/rushs/tinyprintf/freq_analysis/freq_analysis.c new file mode 100644 index 0000000..c60d7a6 --- /dev/null +++ b/rushs/tinyprintf/freq_analysis/freq_analysis.c @@ -0,0 +1,28 @@ +#include <stdio.h> + +int find_rank(int h[26], int min) +{ + int res = 0; + for (int i = 0; i < 26; i++) + { + res += h[i] > h[min] || (h[i] == h[min] && i < min); + } + return res; +} + +void freq_analysis(const char text[], const char table[]) +{ + int h[26] = { 0 }; + for (int i = 0; text[i]; i++) + { + h[text[i] - 'A']++; + } + + for (int j = 0; j < 26; j++) + { + if (h[j] != 0) + { + printf("%c %c\n", j + 'A', table[find_rank(h, j)]); + } + } +} diff --git a/rushs/tinyprintf/functional_programming/foldl.c b/rushs/tinyprintf/functional_programming/foldl.c new file mode 100644 index 0000000..ac222a7 --- /dev/null +++ b/rushs/tinyprintf/functional_programming/foldl.c @@ -0,0 +1,11 @@ +#include "functional_programming.h" + +int foldl(int *array, size_t len, int (*func)(int, int)) +{ + int acc = 0; + for (size_t i = 0; i < len; i++) + { + acc = (*func)(acc, array[i]); + } + return acc; +} diff --git a/rushs/tinyprintf/functional_programming/foldr.c b/rushs/tinyprintf/functional_programming/foldr.c new file mode 100644 index 0000000..c232410 --- /dev/null +++ b/rushs/tinyprintf/functional_programming/foldr.c @@ -0,0 +1,10 @@ +#include "functional_programming.h" + +int foldr(int *array, size_t len, int (*func)(int, int)) +{ + if (len == 1) + { + return (*func)(array[0], 0); + } + return (*func)(array[0], foldr(array + 1, len - 1, func)); +} diff --git a/rushs/tinyprintf/functional_programming/functional_programming.h b/rushs/tinyprintf/functional_programming/functional_programming.h new file mode 100644 index 0000000..429b13c --- /dev/null +++ b/rushs/tinyprintf/functional_programming/functional_programming.h @@ -0,0 +1,10 @@ +#ifndef FUNCTIONAL_PROGRAMMING_H +#define FUNCTIONAL_PROGRAMMING_H + +#include <stddef.h> + +void map(int *array, size_t len, void (*func)(int *)); +int foldr(int *array, size_t len, int (*func)(int, int)); +int foldl(int *array, size_t len, int (*func)(int, int)); + +#endif /* !FUNCTIONAL_PROGRAMMING_H */ diff --git a/rushs/tinyprintf/functional_programming/map.c b/rushs/tinyprintf/functional_programming/map.c new file mode 100644 index 0000000..311c39c --- /dev/null +++ b/rushs/tinyprintf/functional_programming/map.c @@ -0,0 +1,9 @@ +#include "functional_programming.h" + +void map(int *array, size_t len, void (*func)(int *)) +{ + for (size_t i = 0; i < len; i++) + { + (*func)(array + i); + } +} diff --git a/rushs/tinyprintf/generate_files/generate_files.sh b/rushs/tinyprintf/generate_files/generate_files.sh new file mode 100755 index 0000000..cf2ba0a --- /dev/null +++ b/rushs/tinyprintf/generate_files/generate_files.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +FILENAME="default" +NUMBER="1" +EXTENSION="txt" + +while [ $# -gt 0 ]; do + case "$1" in + '-f' | '--filename') + shift + FILENAME="$1" + shift + ;; + '-n' | '--number') + shift + NUMBER="$1" + shift + ;; + '-e' | '--extension') + shift + EXTENSION="$1" + shift + ;; + *) + exit 1 + ;; + esac +done + +for i in $(seq 1 $NUMBER); do + touch -- "$FILENAME-$i.$EXTENSION" +done diff --git a/rushs/tinyprintf/generic_void_list/list.c b/rushs/tinyprintf/generic_void_list/list.c new file mode 100644 index 0000000..20ecfa8 --- /dev/null +++ b/rushs/tinyprintf/generic_void_list/list.c @@ -0,0 +1,36 @@ +#include "list.h" + +#include <stdlib.h> +#include <string.h> + +struct list *list_prepend(struct list *list, const void *value, + size_t data_size) +{ + struct list *new = malloc(sizeof(struct list)); + new->next = list; + new->data = malloc(sizeof(void *)); + memcpy(new->data, value, data_size); + return new; +} + +size_t list_length(struct list *list) +{ + size_t res = 0; + while (list) + { + res++; + list = list->next; + } + return res; +} + +void list_destroy(struct list *list) +{ + while (list) + { + struct list *tmp = list->next; + free(list->data); + free(list); + list = tmp; + } +} diff --git a/rushs/tinyprintf/generic_void_list/list.h b/rushs/tinyprintf/generic_void_list/list.h new file mode 100644 index 0000000..a1bc035 --- /dev/null +++ b/rushs/tinyprintf/generic_void_list/list.h @@ -0,0 +1,31 @@ +#ifndef LIST_H +#define LIST_H + +#include <stddef.h> + +struct list +{ + void *data; + struct list *next; +}; + +/* +** Insert a node containing `value` at the beginning of the list. +** Return `NULL` if an error occurred. +*/ +struct list *list_prepend(struct list *list, const void *value, + size_t data_size); + +/* +** Return the length of the list. +** Return `0` if the list is empty. +*/ +size_t list_length(struct list *list); + +/* +** Release the memory used by the list. +** Does nothing if `list` is `NULL`. +*/ +void list_destroy(struct list *list); + +#endif /* !LIST_H */ diff --git a/rushs/tinyprintf/glob_easy/glob_easy.sh b/rushs/tinyprintf/glob_easy/glob_easy.sh new file mode 100755 index 0000000..b6ae028 --- /dev/null +++ b/rushs/tinyprintf/glob_easy/glob_easy.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo $1/*.[A-Za-z][A-Za-z] diff --git a/rushs/tinyprintf/glob_remove_shell/glob_remove_shell.sh b/rushs/tinyprintf/glob_remove_shell/glob_remove_shell.sh new file mode 100755 index 0000000..c2e7ff7 --- /dev/null +++ b/rushs/tinyprintf/glob_remove_shell/glob_remove_shell.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +fmt=*.${1:-"txt"} + +for file in $(echo "$fmt"); do + [ -e "$file" ] && rm "$file" || exit 1 +done diff --git a/rushs/tinyprintf/grade/grade.c b/rushs/tinyprintf/grade/grade.c new file mode 100644 index 0000000..caecc82 --- /dev/null +++ b/rushs/tinyprintf/grade/grade.c @@ -0,0 +1,29 @@ +#include <stdio.h> + +void grade(char g) +{ + switch (g) + { + case 'A': + puts("Excellent"); + break; + case 'B': + puts("Good"); + break; + case 'C': + puts("Not so bad"); + break; + case 'D': + puts("Could be worse"); + break; + case 'E': + puts("Maybe next time"); + break; + case 'F': + puts("No comment"); + break; + default: + puts("Call a wild ACU"); + break; + } +} diff --git a/rushs/tinyprintf/greatest_divisor/greatest_divisor.c b/rushs/tinyprintf/greatest_divisor/greatest_divisor.c new file mode 100644 index 0000000..4c8efef --- /dev/null +++ b/rushs/tinyprintf/greatest_divisor/greatest_divisor.c @@ -0,0 +1,15 @@ +unsigned int greatest_divisor(unsigned int n) +{ + if (n == 0 || n == 1) + { + return 1; + } + + int i; + for (i = n / 2; i > 0 && n % i; i--) + { + continue; + } + + return i; +} diff --git a/rushs/tinyprintf/hacker_news/input.html b/rushs/tinyprintf/hacker_news/input.html new file mode 100644 index 0000000..54d338d --- /dev/null +++ b/rushs/tinyprintf/hacker_news/input.html @@ -0,0 +1,147 @@ +<html op="news" class=" lddwcbt idc0_332" lang="en"><head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta name="referrer" content="origin"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" type="text/css" href="02_files/news.css"> + <link rel="shortcut icon" href="https://news.ycombinator.com/favicon.ico"> + <link rel="alternate" type="application/rss+xml" title="RSS" href="https://news.ycombinator.com/rss"> + <title>Hacker News</title></head><body><center><table id="hnmain" width="85%" cellspacing="0" cellpadding="0" border="0" bgcolor="#f6f6ef"> + <tbody><tr><td bgcolor="#ff6600"><table style="padding:2px" width="100%" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td style="width:18px;padding-right:4px"><a href="https://news.ycombinator.com/"><img src="02_files/y18.gif" style="border:1px white solid;" width="18" height="18"></a></td> + <td style="line-height:12pt; height:10px;"><span class="pagetop"><b class="hnname"><a href="https://news.ycombinator.com/news">Hacker News</a></b> + <a href="https://news.ycombinator.com/newest">new</a> | <a href="https://news.ycombinator.com/front">past</a> | <a href="https://news.ycombinator.com/newcomments">comments</a> | <a href="https://news.ycombinator.com/ask">ask</a> | <a href="https://news.ycombinator.com/show">show</a> | <a href="https://news.ycombinator.com/jobs">jobs</a> | <a href="https://news.ycombinator.com/submit">submit</a> </span></td><td style="text-align:right;padding-right:4px;"><span class="pagetop"> + <a href="https://news.ycombinator.com/login?goto=news%3Fp%3D2">login</a> + </span></td> + </tr></tbody></table></td></tr> +<tr id="pagespace" title="" style="height:10px"></tr><tr><td><table class="itemlist" cellspacing="0" cellpadding="0" border="0"> + <tbody><tr class="athing" id="28943869"> + <td class="title" valign="top" align="right"><span class="rank">31.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943869" href="https://news.ycombinator.com/vote?id=28943869&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://apnews.com/article/technology-business-arts-and-entertainment-be48d7582fdd5604664fff33ed81ca80" class="titlelink">Sinclair Broadcast Group identifies data breach</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=apnews.com"><span class="sitestr">apnews.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943869">8 points</span> by <a href="https://news.ycombinator.com/user?id=xojoc" class="hnuser">xojoc</a> <span class="age" title="2021-10-21T13:12:05"><a href="https://news.ycombinator.com/item?id=28943869">1 hour ago</a></span> <span id="unv_28943869"></span> | <a href="https://news.ycombinator.com/hide?id=28943869&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943869">1 comment</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28926775"> + <td class="title" valign="top" align="right"><span class="rank">32.</span></td> <td class="votelinks" valign="top"><center><a id="up_28926775" href="https://news.ycombinator.com/vote?id=28926775&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.earlevel.com/main/2002/08/31/a-gentle-introduction-to-the-fft/" class="titlelink">A gentle introduction to the FFT (2002)</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=earlevel.com"><span class="sitestr">earlevel.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28926775">71 points</span> by <a href="https://news.ycombinator.com/user?id=tigerlily" class="hnuser">tigerlily</a> <span class="age" title="2021-10-20T04:31:20"><a href="https://news.ycombinator.com/item?id=28926775">12 hours ago</a></span> <span id="unv_28926775"></span> | <a href="https://news.ycombinator.com/hide?id=28926775&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28926775">14 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28930157"> + <td class="title" valign="top" align="right"><span class="rank">33.</span></td> <td class="votelinks" valign="top"><center><a id="up_28930157" href="https://news.ycombinator.com/vote?id=28930157&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://thebrowser.com/notes/jon-ingold/" class="titlelink">Jon Ingold on translating archeology into video games</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=thebrowser.com"><span class="sitestr">thebrowser.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28930157">36 points</span> by <a href="https://news.ycombinator.com/user?id=nupitalnumber" class="hnuser">nupitalnumber</a> <span class="age" title="2021-10-20T13:04:53"><a href="https://news.ycombinator.com/item?id=28930157">9 hours ago</a></span> <span id="unv_28930157"></span> | <a href="https://news.ycombinator.com/hide?id=28930157&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28930157">4 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28943611"> + <td class="title" valign="top" align="right"><span class="rank">34.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943611" href="https://news.ycombinator.com/vote?id=28943611&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://news.ycombinator.com/item?id=28943611" class="titlelink">Ask HN: How to Sell a Website</a></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943611">7 points</span> by <a href="https://news.ycombinator.com/user?id=legrisch" class="hnuser">legrisch</a> <span class="age" title="2021-10-21T12:45:35"><a href="https://news.ycombinator.com/item?id=28943611">1 hour ago</a></span> <span id="unv_28943611"></span> | <a href="https://news.ycombinator.com/hide?id=28943611&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943611">3 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28933391"> + <td class="title" valign="top" align="right"><span class="rank">35.</span></td> <td class="votelinks" valign="top"><center><a id="up_28933391" href="https://news.ycombinator.com/vote?id=28933391&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://iconmap.io/blog" class="titlelink">We analyzed 425k favicons</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=iconmap.io"><span class="sitestr">iconmap.io</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28933391">493 points</span> by <a href="https://news.ycombinator.com/user?id=gurgeous" class="hnuser">gurgeous</a> <span class="age" title="2021-10-20T17:29:03"><a href="https://news.ycombinator.com/item?id=28933391">20 hours ago</a></span> <span id="unv_28933391"></span> | <a href="https://news.ycombinator.com/hide?id=28933391&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28933391">119 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28938551"> + <td class="title" valign="top" align="right"><span class="rank">36.</span></td> <td class="votelinks" valign="top"><center><a id="up_28938551" href="https://news.ycombinator.com/vote?id=28938551&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.science.org/content/article/machu-picchu-was-built-over-major-fault-zones-now-researchers-think-they-know-why" class="titlelink">Machu Picchu was built over major fault zones (2019)</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=science.org"><span class="sitestr">science.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28938551">98 points</span> by <a href="https://news.ycombinator.com/user?id=Anon84" class="hnuser">Anon84</a> <span class="age" title="2021-10-21T00:07:54"><a href="https://news.ycombinator.com/item?id=28938551">14 hours ago</a></span> <span id="unv_28938551"></span> | <a href="https://news.ycombinator.com/hide?id=28938551&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28938551">41 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940507"> + <td class="title" valign="top" align="right"><span class="rank">37.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940507" href="https://news.ycombinator.com/vote?id=28940507&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://brave.com/wp-content/uploads/2021/03/goggles.pdf" class="titlelink">Goggles: Democracy dies in darkness, and so does the Web [pdf]</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=brave.com"><span class="sitestr">brave.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940507">114 points</span> by <a href="https://news.ycombinator.com/user?id=InvaderFizz" class="hnuser">InvaderFizz</a> <span class="age" title="2021-10-21T05:03:56"><a href="https://news.ycombinator.com/item?id=28940507">9 hours ago</a></span> <span id="unv_28940507"></span> | <a href="https://news.ycombinator.com/hide?id=28940507&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940507">119 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28933663"> + <td class="title" valign="top" align="right"><span class="rank">38.</span></td> <td class="votelinks" valign="top"><center><a id="up_28933663" href="https://news.ycombinator.com/vote?id=28933663&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://browser.geekbench.com/v5/cpu/10496766" class="titlelink">Apple M1 Max Geekbench Score</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=geekbench.com"><span class="sitestr">geekbench.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28933663">467 points</span> by <a href="https://news.ycombinator.com/user?id=mv9" class="hnuser">mv9</a> <span class="age" title="2021-10-20T17:50:17"><a href="https://news.ycombinator.com/item?id=28933663">20 hours ago</a></span> <span id="unv_28933663"></span> | <a href="https://news.ycombinator.com/hide?id=28933663&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28933663">771 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28933981"> + <td class="title" valign="top" align="right"><span class="rank">39.</span></td> <td class="votelinks" valign="top"><center><a id="up_28933981" href="https://news.ycombinator.com/vote?id=28933981&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.commerce.gov/news/press-releases/2021/10/commerce-tightens-export-controls-items-used-surveillance-private" class="titlelink">U.S. tightens export controls on items used in surveillance of private citizens</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=commerce.gov"><span class="sitestr">commerce.gov</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28933981">275 points</span> by <a href="https://news.ycombinator.com/user?id=transpute" class="hnuser">transpute</a> <span class="age" title="2021-10-20T18:14:33"><a href="https://news.ycombinator.com/item?id=28933981">20 hours ago</a></span> <span id="unv_28933981"></span> | <a href="https://news.ycombinator.com/hide?id=28933981&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28933981">161 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28943645"> + <td class="title" valign="top" align="right"><span class="rank">40.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943645" href="https://news.ycombinator.com/vote?id=28943645&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.wsj.com/articles/wework-set-to-go-public-via-spac-deal-two-years-after-failed-ipo-11634808600" class="titlelink" rel="nofollow">WeWork is trying to go public – again</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=wsj.com"><span class="sitestr">wsj.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943645">8 points</span> by <a href="https://news.ycombinator.com/user?id=collegeburner" class="hnuser">collegeburner</a> <span class="age" title="2021-10-21T12:49:02"><a href="https://news.ycombinator.com/item?id=28943645">1 hour ago</a></span> <span id="unv_28943645"></span> | <a href="https://news.ycombinator.com/hide?id=28943645&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943645">2 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28934624"> + <td class="title" valign="top" align="right"><span class="rank">41.</span></td> <td class="votelinks" valign="top"><center><a id="up_28934624" href="https://news.ycombinator.com/vote?id=28934624&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.copetti.org/writings/consoles/playstation-3/" class="titlelink">Playstation 3 Architecture</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=copetti.org"><span class="sitestr">copetti.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28934624">362 points</span> by <a href="https://news.ycombinator.com/user?id=bangonkeyboard" class="hnuser">bangonkeyboard</a> <span class="age" title="2021-10-20T18:56:53"><a href="https://news.ycombinator.com/item?id=28934624">19 hours ago</a></span> <span id="unv_28934624"></span> | <a href="https://news.ycombinator.com/hide?id=28934624&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28934624">81 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28929639"> + <td class="title" valign="top" align="right"><span class="rank">42.</span></td> <td class="votelinks" valign="top"><center><a id="up_28929639" href="https://news.ycombinator.com/vote?id=28929639&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://owlpal.substack.com/p/about-that-time-i-had-an-outburst" class="titlelink">About that time I had an outburst during the Y Combinator Interview</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=owlpal.substack.com"><span class="sitestr">owlpal.substack.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28929639">498 points</span> by <a href="https://news.ycombinator.com/user?id=curiousowl" class="hnuser">curiousowl</a> <span class="age" title="2021-10-20T12:03:25"><a href="https://news.ycombinator.com/item?id=28929639">1 day ago</a></span> <span id="unv_28929639"></span> | <a href="https://news.ycombinator.com/hide?id=28929639&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28929639">242 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28938378"> + <td class="title" valign="top" align="right"><span class="rank">43.</span></td> <td class="votelinks" valign="top"><center><a id="up_28938378" href="https://news.ycombinator.com/vote?id=28938378&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.guernicamag.com/one-mans-pest/" class="titlelink" rel="nofollow">One Man's Pest</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=guernicamag.com"><span class="sitestr">guernicamag.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28938378">8 points</span> by <a href="https://news.ycombinator.com/user?id=yimby" class="hnuser">yimby</a> <span class="age" title="2021-10-20T23:47:13"><a href="https://news.ycombinator.com/item?id=28938378">6 hours ago</a></span> <span id="unv_28938378"></span> | <a href="https://news.ycombinator.com/hide?id=28938378&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28938378">discuss</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28926582"> + <td class="title" valign="top" align="right"><span class="rank">44.</span></td> <td class="votelinks" valign="top"><center><a id="up_28926582" href="https://news.ycombinator.com/vote?id=28926582&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://brave.com/search-and-web-discovery/" class="titlelink">Brave Search replaces Google as default search engine in the Brave browser</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=brave.com"><span class="sitestr">brave.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28926582">723 points</span> by <a href="https://news.ycombinator.com/user?id=skellertor" class="hnuser">skellertor</a> <span class="age" title="2021-10-20T03:56:51"><a href="https://news.ycombinator.com/item?id=28926582">1 day ago</a></span> <span id="unv_28926582"></span> | <a href="https://news.ycombinator.com/hide?id=28926582&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28926582">528 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28943866"> + <td class="title" valign="top" align="right"><span class="rank">45.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943866" href="https://news.ycombinator.com/vote?id=28943866&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://twitter.com//rashiq/status/1319346264992026624" class="titlelink" rel="nofollow">I reverse engineered mcdonald's internal API</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=twitter.com/rashiq"><span class="sitestr">twitter.com/rashiq</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943866">3 points</span> by <a href="https://news.ycombinator.com/user?id=graderjs" class="hnuser">graderjs</a> <span class="age" title="2021-10-21T13:11:46"><a href="https://news.ycombinator.com/item?id=28943866">1 hour ago</a></span> <span id="unv_28943866"></span> | <a href="https://news.ycombinator.com/hide?id=28943866&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943866">discuss</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28936324"> + <td class="title" valign="top" align="right"><span class="rank">46.</span></td> <td class="votelinks" valign="top"><center><a id="up_28936324" href="https://news.ycombinator.com/vote?id=28936324&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.science.org/doi/10.1126/scisignal.abc4764" class="titlelink">Injury response to DNA damage in live tumor cells promotes antitumor immunity</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=science.org"><span class="sitestr">science.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28936324">109 points</span> by <a href="https://news.ycombinator.com/user?id=bcaulfield" class="hnuser">bcaulfield</a> <span class="age" title="2021-10-20T20:48:40"><a href="https://news.ycombinator.com/item?id=28936324">17 hours ago</a></span> <span id="unv_28936324"></span> | <a href="https://news.ycombinator.com/hide?id=28936324&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28936324">5 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940197"> + <td class="title" valign="top" align="right"><span class="rank">47.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940197" href="https://news.ycombinator.com/vote?id=28940197&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.cowin.gov.in/" class="titlelink">India Counting Down to 1B Doses</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=cowin.gov.in"><span class="sitestr">cowin.gov.in</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940197">105 points</span> by <a href="https://news.ycombinator.com/user?id=neelkadia" class="hnuser">neelkadia</a> <span class="age" title="2021-10-21T04:17:41"><a href="https://news.ycombinator.com/item?id=28940197">10 hours ago</a></span> <span id="unv_28940197"></span> | <a href="https://news.ycombinator.com/hide?id=28940197&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940197">78 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28943066"> + <td class="title" valign="top" align="right"><span class="rank">48.</span></td> <td class="votelinks" valign="top"><center><a id="up_28943066" href="https://news.ycombinator.com/vote?id=28943066&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://slate.com/technology/2021/10/tether-crypto-danger-ben-mckenzie.html" class="titlelink" rel="nofollow">Time to get worried about Tether, the “stablecoin†at center of cryptocurrency</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=slate.com"><span class="sitestr">slate.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28943066">6 points</span> by <a href="https://news.ycombinator.com/user?id=RickJWagner" class="hnuser">RickJWagner</a> <span class="age" title="2021-10-21T11:45:09"><a href="https://news.ycombinator.com/item?id=28943066">2 hours ago</a></span> <span id="unv_28943066"></span> | <a href="https://news.ycombinator.com/hide?id=28943066&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28943066">5 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940258"> + <td class="title" valign="top" align="right"><span class="rank">49.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940258" href="https://news.ycombinator.com/vote?id=28940258&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.alifewithoutlimits.com.au/the-history-of-surveying/" class="titlelink">The History of Surveying</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=alifewithoutlimits.com.au"><span class="sitestr">alifewithoutlimits.com.au</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940258">20 points</span> by <a href="https://news.ycombinator.com/user?id=barbazoo" class="hnuser">barbazoo</a> <span class="age" title="2021-10-21T04:27:11"><a href="https://news.ycombinator.com/item?id=28940258">9 hours ago</a></span> <span id="unv_28940258"></span> | <a href="https://news.ycombinator.com/hide?id=28940258&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940258">9 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28921244"> + <td class="title" valign="top" align="right"><span class="rank">50.</span></td> <td class="votelinks" valign="top"><center><a id="up_28921244" href="https://news.ycombinator.com/vote?id=28921244&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.npr.org/2021/10/19/1047303559/fda-hearing-aid-prescription-over-the-counter" class="titlelink">The FDA wants you to be able to buy a hearing aid without a prescription</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=npr.org"><span class="sitestr">npr.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28921244">722 points</span> by <a href="https://news.ycombinator.com/user?id=cf100clunk" class="hnuser">cf100clunk</a> <span class="age" title="2021-10-19T17:58:42"><a href="https://news.ycombinator.com/item?id=28921244">1 day ago</a></span> <span id="unv_28921244"></span> | <a href="https://news.ycombinator.com/hide?id=28921244&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28921244">441 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28942594"> + <td class="title" valign="top" align="right"><span class="rank">51.</span></td> <td class="votelinks" valign="top"><center><a id="up_28942594" href="https://news.ycombinator.com/vote?id=28942594&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.pcgamer.com/windows-11-pcs-can-hobble-gaming-performance/" class="titlelink">Windows 11 will hobble gaming performance by default on some prebuilt PCs</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=pcgamer.com"><span class="sitestr">pcgamer.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28942594">13 points</span> by <a href="https://news.ycombinator.com/user?id=DeathArrow" class="hnuser">DeathArrow</a> <span class="age" title="2021-10-21T10:33:39"><a href="https://news.ycombinator.com/item?id=28942594">3 hours ago</a></span> <span id="unv_28942594"></span> | <a href="https://news.ycombinator.com/hide?id=28942594&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28942594">3 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940705"> + <td class="title" valign="top" align="right"><span class="rank">52.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940705" href="https://news.ycombinator.com/vote?id=28940705&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.gimp.org/news/2021/10/20/gimp-2-99-8-released/" class="titlelink">Development version: GIMP 2.99.8 Released</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=gimp.org"><span class="sitestr">gimp.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940705">19 points</span> by <a href="https://news.ycombinator.com/user?id=pauloxnet" class="hnuser">pauloxnet</a> <span class="age" title="2021-10-21T05:33:20"><a href="https://news.ycombinator.com/item?id=28940705">8 hours ago</a></span> <span id="unv_28940705"></span> | <a href="https://news.ycombinator.com/hide?id=28940705&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940705">2 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28903383"> + <td class="title" valign="top" align="right"><span class="rank">53.</span></td> <td class="votelinks" valign="top"><center><a id="up_28903383" href="https://news.ycombinator.com/vote?id=28903383&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://mikolaj-kaminski.com/jetbrains-rider-docker-compose-unicodedecodeerror-issue-fix/" class="titlelink">I couldn't debug the code because of my name</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=mikolaj-kaminski.com"><span class="sitestr">mikolaj-kaminski.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28903383">247 points</span> by <a href="https://news.ycombinator.com/user?id=mikasjp" class="hnuser">mikasjp</a> <span class="age" title="2021-10-18T08:40:39"><a href="https://news.ycombinator.com/item?id=28903383">23 hours ago</a></span> <span id="unv_28903383"></span> | <a href="https://news.ycombinator.com/hide?id=28903383&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28903383">268 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28937484"> + <td class="title" valign="top" align="right"><span class="rank">54.</span></td> <td class="votelinks" valign="top"><center><a id="up_28937484" href="https://news.ycombinator.com/vote?id=28937484&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://calbryant.uk/blog/10-ways-to-get-the-best-out-of-openscad/" class="titlelink">Getting the best out of OpenSCAD</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=calbryant.uk"><span class="sitestr">calbryant.uk</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28937484">109 points</span> by <a href="https://news.ycombinator.com/user?id=naggie" class="hnuser">naggie</a> <span class="age" title="2021-10-20T22:13:20"><a href="https://news.ycombinator.com/item?id=28937484">16 hours ago</a></span> <span id="unv_28937484"></span> | <a href="https://news.ycombinator.com/hide?id=28937484&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28937484">52 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28921083"> + <td class="title" valign="top" align="right"><span class="rank">55.</span></td> <td class="votelinks" valign="top"><center><a id="up_28921083" href="https://news.ycombinator.com/vote?id=28921083&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://spectrum.ieee.org/recycled-batteries-good-as-newly-mined" class="titlelink">Study: Recycled Lithium Batteries as Good as Newly Mined</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=ieee.org"><span class="sitestr">ieee.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28921083">623 points</span> by <a href="https://news.ycombinator.com/user?id=mpweiher" class="hnuser">mpweiher</a> <span class="age" title="2021-10-19T17:45:07"><a href="https://news.ycombinator.com/item?id=28921083">1 day ago</a></span> <span id="unv_28921083"></span> | <a href="https://news.ycombinator.com/hide?id=28921083&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28921083">179 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28934715"> + <td class="title" valign="top" align="right"><span class="rank">56.</span></td> <td class="votelinks" valign="top"><center><a id="up_28934715" href="https://news.ycombinator.com/vote?id=28934715&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://americasfuture.org/eliminating-gifted-programs-wont-make-education-fair/" class="titlelink">Eliminating gifted programs won’t make education fair</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=americasfuture.org"><span class="sitestr">americasfuture.org</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28934715">180 points</span> by <a href="https://news.ycombinator.com/user?id=paulpauper" class="hnuser">paulpauper</a> <span class="age" title="2021-10-20T19:03:44"><a href="https://news.ycombinator.com/item?id=28934715">19 hours ago</a></span> <span id="unv_28934715"></span> | <a href="https://news.ycombinator.com/hide?id=28934715&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28934715">400 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28939407"> + <td class="title" valign="top" align="right"><span class="rank">57.</span></td> <td class="votelinks" valign="top"><center><a id="up_28939407" href="https://news.ycombinator.com/vote?id=28939407&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://github.com/ToshioCP/Gtk4-tutorial/blob/main/Readme.md" class="titlelink">Gtk4 Tutorial</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=github.com/toshiocp"><span class="sitestr">github.com/toshiocp</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28939407">53 points</span> by <a href="https://news.ycombinator.com/user?id=marcodiego" class="hnuser">marcodiego</a> <span class="age" title="2021-10-21T01:59:18"><a href="https://news.ycombinator.com/item?id=28939407">12 hours ago</a></span> <span id="unv_28939407"></span> | <a href="https://news.ycombinator.com/hide?id=28939407&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28939407">73 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28940334"> + <td class="title" valign="top" align="right"><span class="rank">58.</span></td> <td class="votelinks" valign="top"><center><a id="up_28940334" href="https://news.ycombinator.com/vote?id=28940334&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://obua.com/publications/cosmo-id/3/" class="titlelink" rel="nofollow">Cosmopolitan Identiï¬ers</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=obua.com"><span class="sitestr">obua.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28940334">10 points</span> by <a href="https://news.ycombinator.com/user?id=BeefySwain" class="hnuser">BeefySwain</a> <span class="age" title="2021-10-21T04:39:41"><a href="https://news.ycombinator.com/item?id=28940334">9 hours ago</a></span> <span id="unv_28940334"></span> | <a href="https://news.ycombinator.com/hide?id=28940334&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28940334">2 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28929840"> + <td class="title" valign="top" align="right"><span class="rank">59.</span></td> <td class="votelinks" valign="top"><center><a id="up_28929840" href="https://news.ycombinator.com/vote?id=28929840&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://madned.substack.com/p/a-talk-with-computer-gaming-pioneer" class="titlelink">A talk with Walter Bright about Empire</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=madned.substack.com"><span class="sitestr">madned.substack.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28929840">218 points</span> by <a href="https://news.ycombinator.com/user?id=mad_ned" class="hnuser">mad_ned</a> <span class="age" title="2021-10-20T12:29:16"><a href="https://news.ycombinator.com/item?id=28929840">1 day ago</a></span> <span id="unv_28929840"></span> | <a href="https://news.ycombinator.com/hide?id=28929840&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28929840">86 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="athing" id="28934833"> + <td class="title" valign="top" align="right"><span class="rank">60.</span></td> <td class="votelinks" valign="top"><center><a id="up_28934833" href="https://news.ycombinator.com/vote?id=28934833&how=up&goto=news%3Fp%3D2"><div class="votearrow" title="upvote"></div></a></center></td><td class="title"><a href="https://www.youtube.com/watch?v=NjrYk546uBA" class="titlelink">Bioelektryczność – Polish Robotics (1968) [video]</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=youtube.com"><span class="sitestr">youtube.com</span></a>)</span></td></tr><tr><td colspan="2"></td><td class="subtext"> + <span class="score" id="score_28934833">123 points</span> by <a href="https://news.ycombinator.com/user?id=danielEM" class="hnuser">danielEM</a> <span class="age" title="2021-10-20T19:11:59"><a href="https://news.ycombinator.com/item?id=28934833">19 hours ago</a></span> <span id="unv_28934833"></span> | <a href="https://news.ycombinator.com/hide?id=28934833&goto=news%3Fp%3D2">hide</a> | <a href="https://news.ycombinator.com/item?id=28934833">27 comments</a> </td></tr> + <tr class="spacer" style="height:5px"></tr> + <tr class="morespace" style="height:10px"></tr><tr><td colspan="2"></td><td class="title"><a href="https://news.ycombinator.com/news?p=3" class="morelink" rel="next">More</a></td></tr> + </tbody></table> +</td></tr> +<tr><td><img src="02_files/s.gif" width="0" height="10"><table width="100%" cellspacing="0" cellpadding="1"><tbody><tr><td bgcolor="#ff6600"></td></tr></tbody></table><br><center><span class="yclinks"><a href="https://news.ycombinator.com/newsguidelines.html">Guidelines</a> + | <a href="https://news.ycombinator.com/newsfaq.html">FAQ</a> + | <a href="https://news.ycombinator.com/lists">Lists</a> + | <a href="https://github.com/HackerNews/API">API</a> + | <a href="https://news.ycombinator.com/security.html">Security</a> + | <a href="http://www.ycombinator.com/legal/">Legal</a> + | <a href="http://www.ycombinator.com/apply/">Apply to YC</a> + | <a href="mailto:hn@ycombinator.com">Contact</a></span><br><br><form method="get" action="//hn.algolia.com/">Search: + <input type="text" name="q" size="17" autocorrect="off" spellcheck="false" autocapitalize="none" autocomplete="false"></form> + </center></td></tr> + </tbody></table></center><script type="text/javascript" src="02_files/hn.js"></script> +</body></html>
\ No newline at end of file diff --git a/rushs/tinyprintf/hacker_news/news.sed b/rushs/tinyprintf/hacker_news/news.sed new file mode 100644 index 0000000..91b76d6 --- /dev/null +++ b/rushs/tinyprintf/hacker_news/news.sed @@ -0,0 +1 @@ +s/^.*"\(https\?:\/\/.*\)" class="titlelink"\( rel="nofollow"\)\?>\([^<]*\).*$/**\3**\n\1\n/p diff --git a/rushs/tinyprintf/hacker_news/output.txt b/rushs/tinyprintf/hacker_news/output.txt new file mode 100644 index 0000000..68cc714 --- /dev/null +++ b/rushs/tinyprintf/hacker_news/output.txt @@ -0,0 +1,90 @@ +**Sinclair Broadcast Group identifies data breach** +https://apnews.com/article/technology-business-arts-and-entertainment-be48d7582fdd5604664fff33ed81ca80 + +**A gentle introduction to the FFT (2002)** +https://www.earlevel.com/main/2002/08/31/a-gentle-introduction-to-the-fft/ + +**Jon Ingold on translating archeology into video games** +https://thebrowser.com/notes/jon-ingold/ + +**Ask HN: How to Sell a Website** +https://news.ycombinator.com/item?id=28943611 + +**We analyzed 425k favicons** +https://iconmap.io/blog + +**Machu Picchu was built over major fault zones (2019)** +https://www.science.org/content/article/machu-picchu-was-built-over-major-fault-zones-now-researchers-think-they-know-why + +**Goggles: Democracy dies in darkness, and so does the Web [pdf]** +https://brave.com/wp-content/uploads/2021/03/goggles.pdf + +**Apple M1 Max Geekbench Score** +https://browser.geekbench.com/v5/cpu/10496766 + +**U.S. tightens export controls on items used in surveillance of private citizens** +https://www.commerce.gov/news/press-releases/2021/10/commerce-tightens-export-controls-items-used-surveillance-private + +**WeWork is trying to go public – again** +https://www.wsj.com/articles/wework-set-to-go-public-via-spac-deal-two-years-after-failed-ipo-11634808600 + +**Playstation 3 Architecture** +https://www.copetti.org/writings/consoles/playstation-3/ + +**About that time I had an outburst during the Y Combinator Interview** +https://owlpal.substack.com/p/about-that-time-i-had-an-outburst + +**One Man's Pest** +https://www.guernicamag.com/one-mans-pest/ + +**Brave Search replaces Google as default search engine in the Brave browser** +https://brave.com/search-and-web-discovery/ + +**I reverse engineered mcdonald's internal API** +https://twitter.com//rashiq/status/1319346264992026624 + +**Injury response to DNA damage in live tumor cells promotes antitumor immunity** +https://www.science.org/doi/10.1126/scisignal.abc4764 + +**India Counting Down to 1B Doses** +https://www.cowin.gov.in/ + +**Time to get worried about Tether, the “stablecoin†at center of cryptocurrency** +https://slate.com/technology/2021/10/tether-crypto-danger-ben-mckenzie.html + +**The History of Surveying** +https://www.alifewithoutlimits.com.au/the-history-of-surveying/ + +**The FDA wants you to be able to buy a hearing aid without a prescription** +https://www.npr.org/2021/10/19/1047303559/fda-hearing-aid-prescription-over-the-counter + +**Windows 11 will hobble gaming performance by default on some prebuilt PCs** +https://www.pcgamer.com/windows-11-pcs-can-hobble-gaming-performance/ + +**Development version: GIMP 2.99.8 Released** +https://www.gimp.org/news/2021/10/20/gimp-2-99-8-released/ + +**I couldn't debug the code because of my name** +https://mikolaj-kaminski.com/jetbrains-rider-docker-compose-unicodedecodeerror-issue-fix/ + +**Getting the best out of OpenSCAD** +https://calbryant.uk/blog/10-ways-to-get-the-best-out-of-openscad/ + +**Study: Recycled Lithium Batteries as Good as Newly Mined** +https://spectrum.ieee.org/recycled-batteries-good-as-newly-mined + +**Eliminating gifted programs won’t make education fair** +https://americasfuture.org/eliminating-gifted-programs-wont-make-education-fair/ + +**Gtk4 Tutorial** +https://github.com/ToshioCP/Gtk4-tutorial/blob/main/Readme.md + +**Cosmopolitan Identiï¬ers** +https://obua.com/publications/cosmo-id/3/ + +**A talk with Walter Bright about Empire** +https://madned.substack.com/p/a-talk-with-computer-gaming-pioneer + +**Bioelektryczność – Polish Robotics (1968) [video]** +https://www.youtube.com/watch?v=NjrYk546uBA + diff --git a/rushs/tinyprintf/handling_complex/complex.c b/rushs/tinyprintf/handling_complex/complex.c new file mode 100644 index 0000000..79a10be --- /dev/null +++ b/rushs/tinyprintf/handling_complex/complex.c @@ -0,0 +1,51 @@ +#include "complex.h" + +#include <stdio.h> + +void print_complex(struct complex a) +{ + printf("complex(%.2f ", a.real); + + if (a.img < 0) + { + printf("- %.2fi", -a.img); + } + else + { + printf("+ %.2fi", a.img); + } + printf(")\n"); +} + +struct complex neg_complex(struct complex a) +{ + struct complex z = { -a.real, -a.img }; + return z; +} + +struct complex add_complex(struct complex a, struct complex b) +{ + struct complex z = { a.real + b.real, a.img + b.img }; + return z; +} + +struct complex sub_complex(struct complex a, struct complex b) +{ + return add_complex(a, neg_complex(b)); +} + +struct complex mul_complex(struct complex a, struct complex b) +{ + struct complex z = { a.real * b.real - a.img * b.img, + a.real * b.img + a.img * b.real }; + return z; +} + +struct complex div_complex(struct complex a, struct complex b) +{ + struct complex z = { + (a.real * b.real + a.img * b.img) / (b.real * b.real + b.img * b.img), + (a.img * b.real - a.real * b.img) / (b.real * b.real + b.img * b.img) + }; + return z; +} diff --git a/rushs/tinyprintf/handling_complex/complex.h b/rushs/tinyprintf/handling_complex/complex.h new file mode 100644 index 0000000..c562810 --- /dev/null +++ b/rushs/tinyprintf/handling_complex/complex.h @@ -0,0 +1,20 @@ +#ifndef COMPLEX_H +#define COMPLEX_H + +struct complex +{ + float real; + float img; +}; + +// Print +void print_complex(struct complex a); + +// Operations +struct complex neg_complex(struct complex a); +struct complex add_complex(struct complex a, struct complex b); +struct complex sub_complex(struct complex a, struct complex b); +struct complex mul_complex(struct complex a, struct complex b); +struct complex div_complex(struct complex a, struct complex b); + +#endif /* !COMPLEX_H */ diff --git a/rushs/tinyprintf/hanoi/hanoi.c b/rushs/tinyprintf/hanoi/hanoi.c new file mode 100644 index 0000000..6ac2b71 --- /dev/null +++ b/rushs/tinyprintf/hanoi/hanoi.c @@ -0,0 +1,31 @@ +#include <stdio.h> + +void move(unsigned src, unsigned spare, unsigned dst, unsigned n) +{ + if (n == 0) + { + return; + } + + move(src, dst, spare, n - 1); + + printf("%u->%u\n", src, dst); + + move(spare, src, dst, n - 1); +} + +void hanoi(unsigned n) +{ + if (n == 0) + { + return; + } + + move(1, 2, 3, n); +} + +int main(void) +{ + hanoi(3); + return 0; +} diff --git a/rushs/tinyprintf/hash_map/hash.c b/rushs/tinyprintf/hash_map/hash.c new file mode 100644 index 0000000..434616f --- /dev/null +++ b/rushs/tinyprintf/hash_map/hash.c @@ -0,0 +1,13 @@ +#include <stddef.h> + +size_t hash(const char *key) +{ + size_t i = 0; + size_t hash = 0; + + for (i = 0; key[i] != '\0'; ++i) + hash += key[i]; + hash += i; + + return hash; +} diff --git a/rushs/tinyprintf/hash_map/hash_map.c b/rushs/tinyprintf/hash_map/hash_map.c new file mode 100644 index 0000000..4690e8b --- /dev/null +++ b/rushs/tinyprintf/hash_map/hash_map.c @@ -0,0 +1,177 @@ +#include "hash_map.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct hash_map *hash_map_init(size_t size) +{ + struct hash_map *new; + if ((new = malloc(sizeof(struct hash_map))) == NULL) + { + return NULL; + } + if ((new->data = malloc(size * sizeof(struct pair_list *))) == NULL) + { + return NULL; + } + new->size = size; + + for (size_t i = 0; i < size; i++) + { + new->data[i] = NULL; + } + + return new; +} + +bool hash_map_insert(struct hash_map *hash_map, const char *key, char *value, + bool *updated) +{ + if (hash_map == NULL || updated == NULL || hash_map->size == 0) + { + return false; + } + *updated = false; + + size_t h = hash(key); + if (h >= hash_map->size) + { + h %= hash_map->size; + } + + struct pair_list *new = malloc(sizeof(struct pair_list)); + if (new == NULL) + { + return false; + } + + for (struct pair_list *p = hash_map->data[h]; p; p = p->next) + { + if (strcmp(p->key, key) == 0) + { + p->value = value; + *updated = true; + free(new); + return true; + } + } + + new->next = hash_map->data[h]; + new->key = key; + new->value = value; + hash_map->data[h] = new; + return true; +} + +void hash_map_free(struct hash_map *hash_map) +{ + if (hash_map == NULL) + { + return; + } + + if (hash_map->data == NULL) + { + free(hash_map); + return; + } + + for (size_t i = 0; i < hash_map->size; i++) + { + while (hash_map->data[i]) + { + struct pair_list *tmp = hash_map->data[i]->next; + free(hash_map->data[i]); + hash_map->data[i] = tmp; + } + } + + free(hash_map->data); + free(hash_map); +} + +void hash_map_dump(struct hash_map *hash_map) +{ + if (hash_map == NULL || hash_map->data == NULL) + { + return; + } + + for (size_t i = 0; i < hash_map->size; i++) + { + if (hash_map->data[i] != NULL) + { + printf("%s: %s", hash_map->data[i]->key, hash_map->data[i]->value); + for (struct pair_list *p = hash_map->data[i]->next; p; p = p->next) + { + printf(", %s: %s", p->key, p->value); + } + printf("\n"); + } + } +} + +const char *hash_map_get(const struct hash_map *hash_map, const char *key) +{ + if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) + { + return NULL; + } + + size_t h = hash(key); + if (h >= hash_map->size) + { + h %= hash_map->size; + } + struct pair_list *p; + for (p = hash_map->data[h]; p && strcmp(p->key, key) != 0; p = p->next) + { + continue; + } + + if (p) + { + return p->value; + } + return NULL; +} + +bool hash_map_remove(struct hash_map *hash_map, const char *key) +{ + if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) + { + return false; + } + + size_t h = hash(key); + if (h >= hash_map->size) + { + h %= hash_map->size; + } + if (hash_map->data[h] == NULL) + { + return false; + } + + if (strcmp(hash_map->data[h]->key, key) == 0) + { + struct pair_list *tmp = hash_map->data[h]->next; + free(hash_map->data[h]); + hash_map->data[h] = tmp; + return true; + } + + struct pair_list *p; + for (p = hash_map->data[h]; p->next; p = p->next) + { + if (strcmp(p->next->key, key) == 0) + { + struct pair_list *tmp = p->next->next; + free(p->next); + p->next = tmp; + return true; + } + } + return false; +} diff --git a/rushs/tinyprintf/hash_map/hash_map.h b/rushs/tinyprintf/hash_map/hash_map.h new file mode 100644 index 0000000..c731eab --- /dev/null +++ b/rushs/tinyprintf/hash_map/hash_map.h @@ -0,0 +1,29 @@ +#ifndef HASH_MAP_H +#define HASH_MAP_H + +#include <stdbool.h> +#include <stddef.h> + +struct pair_list +{ + const char *key; + char *value; + struct pair_list *next; +}; + +struct hash_map +{ + struct pair_list **data; + size_t size; +}; + +size_t hash(const char *str); +struct hash_map *hash_map_init(size_t size); +bool hash_map_insert(struct hash_map *hash_map, const char *key, char *value, + bool *updated); +void hash_map_free(struct hash_map *hash_map); +void hash_map_dump(struct hash_map *hash_map); +const char *hash_map_get(const struct hash_map *hash_map, const char *key); +bool hash_map_remove(struct hash_map *hash_map, const char *key); + +#endif /* ! HASH_MAP_H */ diff --git a/rushs/tinyprintf/heap/Makefile b/rushs/tinyprintf/heap/Makefile new file mode 100644 index 0000000..2ed972b --- /dev/null +++ b/rushs/tinyprintf/heap/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wvla -Wextra -std=c99 -pedantic +SRC = add.c del.c print.c pop.c create.c +OBJ = $(SRC:.c=.o) + +.PHONY: library clean + +library: $(OBJ) + ar csr libheap.a $(OBJ) + +$(OBJ): $(SRC) + +clean: + $(RM) libheap.a $(OBJ) diff --git a/rushs/tinyprintf/heap/add.c b/rushs/tinyprintf/heap/add.c new file mode 100644 index 0000000..78a4db8 --- /dev/null +++ b/rushs/tinyprintf/heap/add.c @@ -0,0 +1,39 @@ +#include <stdlib.h> + +#include "heap.h" + +void heapify(int arr[], int n, int i) +{ + if (i == 0) + return; + int parent = (i - 1) / 2; + if (parent >= 0) + { + if (arr[i] > arr[parent]) + { + int tmp = arr[i]; + arr[i] = arr[parent]; + arr[parent] = tmp; + heapify(arr, n, parent); + } + } +} + +void add(struct heap *heap, int val) +{ + if (heap->size == heap->capacity) + { + heap->array = realloc(heap->array, heap->capacity * 2 * sizeof(int)); + if (heap->array == NULL) + { + free(heap); + return; + } + heap->capacity *= 2; + } + + heap->array[heap->size] = val; + heap->size++; + + heapify(heap->array, heap->size, heap->size - 1); +} diff --git a/rushs/tinyprintf/heap/create.c b/rushs/tinyprintf/heap/create.c new file mode 100644 index 0000000..f0675ad --- /dev/null +++ b/rushs/tinyprintf/heap/create.c @@ -0,0 +1,19 @@ +#include <stdlib.h> + +#include "heap.h" + +struct heap *create_heap(void) +{ + struct heap *res = malloc(sizeof(struct heap)); + if (res == NULL) + return NULL; + res->size = 0; + res->capacity = 8; + res->array = malloc(8 * sizeof(int)); + if (res->array == NULL) + { + free(res); + return NULL; + } + return res; +} diff --git a/rushs/tinyprintf/heap/del.c b/rushs/tinyprintf/heap/del.c new file mode 100644 index 0000000..4d2ae35 --- /dev/null +++ b/rushs/tinyprintf/heap/del.c @@ -0,0 +1,9 @@ +#include <stdlib.h> + +#include "heap.h" + +void delete_heap(struct heap *heap) +{ + free(heap->array); + free(heap); +} diff --git a/rushs/tinyprintf/heap/heap.h b/rushs/tinyprintf/heap/heap.h new file mode 100644 index 0000000..085f436 --- /dev/null +++ b/rushs/tinyprintf/heap/heap.h @@ -0,0 +1,20 @@ +#ifndef HEAP_H +#define HEAP_H + +// size_t +#include <stddef.h> + +struct heap +{ + size_t size; + size_t capacity; + int *array; +}; + +struct heap *create_heap(void); +void add(struct heap *heap, int val); +int pop(struct heap *heap); +void delete_heap(struct heap *heap); +void print_heap(const struct heap *heap); + +#endif /* !HEAP_H */ diff --git a/rushs/tinyprintf/heap/pop.c b/rushs/tinyprintf/heap/pop.c new file mode 100644 index 0000000..55e063f --- /dev/null +++ b/rushs/tinyprintf/heap/pop.c @@ -0,0 +1,49 @@ +#include <assert.h> +#include <stdlib.h> + +#include "heap.h" + +void heapify2(struct heap *h, size_t i) +{ + size_t max = i; + if (2 * i + 1 < h->size && h->array[2 * i + 1] > h->array[max]) + max = 2 * i + 1; + if (2 * i + 2 < h->size && h->array[2 * i + 2] > h->array[max]) + max = 2 * i + 2; + if (max != i) + { + int tmp = h->array[i]; + h->array[i] = h->array[max]; + h->array[max] = tmp; + heapify2(h, max); + } +} + +int pop(struct heap *heap) +{ + assert(heap->size != 0); + if (heap->size == 1) + { + heap->size--; + return heap->array[0]; + } + else + { + int res = heap->array[0]; + heap->array[0] = heap->array[heap->size - 1]; + heap->size--; + heapify2(heap, 0); + if (heap->size < heap->capacity / 2 && heap->capacity > 8) + { + heap->array = + realloc(heap->array, (heap->capacity / 2) * sizeof(int)); + if (heap->array == NULL) + { + free(heap); + return -1; + } + heap->capacity /= 2; + } + return res; + } +} diff --git a/rushs/tinyprintf/heap/print.c b/rushs/tinyprintf/heap/print.c new file mode 100644 index 0000000..f5bbe95 --- /dev/null +++ b/rushs/tinyprintf/heap/print.c @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "heap.h" + +void print_rec(const struct heap *h, size_t i, int root) +{ + if (i >= h->size) + return; + if (!root) + printf(" "); + else + root = 0; + printf("%d", h->array[i]); + if (i == h->size - 1) + { + return; + } + print_rec(h, i * 2 + 1, root); + print_rec(h, i * 2 + 2, root); +} + +void print_heap(const struct heap *heap) +{ + print_rec(heap, 0, 1); + printf("\n"); +} diff --git a/rushs/tinyprintf/hello_friends/hello.c b/rushs/tinyprintf/hello_friends/hello.c new file mode 100644 index 0000000..63df2f1 --- /dev/null +++ b/rushs/tinyprintf/hello_friends/hello.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +int main(int argc, char **argv) +{ + if (argc == 1) + printf("Hello World!\n"); + else + for (int i = 1; i < argc; i++) + { + printf("Hello %s!\n", argv[i]); + } + return 0; +} diff --git a/rushs/tinyprintf/hello_world/hello.c b/rushs/tinyprintf/hello_world/hello.c new file mode 100644 index 0000000..0681c18 --- /dev/null +++ b/rushs/tinyprintf/hello_world/hello.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int main(void) +{ + puts("Hello World!"); + return 0; +} diff --git a/rushs/tinyprintf/hello_world_shebang/hello.sh b/rushs/tinyprintf/hello_world_shebang/hello.sh new file mode 100755 index 0000000..8dc4f64 --- /dev/null +++ b/rushs/tinyprintf/hello_world_shebang/hello.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Hello World!" diff --git a/rushs/tinyprintf/hill_array/hill_array.c b/rushs/tinyprintf/hill_array/hill_array.c new file mode 100644 index 0000000..14d3a85 --- /dev/null +++ b/rushs/tinyprintf/hill_array/hill_array.c @@ -0,0 +1,43 @@ +#include "hill_array.h" + +int top_of_the_hill(int tab[], size_t len) +{ + if (len == 0) + { + return -1; + } + + int top = 0; + size_t i = 0; + + while (i + 1 < len && tab[i] <= tab[i + 1]) + { + if (tab[i] < 0 || tab[i + 1] < 0) + { + return -1; + } + if (tab[i] != tab[i + 1]) + { + top = i + 1; + } + i++; + } + + while (i + 1 < len && tab[i] >= tab[i + 1]) + { + if (tab[i] < 0 || tab[i + 1] < 0) + { + return -1; + } + i++; + } + + if (i + 1 == len) + { + return top; + } + else + { + return -1; + } +} diff --git a/rushs/tinyprintf/hill_array/hill_array.h b/rushs/tinyprintf/hill_array/hill_array.h new file mode 100644 index 0000000..3152c19 --- /dev/null +++ b/rushs/tinyprintf/hill_array/hill_array.h @@ -0,0 +1,8 @@ +#ifndef HILL_ARRAY_H +#define HILL_ARRAY_H + +#include <stddef.h> + +int top_of_the_hill(int tab[], size_t len); + +#endif /* !HILL_ARRAY_H */ diff --git a/rushs/tinyprintf/insertion_sort/insertion_sort.c b/rushs/tinyprintf/insertion_sort/insertion_sort.c new file mode 100644 index 0000000..2edd195 --- /dev/null +++ b/rushs/tinyprintf/insertion_sort/insertion_sort.c @@ -0,0 +1,20 @@ +#include "insertion_sort.h" + +#include <stddef.h> + +void insertion_sort(void **array, f_cmp comp) +{ + if (array == NULL || *array == NULL) + { + return; + } + for (int i = 1; array[i]; i++) + { + for (int j = i; j > 0 && comp(array[j - 1], array[j]) > 0; j--) + { + void *tmp = array[j]; + array[j] = array[j - 1]; + array[j - 1] = tmp; + } + } +} diff --git a/rushs/tinyprintf/insertion_sort/insertion_sort.h b/rushs/tinyprintf/insertion_sort/insertion_sort.h new file mode 100644 index 0000000..a7ba674 --- /dev/null +++ b/rushs/tinyprintf/insertion_sort/insertion_sort.h @@ -0,0 +1,8 @@ +#ifndef INSERTION_SORT_H +#define INSERTION_SORT_H + +typedef int (*f_cmp)(const void *, const void *); + +void insertion_sort(void **array, f_cmp comp); + +#endif /* ! INSERTION_SORT_H */ diff --git a/rushs/tinyprintf/inside/inside.sh b/rushs/tinyprintf/inside/inside.sh new file mode 100755 index 0000000..c6872fa --- /dev/null +++ b/rushs/tinyprintf/inside/inside.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +if [ $# -ne 1 ]; then + echo Sorry, expected 1 argument but $# were passed + exit 1 +fi + +if [ -f $1 ]; then + cat $1 + exit 0 +else + echo "$1: + is not a valid file" + exit 2 +fi diff --git a/rushs/tinyprintf/inside_noif/inside_noif.sh b/rushs/tinyprintf/inside_noif/inside_noif.sh new file mode 100755 index 0000000..d4ed8c9 --- /dev/null +++ b/rushs/tinyprintf/inside_noif/inside_noif.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +[ $# -ne 1 ] && echo Sorry, expected 1 argument but $# were passed && exit 1 + +[ -f $1 ] && cat $1 && exit 0 || echo "$1: + is not a valid file" && exit 2 diff --git a/rushs/tinyprintf/int_palindrome/int_palindrome.c b/rushs/tinyprintf/int_palindrome/int_palindrome.c new file mode 100644 index 0000000..6d6847f --- /dev/null +++ b/rushs/tinyprintf/int_palindrome/int_palindrome.c @@ -0,0 +1,18 @@ +int int_palindrome(int n) +{ + if (n < 0) + { + return 0; + } + + int reversed = 0; + int m = n; + + while (m > 0) + { + reversed = reversed * 10 + m % 10; + m /= 10; + } + + return n == reversed; +} diff --git a/rushs/tinyprintf/int_sqrt/int_sqrt.c b/rushs/tinyprintf/int_sqrt/int_sqrt.c new file mode 100644 index 0000000..4b2e5db --- /dev/null +++ b/rushs/tinyprintf/int_sqrt/int_sqrt.c @@ -0,0 +1,20 @@ +int int_sqrt(int n) +{ + if (n < 0) + { + return -1; + } + + if (n == 0 || n == 1) + { + return n; + } + + int i; + for (i = 1; i * i < n; i++) + { + continue; + } + + return i - (i * i != n); +} diff --git a/rushs/tinyprintf/io_count_words/count_words.c b/rushs/tinyprintf/io_count_words/count_words.c new file mode 100644 index 0000000..8b8c9a5 --- /dev/null +++ b/rushs/tinyprintf/io_count_words/count_words.c @@ -0,0 +1,33 @@ +#include <stdio.h> + +int count_words(const char *file_in) +{ + if (file_in == NULL) + { + return -1; + } + + FILE *f = fopen(file_in, "r"); + if (f == NULL) + { + return -1; + } + + int word = 0; + int count = 0; + int c; + while ((c = fgetc(f)) != EOF) + { + if ((c == ' ' || c == '\n' || c == '\t') && word == 1) + { + word = 0; + } + if (c != ' ' && c != '\n' && c != '\t' && word == 0) + { + word = 1; + count++; + } + } + + return count; +} diff --git a/rushs/tinyprintf/io_merge_files/merge_files.c b/rushs/tinyprintf/io_merge_files/merge_files.c new file mode 100644 index 0000000..26ac9cf --- /dev/null +++ b/rushs/tinyprintf/io_merge_files/merge_files.c @@ -0,0 +1,31 @@ +#define _POSIX_C_SOURCE 200809L + +#include <stdio.h> + +int merge_files(const char *file_1, const char *file_2) +{ + FILE *a = fopen(file_1, "a"); + if (a == NULL) + { + return -1; + } + FILE *r = fopen(file_2, "r"); + if (r == NULL) + { + return -1; + } + + int c; + while ((c = fgetc(r)) != EOF) + { + if (fputc(c, a) == EOF) + { + return -1; + } + } + + fclose(a); + fclose(r); + + return 0; +} diff --git a/rushs/tinyprintf/io_replace_line/replace_line.c b/rushs/tinyprintf/io_replace_line/replace_line.c new file mode 100644 index 0000000..7fd0e2a --- /dev/null +++ b/rushs/tinyprintf/io_replace_line/replace_line.c @@ -0,0 +1,50 @@ +#define _POSIX_C_SOURCE 200809L + +#include <stdio.h> +#include <stdlib.h> + +int replace_line(const char *file_in, const char *file_out, const char *content, + int n) +{ + FILE *a = fopen(file_out, "w"); + if (a == NULL) + { + return -1; + } + FILE *r = fopen(file_in, "r"); + if (r == NULL) + { + return -1; + } + + char *buf = NULL; + ssize_t e; + int l = 0; + size_t count = 0; + while ((e = getline(&buf, &count, r)) != 0 && e != -1) + { + if (l == n) + { + if (fputs(content, a) == EOF) + { + free(buf); + return -1; + } + } + else + { + if (fputs(buf, a) == EOF) + { + free(buf); + return -1; + } + } + l++; + } + + fclose(a); + fclose(r); + free(buf); + + return 0; +} diff --git a/rushs/tinyprintf/levenshtein/levenshtein.c b/rushs/tinyprintf/levenshtein/levenshtein.c new file mode 100644 index 0000000..4da9397 --- /dev/null +++ b/rushs/tinyprintf/levenshtein/levenshtein.c @@ -0,0 +1,72 @@ +#include "levenshtein.h" + +#include <stdio.h> + +size_t max(size_t a, size_t b) +{ + if (a >= b) + { + return a; + } + return b; +} + +size_t min(size_t a, size_t b) +{ + if (a <= b) + { + return a; + } + return b; +} + +size_t min_3(size_t a, size_t b, size_t c) +{ + if (a <= b) + { + if (a <= c) + { + return a; + } + return c; + } + else + { + if (b <= c) + { + return b; + } + return c; + } +} + +size_t my_strlen(const char *s) +{ + size_t i; + for (i = 0; s[i]; i++) + { + continue; + } + return i; +} + +size_t levenshtein(const char *s1, const char *s2) +{ + size_t l1 = my_strlen(s1); + size_t l2 = my_strlen(s2); + if (min(l1, l2) == 0) + { + return max(l1, l2); + } + + if (s1[0] == s2[0]) + { + return levenshtein(s1 + 1, s2 + 1); + } + + size_t lev1 = levenshtein(s1 + 1, s2); + size_t lev2 = levenshtein(s1, s2 + 1); + size_t lev3 = levenshtein(s1 + 1, s2 + 1); + + return 1 + min_3(lev1, lev2, lev3); +} diff --git a/rushs/tinyprintf/levenshtein/levenshtein.h b/rushs/tinyprintf/levenshtein/levenshtein.h new file mode 100644 index 0000000..70a5a7b --- /dev/null +++ b/rushs/tinyprintf/levenshtein/levenshtein.h @@ -0,0 +1,8 @@ +#ifndef LEVENSHTEIN_H +#define LEVENSHTEIN_H + +#include <stddef.h> + +size_t levenshtein(const char *s1, const char *s2); + +#endif /* !LEVENSHTEIN_H */ diff --git a/rushs/tinyprintf/main.c b/rushs/tinyprintf/main.c new file mode 100644 index 0000000..4062426 --- /dev/null +++ b/rushs/tinyprintf/main.c @@ -0,0 +1,15 @@ +#include <stdio.h> +#include <stdlib.h> + +//#include "traffic_lights/traffic_lights.h" +unsigned char rol(unsigned char value, unsigned char roll); + +int main(void) +{ + unsigned char l1 = 0b01010101; + unsigned char l2 = 3; + + printf("l1: %b", rol(l1, l2)); + + return 0; +} diff --git a/rushs/tinyprintf/my_abs/my_abs.c b/rushs/tinyprintf/my_abs/my_abs.c new file mode 100644 index 0000000..fc89d2f --- /dev/null +++ b/rushs/tinyprintf/my_abs/my_abs.c @@ -0,0 +1,11 @@ +int my_abs(int n) +{ + if (n < 0) + { + return -n; + } + else + { + return n; + } +} diff --git a/rushs/tinyprintf/my_atoi/my_atoi.c b/rushs/tinyprintf/my_atoi/my_atoi.c new file mode 100644 index 0000000..ca185a5 --- /dev/null +++ b/rushs/tinyprintf/my_atoi/my_atoi.c @@ -0,0 +1,61 @@ +#include "my_atoi.h" + +int my_atoi(const char *str) +{ + int res = 0; + + // str error check + if (str == NULL || *str == '0') + { + return 0; + } + + // trim whitespaces + for (; *str && *str == ' '; str++) + { + continue; + } + + // move to end of str + size_t l; + for (l = 0; str[l]; l++) + { + continue; + } + l--; + + // prepare for calculations + int factor = 1; + + // actual conversion of up to the second element of str (potential sign) + for (; l > 0; l--) + { + char val = str[l]; + if (val < '0' || val > '9') + { + return 0; + } + val -= '0'; + res += val * factor; + + factor *= 10; + } + + // l should be 0 by now + if (str[l] == '-') + { + return -res; + } + else if (str[l] != '+') + { + int val = str[l]; + if (val < '0' || val > '9') + { + return 0; + } + val -= '0'; + return res + val * factor; + } + + return res; +} diff --git a/rushs/tinyprintf/my_atoi/my_atoi.h b/rushs/tinyprintf/my_atoi/my_atoi.h new file mode 100644 index 0000000..b520d09 --- /dev/null +++ b/rushs/tinyprintf/my_atoi/my_atoi.h @@ -0,0 +1,8 @@ +#ifndef MY_ATOI_H +#define MY_ATOI_H + +#include <stddef.h> + +int my_atoi(const char *str); + +#endif /* ! MY_ATOI_H */ diff --git a/rushs/tinyprintf/my_atoi_base/my_atoi_base.c b/rushs/tinyprintf/my_atoi_base/my_atoi_base.c new file mode 100644 index 0000000..46b4560 --- /dev/null +++ b/rushs/tinyprintf/my_atoi_base/my_atoi_base.c @@ -0,0 +1,86 @@ +#include "my_atoi_base.h" + +int val_in_base(char c, const char *base) +{ + size_t i; + for (i = 0; base[i] && base[i] != c; i++) + { + continue; + } + + if (base[i]) + { + return i; + } + + return -1; +} + +int base_size(const char *base) +{ + int res; + for (res = 0; base[res]; res++) + { + continue; + } + return res; +} + +int my_atoi_base(const char *str, const char *base) +{ + int res = 0; + + // str error check + if (str == NULL || *str == '0') + { + return 0; + } + + // trim whitespaces + for (; *str && *str == ' '; str++) + { + continue; + } + + // move to end of str + size_t l; + for (l = 0; str[l]; l++) + { + continue; + } + l--; + + // prepare for calculations + int b = base_size(base); + int factor = 1; + + // actual conversion of up to the second element of str (potential sign) + for (; l > 0; l--) + { + int val = val_in_base(str[l], base); + if (val == -1) + { + return 0; + } + res += val * factor; + + factor *= b; + } + + // l should be 0 by now + if (str[l] == '-') + { + return -res; + } + else if (str[l] != '+') + { + int val = val_in_base(str[l], base); + if (val == -1) + { + return 0; + } + return res + val * factor; + } + + return res; +} diff --git a/rushs/tinyprintf/my_atoi_base/my_atoi_base.h b/rushs/tinyprintf/my_atoi_base/my_atoi_base.h new file mode 100644 index 0000000..296ae23 --- /dev/null +++ b/rushs/tinyprintf/my_atoi_base/my_atoi_base.h @@ -0,0 +1,8 @@ +#ifndef MY_ATOI_BASE_H +#define MY_ATOI_BASE_H + +#include <stddef.h> + +int my_atoi_base(const char *str, const char *base); + +#endif /* ! MY_ATOI_BASE_H */ diff --git a/rushs/tinyprintf/my_bc/my_bc.sh b/rushs/tinyprintf/my_bc/my_bc.sh new file mode 100755 index 0000000..f675838 --- /dev/null +++ b/rushs/tinyprintf/my_bc/my_bc.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +[ -n "$1" ] && echo "$(($1))" && exit 0 + +while IFS='' read -r line; do + [ -z "$line" ] && exit 0 || echo "$(($line))" +done diff --git a/rushs/tinyprintf/my_c_tail/main.c b/rushs/tinyprintf/my_c_tail/main.c new file mode 100644 index 0000000..ba33337 --- /dev/null +++ b/rushs/tinyprintf/my_c_tail/main.c @@ -0,0 +1,10 @@ +#include <stdlib.h> + +#include "my_c_tail.h" + +int main(int argc, char *argv[]) +{ + if (argc > 1) + stdintail(atoi(argv[1])); + return 0; +} diff --git a/rushs/tinyprintf/my_c_tail/my_c_tail.c b/rushs/tinyprintf/my_c_tail/my_c_tail.c new file mode 100644 index 0000000..790240c --- /dev/null +++ b/rushs/tinyprintf/my_c_tail/my_c_tail.c @@ -0,0 +1,46 @@ +#include "my_c_tail.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+void stdintail(unsigned int n)
+{
+ char **lines = calloc(2000, sizeof(char *));
+ lines[0] = malloc(350 * sizeof(char));
+ size_t m = 0;
+ char c;
+ size_t i = 0;
+ while (read(STDIN_FILENO, &c, 1))
+ {
+ if (c == '\n')
+ {
+ lines[m][i] = '\0';
+ lines[++m] = malloc(350 * sizeof(char));
+ i = 0;
+ }
+ else
+ {
+ lines[m][i++] = c;
+ }
+ }
+
+ size_t j;
+ if (m > n)
+ {
+ for (size_t i = 0; i < m - n; i++)
+ free(lines[i]);
+ j = m - n;
+ }
+ else
+ j = 0;
+
+ for (; j < m; j++)
+ {
+ for (size_t i = 0; lines[j][i]; i++)
+ write(STDOUT_FILENO, &(lines[j][i]), 1);
+ write(STDOUT_FILENO, "\n", 1);
+ free(lines[j]);
+ }
+ free(lines[m]);
+ free(lines);
+}
diff --git a/rushs/tinyprintf/my_c_tail/my_c_tail.h b/rushs/tinyprintf/my_c_tail/my_c_tail.h new file mode 100644 index 0000000..172c844 --- /dev/null +++ b/rushs/tinyprintf/my_c_tail/my_c_tail.h @@ -0,0 +1,6 @@ +#ifndef MY_C_TAIL_H +#define MY_C_TAIL_H + +void stdintail(unsigned int n); + +#endif // MY_C_TAIL_H diff --git a/rushs/tinyprintf/my_calloc/my_calloc.c b/rushs/tinyprintf/my_calloc/my_calloc.c new file mode 100644 index 0000000..5a2f7f2 --- /dev/null +++ b/rushs/tinyprintf/my_calloc/my_calloc.c @@ -0,0 +1,11 @@ +#include <stdlib.h> + +void *my_calloc(size_t n, size_t size) +{ + char *res = malloc(n * size); + for (size_t i = 0; i < n * size; i++) + { + res[i] = 0; + } + return res; +} diff --git a/rushs/tinyprintf/my_calloc/my_calloc.h b/rushs/tinyprintf/my_calloc/my_calloc.h new file mode 100644 index 0000000..44bf9a2 --- /dev/null +++ b/rushs/tinyprintf/my_calloc/my_calloc.h @@ -0,0 +1,8 @@ +#ifndef MY_CALLOC_H +#define MY_CALLOC_H + +#include <stdlib.h> + +void *my_calloc(size_t n, size_t size); + +#endif /* ! MY_CALLOC_H */ diff --git a/rushs/tinyprintf/my_file/my_file.sh b/rushs/tinyprintf/my_file/my_file.sh new file mode 100755 index 0000000..93c0c20 --- /dev/null +++ b/rushs/tinyprintf/my_file/my_file.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +for arg; do + if [ -f "$arg" ]; then + echo $arg: file + elif [ -d "$arg" ]; then + echo $arg: directory + else + echo $arg: unknown + fi +done diff --git a/rushs/tinyprintf/my_first_variable/create.sh b/rushs/tinyprintf/my_first_variable/create.sh new file mode 100755 index 0000000..d9264db --- /dev/null +++ b/rushs/tinyprintf/my_first_variable/create.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +my_local_frais="Javotte" + +echo My frais is $my_local_frais diff --git a/rushs/tinyprintf/my_first_variable/edit.sh b/rushs/tinyprintf/my_first_variable/edit.sh new file mode 100755 index 0000000..e47e0c3 --- /dev/null +++ b/rushs/tinyprintf/my_first_variable/edit.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +my_local_frais="Javotte" + +echo My frais is $my_local_frais + +my_local_frais="Pulpa" + +echo My frais is now $my_local_frais diff --git a/rushs/tinyprintf/my_first_variable/use.sh b/rushs/tinyprintf/my_first_variable/use.sh new file mode 100755 index 0000000..f9d462e --- /dev/null +++ b/rushs/tinyprintf/my_first_variable/use.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "My frais is $MY_ENV_FRAIS" diff --git a/rushs/tinyprintf/my_itoa/my_itoa.c b/rushs/tinyprintf/my_itoa/my_itoa.c new file mode 100644 index 0000000..cbb6f73 --- /dev/null +++ b/rushs/tinyprintf/my_itoa/my_itoa.c @@ -0,0 +1,38 @@ +#include "my_itoa.h" + +char *my_itoa(int value, char *s) +{ + if (value == 0) + { + s[0] = '0'; + s[1] = '\0'; + return s; + } + char *head = s; + if (value < 0) + { + s[0] = '-'; + s++; + value = -value; + } + + // count numbers + int t = value; + int n = 0; + while (t > 0) + { + t /= 10; + n++; + } + + // n = number count + s[n] = '\0'; + n--; + for (; n >= 0; n--) + { + s[n] = value % 10 + '0'; + value /= 10; + } + + return head; +} diff --git a/rushs/tinyprintf/my_itoa/my_itoa.h b/rushs/tinyprintf/my_itoa/my_itoa.h new file mode 100644 index 0000000..8e84c72 --- /dev/null +++ b/rushs/tinyprintf/my_itoa/my_itoa.h @@ -0,0 +1,6 @@ +#ifndef MY_ITOA_H +#define MY_ITOA_H + +char *my_itoa(int value, char *s); + +#endif /* ! MY_ITOA_H */ diff --git a/rushs/tinyprintf/my_itoa_base/my_itoa_base.c b/rushs/tinyprintf/my_itoa_base/my_itoa_base.c new file mode 100644 index 0000000..29b3042 --- /dev/null +++ b/rushs/tinyprintf/my_itoa_base/my_itoa_base.c @@ -0,0 +1,49 @@ +#include "my_itoa_base.h" + +int base_count(const char *base) +{ + int i; + for (i = 0; base[i]; i++) + { + continue; + } + return i; +} + +char *my_itoa_base(int n, char *s, const char *base) +{ + if (n == 0) + { + s[0] = base[0]; + s[1] = '\0'; + return s; + } + char *head = s; + if (n < 0) + { + s[0] = '-'; + s++; + n = -n; + } + + // count numbers + int t = n; + int m = 0; + int b = base_count(base); + while (t > 0) + { + t /= b; + m++; + } + + // n = number count + s[m] = '\0'; + m--; + for (; m >= 0; m--) + { + s[m] = base[n % b]; + n /= b; + } + + return head; +} diff --git a/rushs/tinyprintf/my_itoa_base/my_itoa_base.h b/rushs/tinyprintf/my_itoa_base/my_itoa_base.h new file mode 100644 index 0000000..0be6314 --- /dev/null +++ b/rushs/tinyprintf/my_itoa_base/my_itoa_base.h @@ -0,0 +1,6 @@ +#ifndef MY_ITOA_BASE_H +#define MY_ITOA_BASE_H + +char *my_itoa_base(int n, char *s, const char *base); + +#endif /* ! MY_ITOA_BASE_H */ diff --git a/rushs/tinyprintf/my_memcmp/my_memcmp.c b/rushs/tinyprintf/my_memcmp/my_memcmp.c new file mode 100644 index 0000000..d498360 --- /dev/null +++ b/rushs/tinyprintf/my_memcmp/my_memcmp.c @@ -0,0 +1,18 @@ +#include "my_memcmp.h" + +int my_memcmp(const void *s1, const void *s2, size_t num) +{ + if (num == 0) + { + return 0; + } + const unsigned char *a = s1; + const unsigned char *b = s2; + + for (; num - 1 && *a == *b; a++, b++, num--) + { + continue; + } + + return *a - *b; +} diff --git a/rushs/tinyprintf/my_memcmp/my_memcmp.h b/rushs/tinyprintf/my_memcmp/my_memcmp.h new file mode 100644 index 0000000..d17cbe6 --- /dev/null +++ b/rushs/tinyprintf/my_memcmp/my_memcmp.h @@ -0,0 +1,8 @@ +#ifndef MY_MEMCMP_H +#define MY_MEMCMP_H + +#include <stddef.h> + +int my_memcmp(const void *s1, const void *s2, size_t num); + +#endif /* !MY_MEMCMP_H */ diff --git a/rushs/tinyprintf/my_memcpy/my_memcpy.c b/rushs/tinyprintf/my_memcpy/my_memcpy.c new file mode 100644 index 0000000..a6a48d4 --- /dev/null +++ b/rushs/tinyprintf/my_memcpy/my_memcpy.c @@ -0,0 +1,28 @@ +#include "my_memcpy.h" + +void *my_memcpy(void *dest, const void *source, size_t num) +{ + char *d = dest; + const char *s = source; + if (dest > source) // reverse array + { + size_t l = num; + for (; l > 0; l--) + { + d[l - 1] = s[l - 1]; + } + } + else + { + for (size_t i = 0; i < num; i++) + { + d[i] = s[i]; + } + } + return dest; +} + +int main(void) +{ + return 0; +} diff --git a/rushs/tinyprintf/my_memcpy/my_memcpy.h b/rushs/tinyprintf/my_memcpy/my_memcpy.h new file mode 100644 index 0000000..bc1b926 --- /dev/null +++ b/rushs/tinyprintf/my_memcpy/my_memcpy.h @@ -0,0 +1,8 @@ +#ifndef MY_MEMCPY_H +#define MY_MEMCPY_H + +#include <stddef.h> + +void *my_memcpy(void *dest, const void *source, size_t num); + +#endif /* ! MY_MEMCPY_H */ diff --git a/rushs/tinyprintf/my_memmove/my_memmove.c b/rushs/tinyprintf/my_memmove/my_memmove.c new file mode 100644 index 0000000..bb360a5 --- /dev/null +++ b/rushs/tinyprintf/my_memmove/my_memmove.c @@ -0,0 +1,23 @@ +#include "my_memmove.h" + +void *my_memmove(void *dest, const void *src, size_t n) +{ + char *d = dest; + const char *s = src; + if (dest > src) // reverse array + { + size_t l = n; + for (; l > 0; l--) + { + d[l - 1] = s[l - 1]; + } + } + else + { + for (size_t i = 0; i < n; i++) + { + d[i] = s[i]; + } + } + return dest; +} diff --git a/rushs/tinyprintf/my_memmove/my_memmove.h b/rushs/tinyprintf/my_memmove/my_memmove.h new file mode 100644 index 0000000..cb253b7 --- /dev/null +++ b/rushs/tinyprintf/my_memmove/my_memmove.h @@ -0,0 +1,8 @@ +#ifndef MY_MEMMOVE_H +#define MY_MEMMOVE_H + +#include <stddef.h> + +void *my_memmove(void *dest, const void *src, size_t n); + +#endif /* ! MY_MEMMOVE_H */ diff --git a/rushs/tinyprintf/my_memset/my_memset.c b/rushs/tinyprintf/my_memset/my_memset.c new file mode 100644 index 0000000..243a5ac --- /dev/null +++ b/rushs/tinyprintf/my_memset/my_memset.c @@ -0,0 +1,12 @@ +#include "my_memset.h" + +void *my_memset(void *s, int c, size_t n) +{ + unsigned char *t = s; + for (size_t i = 0; i < n; i++) + { + t[i] = c; + } + + return t; +} diff --git a/rushs/tinyprintf/my_memset/my_memset.h b/rushs/tinyprintf/my_memset/my_memset.h new file mode 100644 index 0000000..e5ed0f0 --- /dev/null +++ b/rushs/tinyprintf/my_memset/my_memset.h @@ -0,0 +1,6 @@ +#ifndef MY_MEMSET_H +#define MY_MEMSET_H + +#include <stddef.h> + +#endif /* ! MY_MEMSET_H */ diff --git a/rushs/tinyprintf/my_pow/my_pow.c b/rushs/tinyprintf/my_pow/my_pow.c new file mode 100644 index 0000000..f529d87 --- /dev/null +++ b/rushs/tinyprintf/my_pow/my_pow.c @@ -0,0 +1,13 @@ +int my_pow(int a, int b) +{ + if (!a) + return b == 0; + int res = 1; + for (int i = 0; i < b / 2; i++) + { + res *= a * a; + } + if (b % 2) + res *= a; + return res; +} diff --git a/rushs/tinyprintf/my_round/my_round.c b/rushs/tinyprintf/my_round/my_round.c new file mode 100644 index 0000000..324bc1d --- /dev/null +++ b/rushs/tinyprintf/my_round/my_round.c @@ -0,0 +1,6 @@ +int my_round(float n) +{ + if (n < 0) + return n - 0.5; + return n + 0.5; +} diff --git a/rushs/tinyprintf/my_strcmp/my_strcmp.c b/rushs/tinyprintf/my_strcmp/my_strcmp.c new file mode 100644 index 0000000..d3ef3e3 --- /dev/null +++ b/rushs/tinyprintf/my_strcmp/my_strcmp.c @@ -0,0 +1,11 @@ +#include "my_strcmp.h" + +int my_strcmp(const char *s1, const char *s2) +{ + for (; *s1 && *s1 == *s2; s1++, s2++) + { + continue; + } + + return *s1 - *s2; +} diff --git a/rushs/tinyprintf/my_strcmp/my_strcmp.h b/rushs/tinyprintf/my_strcmp/my_strcmp.h new file mode 100644 index 0000000..d89a00b --- /dev/null +++ b/rushs/tinyprintf/my_strcmp/my_strcmp.h @@ -0,0 +1,6 @@ +#ifndef MY_STRCMP_H +#define MY_STRCMP_H + +#include <stddef.h> + +#endif /* ! MY_STRCMP_H */ diff --git a/rushs/tinyprintf/my_strcpy/my_strcpy.c b/rushs/tinyprintf/my_strcpy/my_strcpy.c new file mode 100644 index 0000000..69ad5ee --- /dev/null +++ b/rushs/tinyprintf/my_strcpy/my_strcpy.c @@ -0,0 +1,13 @@ +#include <stdlib.h> + +char *my_strcpy(char *dest, const char *source) +{ + size_t i; + for (i = 0; source[i]; i++) + { + dest[i] = source[i]; + } + dest[i] = '\0'; + + return dest; +} diff --git a/rushs/tinyprintf/my_strlen/my_strlen.c b/rushs/tinyprintf/my_strlen/my_strlen.c new file mode 100644 index 0000000..ec80d0b --- /dev/null +++ b/rushs/tinyprintf/my_strlen/my_strlen.c @@ -0,0 +1,12 @@ +#include "my_strlen.h" + +size_t my_strlen(const char *s) +{ + size_t i; + for (i = 0; s[i]; i++) + { + continue; + } + + return i; +} diff --git a/rushs/tinyprintf/my_strlen/my_strlen.h b/rushs/tinyprintf/my_strlen/my_strlen.h new file mode 100644 index 0000000..02806cc --- /dev/null +++ b/rushs/tinyprintf/my_strlen/my_strlen.h @@ -0,0 +1,6 @@ +#ifndef MY_STRLEN_H +#define MY_STRLEN_H + +#include <stddef.h> + +#endif /* ! MY_STRLEN_H */ diff --git a/rushs/tinyprintf/my_strlowcase/my_strlowcase.c b/rushs/tinyprintf/my_strlowcase/my_strlowcase.c new file mode 100644 index 0000000..e52ea32 --- /dev/null +++ b/rushs/tinyprintf/my_strlowcase/my_strlowcase.c @@ -0,0 +1,13 @@ +#include "my_strlowcase.h" + +void my_strlowcase(char *s) +{ + size_t i; + for (i = 0; s[i]; i++) + { + if (s[i] >= 'A' && s[i] <= 'Z') + { + s[i] += ('a' - 'A'); + } + } +} diff --git a/rushs/tinyprintf/my_strlowcase/my_strlowcase.h b/rushs/tinyprintf/my_strlowcase/my_strlowcase.h new file mode 100644 index 0000000..d4996b8 --- /dev/null +++ b/rushs/tinyprintf/my_strlowcase/my_strlowcase.h @@ -0,0 +1,8 @@ +#ifndef MY_STRLOWCASE_H +#define MY_STRLOWCASE_H + +#include <stddef.h> + +void my_strlowcase(char *str); + +#endif /* ! MY_STRLOWCASE_H */ diff --git a/rushs/tinyprintf/my_strspn/my_strspn.c b/rushs/tinyprintf/my_strspn/my_strspn.c new file mode 100644 index 0000000..18bba0f --- /dev/null +++ b/rushs/tinyprintf/my_strspn/my_strspn.c @@ -0,0 +1,26 @@ +#include "my_strspn.h" + +int is_in(char c, const char *accept) +{ + for (; *accept && *accept != c; accept++) + { + continue; + } + return *accept != '\0'; +} + +size_t my_strspn(const char *s, const char *accept) +{ + if (s == NULL || *s == '\0') + { + return 0; + } + + size_t res; + for (res = 0; *s && is_in(*s, accept) != 0; res++, s++) + { + continue; + } + + return res; +} diff --git a/rushs/tinyprintf/my_strspn/my_strspn.h b/rushs/tinyprintf/my_strspn/my_strspn.h new file mode 100644 index 0000000..f2d7759 --- /dev/null +++ b/rushs/tinyprintf/my_strspn/my_strspn.h @@ -0,0 +1,8 @@ +#ifndef MY_STRSPN_H +#define MY_STRSPN_H + +#include <stddef.h> + +size_t my_strspn(const char *s, const char *accept); + +#endif /* ! MY_STRSPN_H */ diff --git a/rushs/tinyprintf/my_strstr/my_strstr.c b/rushs/tinyprintf/my_strstr/my_strstr.c new file mode 100644 index 0000000..36ac439 --- /dev/null +++ b/rushs/tinyprintf/my_strstr/my_strstr.c @@ -0,0 +1,34 @@ +#include "my_strstr.h" + +#include <stddef.h> + +int my_strstr(const char *haystack, const char *needle) +{ + if (needle == NULL || *needle == '\0') + { + return 0; + } + + for (int i = 0; haystack[i]; i++) + { + if (haystack[i] == needle[0]) + { + int j; + for (j = 0; + haystack[i + j] && needle[j] && needle[j] == haystack[i + j]; + j++) + { + continue; + } + if (needle[j] == '\0') + { + return i; + } + if (haystack[i + j] == '\0') + { + return -1; + } + } + } + return -1; +} diff --git a/rushs/tinyprintf/my_strstr/my_strstr.h b/rushs/tinyprintf/my_strstr/my_strstr.h new file mode 100644 index 0000000..1b734b2 --- /dev/null +++ b/rushs/tinyprintf/my_strstr/my_strstr.h @@ -0,0 +1,6 @@ +#ifndef MY_STRSTR_H +#define MY_STRSTR_H + +int my_strstr(const char *haystack, const char *needle); + +#endif /* ! MY_STRSTR_H */ diff --git a/rushs/tinyprintf/my_strtok_r/my_strtok_r.c b/rushs/tinyprintf/my_strtok_r/my_strtok_r.c new file mode 100644 index 0000000..ec052b7 --- /dev/null +++ b/rushs/tinyprintf/my_strtok_r/my_strtok_r.c @@ -0,0 +1,51 @@ +#include "my_strtok_r.h" + +#include <stddef.h> + +static int is_delim(char c, const char *delims) +{ + for (const char *d = delims; *d; d++) + { + if (*d == c) + return 1; + } + return 0; +} + +char *my_strtok_r(char *str, const char *delim, char **saveptr) +{ + if (str == NULL) + { + if (*saveptr == NULL) + { + return NULL; + } + str = *saveptr; + } + + size_t i = 0; + while (str[i] != '\0' && is_delim(str[i], delim)) + { + i++; + } + if (str[i] == '\0') + { + *saveptr = NULL; + return NULL; + } + + char *res = str + i; + + while (str[i] != '\0' && !is_delim(str[i], delim)) + { + i++; + } + if (str[i] == '\0') + { + *saveptr = NULL; + return res; + } + *saveptr = str + i + 1; + str[i] = '\0'; + return res; +} diff --git a/rushs/tinyprintf/my_strtok_r/my_strtok_r.h b/rushs/tinyprintf/my_strtok_r/my_strtok_r.h new file mode 100644 index 0000000..5603729 --- /dev/null +++ b/rushs/tinyprintf/my_strtok_r/my_strtok_r.h @@ -0,0 +1,6 @@ +#ifndef MY_STRTOK_R_H +#define MY_STRTOK_R_H + +char *my_strtok_r(char *str, const char *delim, char **saveptr); + +#endif /* ! MY_STRTOK_R_H */ diff --git a/rushs/tinyprintf/null_terminated_arrays/null_terminated_arrays.c b/rushs/tinyprintf/null_terminated_arrays/null_terminated_arrays.c new file mode 100644 index 0000000..32d2a17 --- /dev/null +++ b/rushs/tinyprintf/null_terminated_arrays/null_terminated_arrays.c @@ -0,0 +1,50 @@ +#include "null_terminated_arrays.h" + +#include <assert.h> +#include <stddef.h> +#include <stdio.h> + +void reverse_array(const char **arr) +{ + const char **p; + for (p = arr; *p; p++) + { + continue; + } + p--; + + while (p > arr) + { + const char *tmp = *p; + *p = *arr; + *arr = tmp; + arr++; + p--; + } +} + +void reverse_matrix(const char ***matrix) +{ + const char ***p; + for (p = matrix; *p; p++) + { + continue; + } + p--; + + while (p > matrix) + { + reverse_array(*p); + reverse_array(*matrix); + const char **tmp = *p; + *p = *matrix; + *matrix = tmp; + matrix++; + p--; + } + + if (p == matrix) + { + reverse_array(*matrix); + } +} diff --git a/rushs/tinyprintf/null_terminated_arrays/null_terminated_arrays.h b/rushs/tinyprintf/null_terminated_arrays/null_terminated_arrays.h new file mode 100644 index 0000000..31fccc5 --- /dev/null +++ b/rushs/tinyprintf/null_terminated_arrays/null_terminated_arrays.h @@ -0,0 +1,6 @@ +#ifndef NULL_TERMINATED_ARRAYS_H_ +#define NULL_TERMINATED_ARRAYS_H_ + +void reverse_matrix(const char ***matrix); + +#endif /* !NULL_TERMINATED_ARRAYS_H_ */ diff --git a/rushs/tinyprintf/number_digits_rec/number_digits_rec.c b/rushs/tinyprintf/number_digits_rec/number_digits_rec.c new file mode 100644 index 0000000..94de296 --- /dev/null +++ b/rushs/tinyprintf/number_digits_rec/number_digits_rec.c @@ -0,0 +1,8 @@ +unsigned int number_digits_rec(unsigned int n) +{ + if (n / 10 == 0) + { + return 1; + } + return 1 + number_digits_rec(n / 10); +} diff --git a/rushs/tinyprintf/palindrome/palindrome.c b/rushs/tinyprintf/palindrome/palindrome.c new file mode 100644 index 0000000..2ecacfd --- /dev/null +++ b/rushs/tinyprintf/palindrome/palindrome.c @@ -0,0 +1,47 @@ +#include "palindrome.h" + +#include <stddef.h> + +int palindrome(const char *s) +{ + if (s == NULL) + { + return 0; + } + + if (*s == '\0') + { + return 1; + } + + const char *p = s; + while (*p) + { + p++; + } + p--; + + while (p > s) + { + while ((*p < '0' || (*p > '9' && *p < 'A') || (*p > 'Z' && *p < 'a') + || *p > 'z') + && p > s) + { + p--; + } + while ((*s < '0' || (*s > '9' && *s < 'A') || (*s > 'Z' && *s < 'a') + || *s > 'z') + && p > s) + { + s++; + } + if (*p != *s) + { + return 0; + } + p--; + s++; + } + + return 1; +} diff --git a/rushs/tinyprintf/palindrome/palindrome.h b/rushs/tinyprintf/palindrome/palindrome.h new file mode 100644 index 0000000..8595911 --- /dev/null +++ b/rushs/tinyprintf/palindrome/palindrome.h @@ -0,0 +1,6 @@ +#ifndef PALINDROME_H +#define PALINDROME_H + +int palindrome(const char *s); + +#endif /* !PALINDROME_H */ diff --git a/rushs/tinyprintf/pine/pine.c b/rushs/tinyprintf/pine/pine.c new file mode 100644 index 0000000..9d48761 --- /dev/null +++ b/rushs/tinyprintf/pine/pine.c @@ -0,0 +1,36 @@ +#include <stdio.h> + +int pine(unsigned n) +{ + if (n < 3) + { + return 1; + } + + for (unsigned i = 0; i < n; i++) + { + for (unsigned j = 0; j < n - i - 1; j++) + { + putchar(' '); + } + + for (unsigned j = 0; j < 2 * i + 1; j++) + { + putchar('*'); + } + + putchar('\n'); + } + + for (unsigned i = 0; i < n / 2; i++) + { + for (unsigned j = 0; j < n - 1; j++) + { + putchar(' '); + } + putchar('*'); + putchar('\n'); + } + + return 0; +} diff --git a/rushs/tinyprintf/pointer_swap/pointer_swap.c b/rushs/tinyprintf/pointer_swap/pointer_swap.c new file mode 100644 index 0000000..32ceb84 --- /dev/null +++ b/rushs/tinyprintf/pointer_swap/pointer_swap.c @@ -0,0 +1,6 @@ +void pointer_swap(int **a, int **b) +{ + int *tmp = *a; + *a = *b; + *b = tmp; +} diff --git a/rushs/tinyprintf/prototypes/prototypes.sh b/rushs/tinyprintf/prototypes/prototypes.sh new file mode 100755 index 0000000..3c80468 --- /dev/null +++ b/rushs/tinyprintf/prototypes/prototypes.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +sed -En 's/^(([a-zA-Z]* ){0,2}([a-zA-Z]*) *\**([a-z][a-z0-9_]*)\((([a-zA-Z]* )?([a-zA-Z]* )?([a-z][a-z0-9_]* *)(\**[a-z][a-z0-9_]*|[a-z][a-z0-9_]*\[([0-9][0-9]*)?\])(, ([a-zA-Z]* )?([a-zA-Z]* )?([a-z][a-z0-9_]* *)(\**[a-z][a-z0-9_]*|[a-z][a-z0-9_]*\[([0-9][0-9]*)?\])){0,3}|void)\))$/\1;/p' "$1" diff --git a/rushs/tinyprintf/quick_sort/quick_sort.c b/rushs/tinyprintf/quick_sort/quick_sort.c new file mode 100644 index 0000000..6c61fc3 --- /dev/null +++ b/rushs/tinyprintf/quick_sort/quick_sort.c @@ -0,0 +1,18 @@ +#include <stddef.h> + +void quicksort(int *tab, size_t len) +{ + if (tab == NULL) + { + return; + } + for (size_t i = 1; i < len; i++) + { + for (size_t j = i; j > 0 && tab[j - 1] > tab[j]; j--) + { + int tmp = tab[j]; + tab[j] = tab[j - 1]; + tab[j - 1] = tmp; + } + } +} diff --git a/rushs/tinyprintf/quick_sort/quick_sort_example.c b/rushs/tinyprintf/quick_sort/quick_sort_example.c new file mode 100644 index 0000000..2a5228f --- /dev/null +++ b/rushs/tinyprintf/quick_sort/quick_sort_example.c @@ -0,0 +1,19 @@ +#include <stdio.h> + +void quicksort(int *tab, int len); + +int main(void) +{ + unsigned i = 0; + int tab[] = { 10, 11, 2, 3, 8, 5, 7, 6, 26, 30, 2, 1, 17, 13, 14 }; + + unsigned size = sizeof(tab) / sizeof(int); + + quicksort(tab, size); + + for (; i < size - 1; ++i) + printf("%d ", tab[i]); + printf("%d\n", tab[i]); + + return 0; +} diff --git a/rushs/tinyprintf/repeat/repeat.c b/rushs/tinyprintf/repeat/repeat.c new file mode 100644 index 0000000..06d0b43 --- /dev/null +++ b/rushs/tinyprintf/repeat/repeat.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +int main(int argc, char **argv) +{ + if (argc != 3) + return 1; + + for (int i = 0; i < argv[2][0] - '0'; i++) + puts(argv[1]); + return 0; +} diff --git a/rushs/tinyprintf/right_tarball/my_tarball.tar.gz b/rushs/tinyprintf/right_tarball/my_tarball.tar.gz Binary files differnew file mode 100644 index 0000000..eb6acfc --- /dev/null +++ b/rushs/tinyprintf/right_tarball/my_tarball.tar.gz diff --git a/rushs/tinyprintf/rotx/rotx.c b/rushs/tinyprintf/rotx/rotx.c new file mode 100644 index 0000000..a2cb820 --- /dev/null +++ b/rushs/tinyprintf/rotx/rotx.c @@ -0,0 +1,59 @@ +#include <stdlib.h> +#include <unistd.h> + +#define BUFFER_SIZE 10 + +int main(int argc, char **argv) +{ + if (argc != 2) + { + return 0; + } + + int rot = atoi(argv[1]); + int rod = rot; + if (rot < 0) + { + rot = (rot % 26) + 26; + rod = (rod % 10) + 10; + } + + char buf[BUFFER_SIZE]; + ssize_t r; + + while ((r = read(STDIN_FILENO, buf, BUFFER_SIZE))) + { + if (r == -1) + { + return 1; + } + + for (ssize_t i = 0; i < r; i++) + { + if (buf[i] >= 'a' && buf[i] <= 'z') + { + buf[i] = ((buf[i] - 'a') + rot) % 26 + 'a'; + } + else if (buf[i] >= 'A' && buf[i] <= 'Z') + { + buf[i] = ((buf[i] - 'A') + rot) % 26 + 'A'; + } + else if (buf[i] >= '0' && buf[i] <= '9') + { + buf[i] = ((buf[i] - '0') + rod) % 10 + '0'; + } + } + + ssize_t w = write(STDOUT_FILENO, buf, r); + while (w != r) + { + w += write(STDOUT_FILENO, buf, r); + if (w == -1) + { + return 1; + } + } + } + + return 0; +} diff --git a/rushs/tinyprintf/sed_trailing_whitespaces/whitespaces.sed b/rushs/tinyprintf/sed_trailing_whitespaces/whitespaces.sed new file mode 100644 index 0000000..46b7017 --- /dev/null +++ b/rushs/tinyprintf/sed_trailing_whitespaces/whitespaces.sed @@ -0,0 +1 @@ +s/[ \t]*$// diff --git a/rushs/tinyprintf/selection_sort/selection_sort.c b/rushs/tinyprintf/selection_sort/selection_sort.c new file mode 100644 index 0000000..98adc7e --- /dev/null +++ b/rushs/tinyprintf/selection_sort/selection_sort.c @@ -0,0 +1,30 @@ +#include <stddef.h> + +void swap(int *a, int *b) +{ + int tmp = *a; + *a = *b; + *b = tmp; +} + +unsigned array_min(const int arr[], unsigned start, unsigned size) +{ + unsigned min = start; + for (; start < size; start++) + { + if (arr[min] > arr[start]) + { + min = start; + } + } + return min; +} + +void selection_sort(int arr[], unsigned size) +{ + for (size_t i = 0; i < size; i++) + { + unsigned j = array_min(arr, i, size); + swap(&(arr[i]), &(arr[j])); + } +} diff --git a/rushs/tinyprintf/seq/seq.sh b/rushs/tinyprintf/seq/seq.sh new file mode 100755 index 0000000..9721432 --- /dev/null +++ b/rushs/tinyprintf/seq/seq.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +if [ $# -ne 3 ]; then + echo "Usage: ./seq.sh FIRST INCREMENT LAST" 1>&2 + exit 1 +fi + +if [ "$2" -eq 0 ]; then + exit 1 +fi + +if [ "$1" -eq "$3" ]; then + echo "$1" + exit 0 +fi + +if [ "$1" -lt "$3" ]; then + [ 0 -gt "$2" ] && exit 1 + i="$1" + while [ "$3" -ge "$i" ]; do + echo "$i" + i=$(($i + $2)) + done + exit 0 +fi + +[ "$2" -gt 0 ] && exit 1 +i="$1" +while [ "$i" -ge "$3" ]; do + echo "$i" + i=$(($i + $2)) +done +exit 0 diff --git a/rushs/tinyprintf/sieve_eratosthenes_advanced/Makefile b/rushs/tinyprintf/sieve_eratosthenes_advanced/Makefile new file mode 100644 index 0000000..c7e35f9 --- /dev/null +++ b/rushs/tinyprintf/sieve_eratosthenes_advanced/Makefile @@ -0,0 +1,13 @@ +CC=gcc +CFLAGS=-std=c99 -Wall -Wextra -Werror -Wvla -pedantic +LDLIBS= + +all: sieve.o + +sieve.o: sieve.c + $(CC) $(CFLAGS) -c -o sieve.o sieve.c + +.PHONY: clean + +clean: + rm sieve.o diff --git a/rushs/tinyprintf/sieve_eratosthenes_advanced/sieve.c b/rushs/tinyprintf/sieve_eratosthenes_advanced/sieve.c new file mode 100644 index 0000000..7dd4816 --- /dev/null +++ b/rushs/tinyprintf/sieve_eratosthenes_advanced/sieve.c @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <stdlib.h> + +void sieve(int n) +{ + if (n <= 2) + { + return; + } + + // Generate array + int *a = calloc(n, sizeof(int)); + int count = 0; + + // Actual sieve and count + for (int i = 2; i < n; i++) + { + if (a[i] == 0) + { + for (int k = 2 * i; k < n; k += i) + { + a[k] = 1; + } + } + } + + for (int i = 2; i < n; i++) + { + if (a[i] == 0) + { + count++; + } + } + + // Print the count + printf("%d\n", count); + + free(a); +} diff --git a/rushs/tinyprintf/simple_fnmatch/simple_fnmatch.c b/rushs/tinyprintf/simple_fnmatch/simple_fnmatch.c new file mode 100644 index 0000000..d40353f --- /dev/null +++ b/rushs/tinyprintf/simple_fnmatch/simple_fnmatch.c @@ -0,0 +1,46 @@ +#include "simple_fnmatch.h" + +int simple_fnmatch(const char *pattern, const char *string) +{ + if (!pattern || !string) + return FNM_NOMATCH; + if (*pattern == '*' && pattern[1] == '\0') + return 0; + while (*pattern && *string) + { + if (*pattern == '?') + { + pattern++; + string++; + } + else if (*pattern == '\\') + { + pattern++; + if (!pattern || *pattern != *string) + return FNM_NOMATCH; + string++; + pattern++; + } + else if (*pattern == '*') + { + pattern++; + while (*string && simple_fnmatch(pattern, string)) + string++; + if (*string) + return 0; + } + else if (*pattern != *string) + return FNM_NOMATCH; + else + { + string++; + pattern++; + } + } + + if (*pattern == '*' && pattern[1] == '\0') + return 0; + if (*string || *pattern) + return FNM_NOMATCH; + return 0; +} diff --git a/rushs/tinyprintf/simple_fnmatch/simple_fnmatch.h b/rushs/tinyprintf/simple_fnmatch/simple_fnmatch.h new file mode 100644 index 0000000..e1ae166 --- /dev/null +++ b/rushs/tinyprintf/simple_fnmatch/simple_fnmatch.h @@ -0,0 +1,8 @@ +#ifndef SIMPLE_FNMATCH_H +#define SIMPLE_FNMATCH_H + +#define FNM_NOMATCH 1 + +int simple_fnmatch(const char *pattern, const char *string); + +#endif /* !SIMPLE_FNMATCH_H */ diff --git a/rushs/tinyprintf/stack/stack.c b/rushs/tinyprintf/stack/stack.c new file mode 100644 index 0000000..0498abc --- /dev/null +++ b/rushs/tinyprintf/stack/stack.c @@ -0,0 +1,30 @@ +#include "stack.h" + +#include <stdlib.h> + +struct stack *stack_push(struct stack *s, int e) +{ + struct stack *new = malloc(sizeof(struct stack)); + new->data = e; + new->next = NULL; + + new->next = s; + return new; +} + +struct stack *stack_pop(struct stack *s) +{ + if (s == NULL) + { + return NULL; + } + + struct stack *res = s->next; + free(s); + return res; +} + +int stack_peek(struct stack *s) +{ + return s->data; +} diff --git a/rushs/tinyprintf/stack/stack.h b/rushs/tinyprintf/stack/stack.h new file mode 100644 index 0000000..bd5dd24 --- /dev/null +++ b/rushs/tinyprintf/stack/stack.h @@ -0,0 +1,14 @@ +#ifndef STACK_H +#define STACK_H + +struct stack +{ + int data; + struct stack *next; +}; + +struct stack *stack_push(struct stack *s, int e); +struct stack *stack_pop(struct stack *s); +int stack_peek(struct stack *s); + +#endif /* !STACK_H */ diff --git a/rushs/tinyprintf/str_revert/str_revert.c b/rushs/tinyprintf/str_revert/str_revert.c new file mode 100644 index 0000000..31f7f3d --- /dev/null +++ b/rushs/tinyprintf/str_revert/str_revert.c @@ -0,0 +1,25 @@ +#include "str_revert.h" + +#include <stddef.h> + +void str_revert(char str[]) +{ + if (*str == '\0') + { + return; + } + + size_t len = 0; + for (; str[len]; len++) + { + continue; + } + len--; + + for (size_t i = 0; i <= len / 2; i++) + { + char tmp = str[i]; + str[i] = str[len - i]; + str[len - i] = tmp; + } +} diff --git a/rushs/tinyprintf/str_revert/str_revert.h b/rushs/tinyprintf/str_revert/str_revert.h new file mode 100644 index 0000000..daa23d4 --- /dev/null +++ b/rushs/tinyprintf/str_revert/str_revert.h @@ -0,0 +1,6 @@ +#ifndef STR_REVERT_H +#define STR_REVERT_H + +void str_revert(char str[]); + +#endif /* ! STR_REVERT_H */ diff --git a/rushs/tinyprintf/test.txt b/rushs/tinyprintf/test.txt new file mode 100644 index 0000000..958cdbc --- /dev/null +++ b/rushs/tinyprintf/test.txt @@ -0,0 +1,3 @@ +This is a short line. +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +This is another short line. diff --git a/rushs/tinyprintf/test_a_bit/is_set.c b/rushs/tinyprintf/test_a_bit/is_set.c new file mode 100644 index 0000000..38fccf8 --- /dev/null +++ b/rushs/tinyprintf/test_a_bit/is_set.c @@ -0,0 +1,6 @@ +#include "is_set.h" + +unsigned int is_set(unsigned int value, unsigned char n) +{ + return (value & (1 << (n - 1))) != 0; +} diff --git a/rushs/tinyprintf/test_a_bit/is_set.h b/rushs/tinyprintf/test_a_bit/is_set.h new file mode 100644 index 0000000..8f2fd9a --- /dev/null +++ b/rushs/tinyprintf/test_a_bit/is_set.h @@ -0,0 +1,6 @@ +#ifndef IS_SET_H +#define IS_SET_H + +unsigned int is_set(unsigned int value, unsigned char n); + +#endif /* ! IS_SET_H */ diff --git a/rushs/tinyprintf/test_a_bit/test.c b/rushs/tinyprintf/test_a_bit/test.c new file mode 100644 index 0000000..e3403e4 --- /dev/null +++ b/rushs/tinyprintf/test_a_bit/test.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +#include "is_set.h" + +int main(void) +{ + printf("%d\n", is_set(24, 4)); + printf("%d\n", is_set(24, 3)); + + return 0; +} diff --git a/rushs/tinyprintf/tinylibstream/Makefile b/rushs/tinyprintf/tinylibstream/Makefile new file mode 100644 index 0000000..b060495 --- /dev/null +++ b/rushs/tinyprintf/tinylibstream/Makefile @@ -0,0 +1,13 @@ +CC = gcc +CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla + +.PHONY: library clean + +library: src/tinylibstream.o + ar csr libstream.a src/tinylibstream.o + +clean: + rm libstream.a src/tinylibstream.o + +check: + $(CC) $(CFLAGS) -lcriterion src/tinylibstream.c tests/tests.c diff --git a/rushs/tinyprintf/tinylibstream/include/libstream.h b/rushs/tinyprintf/tinylibstream/include/libstream.h new file mode 100644 index 0000000..459432d --- /dev/null +++ b/rushs/tinyprintf/tinylibstream/include/libstream.h @@ -0,0 +1,167 @@ +#ifndef LIBSTREAM_H +#define LIBSTREAM_H + +#include <fcntl.h> +#include <stdbool.h> +#include <stddef.h> +#include <unistd.h> + +/* +** /!\ DO NOT MODIFY THIS FILE, AS IT WILL BE OVERRIDDEN DURING CORRECTION. /!\ +** +** You can add your own functions declarations to OTHER HEADER FILES. +*/ + +/* the value returned when end of file is reached */ +#define LBS_EOF (-1) + +/* the size of the buffer */ +#define LBS_BUFFER_SIZE 32 + +/* +** Describes the current operation: +** - if reading, the buffer contains read-buffered data +** - if writing, the buffer contains write-buffered data +*/ +enum stream_io_operation +{ + STREAM_READING = 0, + STREAM_WRITING, +}; + +/* +** Controls when to flush the buffer: +** - when unbuffered, flush every time a character is written +** - when buffered, flush when the buffer is full +** - when line buffered, flush when the buffer is full or when a \n +** character is written +*/ +enum stream_buffering +{ + STREAM_UNBUFFERED = 0, + STREAM_LINE_BUFFERED, + STREAM_BUFFERED, +}; + +struct stream +{ + /* the flags passed to open */ + int flags; + + /* + ** Initially, this variable is 0. + ** When a function such as fgetc fails, it is set to 1 to indicate + ** something went wrong. This is useful to make the difference between + ** reaching the end of file and read errors while using fgetc and + ** some others. + ** It is often referred to as the error indicator. + */ + int error; + + /* the file descriptor, as returned by open(2) */ + int fd; + + /* + ** the kind of data stored by the buffer. + ** The default value shouldn't matter. + */ + enum stream_io_operation io_operation; + + /* + ** defines when to flush **output**. + ** This field does not control input buffering (which is always fully + ** buffered). + ** + ** The default value is LINE_BUFFERED if isatty(fd), BUFFERED otherwise. + */ + enum stream_buffering buffering_mode; + + /* the amount of used bytes in the buffer */ + size_t buffered_size; + + /* + ** /!\ This field only makes sense when io_operation is STREAM_READING /!\ + ** the amount of data already read from the buffer by the user. + */ + size_t already_read; + + /* + ** buffer + ** --------------> + ** +==============+====================+---------------------+ + ** | already_read | remaining_buffered | unused_buffer_space | + ** +==============+====================+---------------------+ + ** \_______________________________/ + ** buffered_size + ** + ** /!\ The buffer can contain either read-buffered or write-buffered data, + ** depending on the value of io_operation /!\ + */ + char buffer[LBS_BUFFER_SIZE]; +}; + +/* +** These functions are defined in a header for optimization reasons: +** each .c file that includes this header will get its own copy of the +** function's code, thus easily make optimizations. +** +** ``static`` means each compilation unit (.c file) will have its own copy +** of the function without them clashing. +** +** ``inline`` means the content of the function should be "copy pasted" +** where it's called. It also tells the compiler not to complain when the +** function isn't used. +** +** They're just like a macro, except the type of arguments is checked. +*/ + +static inline size_t stream_remaining_buffered(struct stream *stream) +{ + return stream->buffered_size - stream->already_read; +} + +static inline size_t stream_unused_buffer_space(struct stream *stream) +{ + return sizeof(stream->buffer) - stream->buffered_size; +} + +static inline bool stream_readable(struct stream *stream) +{ + int access_mode = stream->flags & O_ACCMODE; + if (access_mode == O_RDWR) + return true; + return access_mode == O_RDONLY; +} + +static inline bool stream_writable(struct stream *stream) +{ + int access_mode = stream->flags & O_ACCMODE; + if (access_mode == O_RDWR) + return true; + return access_mode == O_WRONLY; +} + +static inline int lbs_ferror(struct stream *stream) +{ + return stream->error; +} + +static inline void lbs_clearerr(struct stream *stream) +{ + stream->error = 0; +} + +static inline void lbs_setbufmode(struct stream *stream, + enum stream_buffering mode) +{ + stream->buffering_mode = mode; +} + +struct stream *lbs_fopen(const char *path, const char *mode); +struct stream *lbs_fdopen(int fd, const char *mode); +int lbs_fflush(struct stream *stream); +int lbs_fclose(struct stream *stream); +int lbs_fputc(int c, struct stream *stream); +int lbs_fgetc(struct stream *stream); + +#endif /* !LIBSTREAM_H */ diff --git a/rushs/tinyprintf/tinylibstream/src/tinylibstream.c b/rushs/tinyprintf/tinylibstream/src/tinylibstream.c new file mode 100644 index 0000000..dca1c01 --- /dev/null +++ b/rushs/tinyprintf/tinylibstream/src/tinylibstream.c @@ -0,0 +1,221 @@ +#include <stdlib.h> +#include <string.h> + +#include "../include/libstream.h" + +int get_flags(const char *mode) +{ + int flags; + if (strcmp(mode, "r") == 0) + { + flags = O_RDONLY; + } + else if (strcmp(mode, "r+") == 0) + { + flags = O_RDWR; + } + else if (strcmp(mode, "w") == 0) + { + flags = O_WRONLY | O_TRUNC | O_CREAT; + } + else + { + flags = O_RDWR | O_TRUNC | O_CREAT; + } + + return flags; +} + +struct stream *lbs_fopen(const char *path, const char *mode) +{ + int fd = open(path, get_flags(mode)); + + return lbs_fdopen(fd, mode); +} + +struct stream *lbs_fdopen(int fd, const char *mode) +{ + if (fd == -1) + { + return NULL; + } + + struct stream *s = malloc(sizeof(struct stream)); + if (s == NULL) + { + return NULL; + } + + s->flags = get_flags(mode); + s->error = 0; + s->fd = fd; + if (isatty(fd)) + { + s->buffering_mode = STREAM_LINE_BUFFERED; + } + else + { + s->buffering_mode = STREAM_BUFFERED; + } + s->buffered_size = 0; + s->already_read = 0; + + return s; +} + +int lbs_fflush(struct stream *stream) +{ + if (stream == NULL || stream->buffered_size == 0) + { + return 0; + } + + if (stream->io_operation == STREAM_READING) + { + if (!stream_readable(stream)) + { + stream->error = 1; + return LBS_EOF; + } + if (stream_remaining_buffered(stream) != 0 + && lseek(stream->fd, -stream_remaining_buffered(stream), SEEK_CUR) + == -1) + { + stream->error = 1; + return LBS_EOF; + } + stream->buffered_size = 0; + stream->already_read = 0; + } + else + { + if (!stream_writable(stream)) + { + stream->error = 1; + return LBS_EOF; + } + ssize_t w; + if ((w = write(stream->fd, stream->buffer, stream->buffered_size)) + == -1) + { + stream->error = 1; + return LBS_EOF; + } + stream->buffered_size = 0; + stream->already_read = 0; + } + return 0; +} + +int lbs_fclose(struct stream *stream) +{ + if (stream == NULL) + { + return 1; + } + + lbs_fflush(stream); + if (close(stream->fd) == -1) + { + return 1; + } + + free(stream); + + return 0; +} + +int lbs_fputc(int c, struct stream *stream) +{ + if (!stream_writable(stream)) + { + stream->error = 1; + return -1; + } + + if (stream->io_operation == STREAM_READING) + { + if (lbs_fflush(stream) != 0) + { + return -1; + } + stream->buffered_size = 0; + stream->already_read = 0; + } + stream->io_operation = STREAM_WRITING; + + if (stream_unused_buffer_space(stream) == 0 + || stream->buffering_mode == STREAM_UNBUFFERED) + { + if (lbs_fflush(stream) != 0) + { + return -1; + } + } + + stream->buffer[stream->buffered_size] = c; + stream->buffered_size++; + if (stream_unused_buffer_space(stream) == 0 + || stream->buffering_mode == STREAM_UNBUFFERED + || (stream->buffering_mode == STREAM_LINE_BUFFERED && c == '\n')) + { + if (lbs_fflush(stream) != 0) + { + return -1; + } + } + + return c; +} + +int refill_buffer(struct stream *stream) +{ + stream->already_read = 0; + ssize_t r; + if ((r = read(stream->fd, stream->buffer, LBS_BUFFER_SIZE)) == -1) + { + stream->error = 1; + return -1; + } + if (r == 0) + { + return -1; + } + stream->buffered_size = r; + return r; +} + +int lbs_fgetc(struct stream *stream) +{ + if (!stream_readable(stream)) + { + stream->error = 1; + return -1; + } + if (stream->io_operation == STREAM_WRITING) + { + if (lbs_fflush(stream) != 0) + { + stream->error = 1; + return -1; + } + stream->already_read = 0; + } + stream->io_operation = STREAM_READING; + + if (stream_remaining_buffered(stream) == 0) + { + int r; + if ((r = refill_buffer(stream)) == -1) + { + stream->error = 1; + return -1; + } + } + + int res = stream->buffer[stream->already_read++]; + + unsigned char c = res; + + return c; +} diff --git a/rushs/tinyprintf/tinylibstream/stdin_buffering_test.c b/rushs/tinyprintf/tinylibstream/stdin_buffering_test.c new file mode 100644 index 0000000..6d3361b --- /dev/null +++ b/rushs/tinyprintf/tinylibstream/stdin_buffering_test.c @@ -0,0 +1,70 @@ +#define _GNU_SOURCE +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +struct slow_cookie +{ + int fd; +}; + +static ssize_t slow_read(void *vcookie, char *buf, size_t count) +{ + struct slow_cookie *cookie = vcookie; + usleep(500000); // sleep for half of a second + + ssize_t res; + + while ((res = read(cookie->fd, buf, count)) < 0) + if (errno != EINTR && errno != EAGAIN) + break; + + return res; +} + +static int slow_close(void *vcookie) +{ + struct slow_cookie *cookie = vcookie; + return close(cookie->fd); +} + +cookie_io_functions_t slow_stdio = { + .read = slow_read, + .close = slow_close, +}; + +int main(void) +{ + /* setup a custom stdin stream with a slow read function */ + struct slow_cookie cookie = { + .fd = STDIN_FILENO, + }; + + FILE *input_stream = fopencookie(&cookie, "r", slow_stdio); + + /* change the buffer size to the one given by stdbuf. + ** it doesn't work out of the box as stdbuf only does + ** this for the already existing stdin stream. + */ + char *buffer = NULL; + char *buffer_size = getenv("_STDBUF_I"); + if (buffer_size) + { + size_t size = atoi(buffer_size); + buffer = malloc(size); + setvbuf(input_stream, buffer, _IOFBF, size); + } + + /* forward all characters from stdin to stdout */ + int c; + while ((c = fgetc(input_stream)) != EOF) + { + fputc(c, stdout); + fflush(stdout); + } + + fclose(input_stream); + free(buffer); + return 0; +} diff --git a/rushs/tinyprintf/tinylibstream/stdout_buffering_test.c b/rushs/tinyprintf/tinylibstream/stdout_buffering_test.c new file mode 100644 index 0000000..45c0a83 --- /dev/null +++ b/rushs/tinyprintf/tinylibstream/stdout_buffering_test.c @@ -0,0 +1,13 @@ +#define _XOPEN_SOURCE 500 +#include <stdio.h> +#include <unistd.h> + +int main(void) +{ + const char test_string[] = "Robin\nloves\nBatman\n"; + for (size_t i = 0; test_string[i]; i++) + { + usleep(100000); // wait a tenth of a second + putchar(test_string[i]); + } +} diff --git a/rushs/tinyprintf/tinyprintf/Makefile b/rushs/tinyprintf/tinyprintf/Makefile new file mode 100644 index 0000000..6a07d90 --- /dev/null +++ b/rushs/tinyprintf/tinyprintf/Makefile @@ -0,0 +1,17 @@ +CC=gcc +CFLAGS=-std=c99 -Wall -Wextra -Werror -Wvla -pedantic +LDLIBS=-lcriterion + +all: src/tinyprintf.o + +check: src/tinyprintf.o + $(CC) $(CFLAGS) -o tinytests src/tinyprintf.o tests/tests.c $(LDLIBS) + ./tinytests + +src/tinyprintf.o: src/tinyprintf.c + $(CC) $(CFLAGS) -c -o src/tinyprintf.o src/tinyprintf.c + +.PHONY: clean + +clean: + rm src/tinyprintf.o tinytests diff --git a/rushs/tinyprintf/tinyprintf/src/tinyprintf.c b/rushs/tinyprintf/tinyprintf/src/tinyprintf.c new file mode 100644 index 0000000..d005db7 --- /dev/null +++ b/rushs/tinyprintf/tinyprintf/src/tinyprintf.c @@ -0,0 +1,251 @@ +#include "tinyprintf.h" + +#include <stdio.h> +#include <stdlib.h> + +int tinyprintf(const char *format, ...) +{ + if (format == NULL || *format == '\0') + { + return 0; + } + + va_list ap; + va_start(ap, format); + int res = 0; + + size_t i = 0; + while (format[i]) + { + if (format[i] != '%') + { + putchar(format[i]); + res++; + } + else + { + dispatch(format[i + 1], ap, &res); + format++; + } + format++; + } + va_end(ap); + return res; +} + +void dispatch(char c, va_list ap, int *res) +{ + switch (c) + { + case '%': + putchar('%'); + (*res)++; + break; + case 'd': + handle_d(va_arg(ap, int), res); + break; + case 'u': + handle_u(va_arg(ap, unsigned int), res); + break; + case 'x': + handle_x(va_arg(ap, unsigned int), res); + break; + case 'o': + handle_o(va_arg(ap, unsigned int), res); + break; + case 'c': + putchar(va_arg(ap, int)); + (*res)++; + break; + case 's': + handle_s(va_arg(ap, char *), res); + break; + default: + putchar('%'); + putchar(c); + *res += 2; + break; + } +} + +void handle_d(int val, int *res) +{ + if (val < 0) + { + putchar('-'); + (*res)++; + val = -val; + } + + if (val == 0) + { + putchar('0'); + (*res)++; + } + + int t = val; + int n = 0; + while (t > 0) + { + t /= 10; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 10 + '0'; + val /= 10; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_s(char *s, int *res) +{ + if (s == NULL) + { + char *text = "(null)"; + for (; *text; text++) + { + putchar(*text); + (*res)++; + } + return; + } + for (; *s; s++) + { + putchar(*s); + (*res)++; + } +} + +void handle_u(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 10; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 10 + '0'; + val /= 10; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_x(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 16; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 16 + '0'; + if (s[n] > '9') + { + s[n] = (s[n] - '0') % 10 + 'a'; + } + val /= 16; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_o(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 8; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 8 + '0'; + val /= 8; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} diff --git a/rushs/tinyprintf/tinyprintf/src/tinyprintf.h b/rushs/tinyprintf/tinyprintf/src/tinyprintf.h new file mode 100644 index 0000000..fd1f0b4 --- /dev/null +++ b/rushs/tinyprintf/tinyprintf/src/tinyprintf.h @@ -0,0 +1,15 @@ +#ifndef TINYPRINTF_H +#define TINYPRINTF_H + +#include <stdarg.h> +#include <stddef.h> + +int tinyprintf(const char *format, ...); +void handle_d(int val, int *res); +void handle_u(unsigned int val, int *res); +void handle_x(unsigned int val, int *res); +void handle_o(unsigned int val, int *res); +void handle_s(char *s, int *res); +void dispatch(char c, va_list ap, int *res); + +#endif /* ! TINYPRINTF_H */ diff --git a/rushs/tinyprintf/tinyprintf/tests/tests.c b/rushs/tinyprintf/tinyprintf/tests/tests.c new file mode 100644 index 0000000..4235203 --- /dev/null +++ b/rushs/tinyprintf/tinyprintf/tests/tests.c @@ -0,0 +1,213 @@ +#include <criterion/criterion.h> +#include <criterion/assert.h> +#include <criterion/redirect.h> +#include <stdio.h> + +#include "../src/tinyprintf.h" + +TestSuite(TestHandleD); + +Test(TestHandleD, handle_d42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("42"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleD, handle_d0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleD, handle_dminus42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(-42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("-42"); + cr_expect(res == 3, "Expected: %d. Got: %d", 3, res); +} + +Test(TestHandleD, simple_print, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%d] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [42] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleX); + +Test(TestHandleX, handle_x42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("2a"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleX, handle_x0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleX, handle_x15, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(15, &res); + fflush(stdout); + cr_assert_stdout_eq_str("f"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleX, handle_0xdeadc0de, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(0xdeadc0de, &res); + fflush(stdout); + cr_assert_stdout_eq_str("deadc0de"); + cr_expect(res == 8, "Expected: %d. Got: %d", 8, res); +} + +Test(TestHandleX, simple_print_hexa, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%x] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [2a] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleU); + +Test(TestHandleU, handle_u42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("42"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleU, handle_u0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleU, handle_u15, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(15, &res); + fflush(stdout); + cr_assert_stdout_eq_str("15"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleU, simple_print_unsigned, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%u] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [42] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleO); + +Test(TestHandleO, handle_o42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("52"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleO, handle_o0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleO, handle_o7, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(7, &res); + fflush(stdout); + cr_assert_stdout_eq_str("7"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleO, simple_print_octal, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%o] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [52] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestPrint); + +Test(TestPrint, print_percent, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%%s", "in your head"); + fflush(stdout); + cr_assert_stdout_eq_str("%s"); + cr_expect(retval == 2, "Expected: %d. Got: %d", 2, retval); +} + +Test(TestPrint, print_unknown_option, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("Good morning ACU! %t Tinyprintf is cool", 12); + fflush(stdout); + cr_assert_stdout_eq_str("Good morning ACU! %t Tinyprintf is cool"); + cr_expect(retval == 39, "Expected: %d. Got: %d", 39, retval); +} + +Test(TestPrint, print_tricky, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%c%c is %s... %d too.", '4', '2', "the answer", '*'); + fflush(stdout); + cr_assert_stdout_eq_str("42 is the answer... 42 too."); + cr_expect(retval == 27, "Expected: %d. Got: %d", 27, retval); +} + +Test(TestPrint, print_null, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%c%c is %s... %d too.", '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str("42 is (null)... 42 too."); + cr_expect(retval == 23, "Expected: %d. Got: %d", 23, retval); +} + +Test(TestPrint, print_null_fmt, .init = cr_redirect_stdout) +{ + int retval = tinyprintf(NULL, '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str(""); + cr_expect(retval == 0, "Expected: %d. Got: %d", 0, retval); +} + +Test(TestPrint, print_empty_fmt, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("", '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str(""); + cr_expect(retval == 0, "Expected: %d. Got: %d", 0, retval); +} diff --git a/rushs/tinyprintf/traffic_lights/traffic_lights.c b/rushs/tinyprintf/traffic_lights/traffic_lights.c new file mode 100644 index 0000000..76ea94f --- /dev/null +++ b/rushs/tinyprintf/traffic_lights/traffic_lights.c @@ -0,0 +1,38 @@ +#include "traffic_lights.h" + +void init(unsigned char *lights) +{ + *lights <<= 4; +} + +void turn_on(unsigned char *lights, unsigned char light_num) +{ + *lights |= 1 << (light_num - 1); +} + +void turn_off(unsigned char *lights, unsigned char light_num) +{ + *lights &= ~(1 << (light_num - 1)); +} + +void next_step(unsigned char *lights) +{ + *lights <<= 1; + *lights += *lights >> 4; +} + +void reverse(unsigned char *lights) +{ + *lights = ~*lights; +} + +void swap(unsigned char *lights_1, unsigned char *lights_2) +{ + if (lights_1 == lights_2) + { + return; + } + *lights_1 = *lights_2 ^ *lights_1; + *lights_2 = *lights_1 ^ *lights_2; + *lights_1 = *lights_2 ^ *lights_1; +} diff --git a/rushs/tinyprintf/traffic_lights/traffic_lights.h b/rushs/tinyprintf/traffic_lights/traffic_lights.h new file mode 100644 index 0000000..7c803ea --- /dev/null +++ b/rushs/tinyprintf/traffic_lights/traffic_lights.h @@ -0,0 +1,11 @@ +#ifndef TRAFFIC_LIGHTS_H +#define TRAFFIC_LIGHTS_H + +void init(unsigned char *lights); +void turn_on(unsigned char *lights, unsigned char light_num); +void turn_off(unsigned char *lights, unsigned char light_num); +void next_step(unsigned char *lights); +void reverse(unsigned char *lights); +void swap(unsigned char *lights_1, unsigned char *lights_2); + +#endif /* !TRAFFIC_LIGHTS_H */ diff --git a/rushs/tinyprintf/user_ids/get_ids.sh b/rushs/tinyprintf/user_ids/get_ids.sh new file mode 100644 index 0000000..2a1668b --- /dev/null +++ b/rushs/tinyprintf/user_ids/get_ids.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cut --delimiter=: --fields=3 -s /etc/passwd | sort -rgu diff --git a/rushs/tinyprintf/using_special_variables/print.sh b/rushs/tinyprintf/using_special_variables/print.sh new file mode 100755 index 0000000..c24bebd --- /dev/null +++ b/rushs/tinyprintf/using_special_variables/print.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +echo $# +echo $* +echo $1 +echo $2 +echo $3 +echo ${13} +echo $0 diff --git a/rushs/tinyprintf/variant/variant.c b/rushs/tinyprintf/variant/variant.c new file mode 100644 index 0000000..eb2f8a8 --- /dev/null +++ b/rushs/tinyprintf/variant/variant.c @@ -0,0 +1,96 @@ +#include "variant.h" + +#include <stdio.h> +#include <string.h> + +void variant_display(const struct variant *e) +{ + switch (e->type) + { + case (TYPE_INT): + printf("%d\n", e->value.int_v); + break; + case (TYPE_FLOAT): + printf("%f\n", e->value.float_v); + break; + case (TYPE_CHAR): + printf("%c\n", e->value.char_v); + break; + default: + printf("%s\n", e->value.str_v); + break; + } +} + +bool variant_equal(const struct variant *left, const struct variant *right) +{ + if (left == NULL || right == NULL) + { + return true; + } + switch (left->type) + { + case (TYPE_INT): + if (right->type != TYPE_INT) + { + return false; + } + return left->value.int_v == right->value.int_v; + case (TYPE_FLOAT): + if (right->type != TYPE_FLOAT) + { + return false; + } + return left->value.float_v == right->value.float_v; + case (TYPE_CHAR): + if (right->type != TYPE_CHAR) + { + return false; + } + return left->value.char_v == right->value.char_v; + default: + if (right->type != TYPE_STRING) + { + return false; + } + return strcmp(left->value.str_v, right->value.str_v) == 0; + } +} + +int variant_find(const struct variant *array, size_t len, enum type type, + union type_any value) +{ + size_t i; + struct variant cmp = { type, value }; + for (i = 0; i < len && variant_equal(array + i, &cmp) == false; i++) + { + continue; + } + + if (i == len) + { + return -1; + } + return i; +} + +float variant_sum(const struct variant *array, size_t len) +{ + if (array == NULL) + { + return 0; + } + float sum = 0; + for (size_t i = 0; i < len; i++) + { + if (array[i].type == TYPE_FLOAT) + { + sum += array[i].value.float_v; + } + else if (array[i].type == TYPE_INT) + { + sum += array[i].value.int_v; + } + } + return sum; +} diff --git a/rushs/tinyprintf/variant/variant.h b/rushs/tinyprintf/variant/variant.h new file mode 100644 index 0000000..9983bc1 --- /dev/null +++ b/rushs/tinyprintf/variant/variant.h @@ -0,0 +1,35 @@ +#ifndef VARIANT_H +#define VARIANT_H + +#include <stdbool.h> +#include <stddef.h> + +enum type +{ + TYPE_INT, + TYPE_FLOAT, + TYPE_CHAR, + TYPE_STRING +}; + +union type_any +{ + int int_v; + float float_v; + char char_v; + const char *str_v; +}; + +struct variant +{ + enum type type; + union type_any value; +}; + +void variant_display(const struct variant *e); +bool variant_equal(const struct variant *left, const struct variant *right); +int variant_find(const struct variant *array, size_t len, enum type type, + union type_any value); +float variant_sum(const struct variant *array, size_t len); + +#endif /* !VARIANT_H */ diff --git a/rushs/tinyprintf/vector/Makefile b/rushs/tinyprintf/vector/Makefile new file mode 100644 index 0000000..744241f --- /dev/null +++ b/rushs/tinyprintf/vector/Makefile @@ -0,0 +1,13 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wvla -Wextra -std=c99 -pedantic + +.PHONY: library clean + +library: vector.o + ar csr libvector.a vector.o + +vector.o: vector.c + $(CC) $(CFLAGS) -c -o vector.o vector.c + +clean: + $(RM) libvector.a vector.o diff --git a/rushs/tinyprintf/vector/vector.c b/rushs/tinyprintf/vector/vector.c new file mode 100644 index 0000000..cbd19aa --- /dev/null +++ b/rushs/tinyprintf/vector/vector.c @@ -0,0 +1,152 @@ +#include "vector.h" + +#include <stdio.h> +#include <stdlib.h> + +struct vector *vector_init(size_t n) +{ + struct vector *res = malloc(sizeof(struct vector)); + if (res == NULL) + { + return NULL; + } + + res->size = 0; + res->capacity = n; + res->data = malloc(n * sizeof(int)); + if (res->data == NULL) + { + return NULL; + } + return res; +} + +void vector_destroy(struct vector *v) +{ + if (v) + { + free(v->data); + free(v); + } +} + +struct vector *vector_resize(struct vector *v, size_t n) +{ + if (!v) + { + return NULL; + } + if (n == v->capacity) + { + return v; + } + if (v) + { + int *tmp = realloc(v->data, n * sizeof(int)); + if (tmp == NULL) + { + return NULL; + } + v->data = tmp; + + if (n < v->size) + { + v->size = n; + } + v->capacity = n; + return v; + } + return NULL; +} + +struct vector *vector_append(struct vector *v, int elt) +{ + if (v == NULL) + { + return NULL; + } + + if (v->size == v->capacity) + { + if (vector_resize(v, v->capacity * 2) == NULL) + { + return NULL; + } + } + v->data[v->size] = elt; + v->size++; + return v; +} + +void vector_print(const struct vector *v) +{ + if (v == NULL || v->size == 0) + { + printf("\n"); + return; + } + for (size_t i = 0; i < v->size - 1; i++) + { + printf("%d,", v->data[i]); + } + printf("%d\n", v->data[v->size - 1]); +} + +struct vector *vector_reset(struct vector *v, size_t n) +{ + if (vector_resize(v, n) == NULL) + { + return NULL; + } + + v->size = 0; + return v; +} + +struct vector *vector_insert(struct vector *v, size_t i, int elt) +{ + if (v == NULL || i > v->size) + return NULL; + if (i == v->size) + { + return vector_append(v, elt); + } + if (v->size == v->capacity) + { + if (vector_resize(v, v->capacity * 2) == NULL) + { + return NULL; + } + } + for (size_t j = v->size; j > i; j--) + { + v->data[j] = v->data[j - 1]; + } + v->size++; + + v->data[i] = elt; + return v; +} + +struct vector *vector_remove(struct vector *v, size_t i) +{ + if (v == NULL || v->size == 0 || i >= v->size) + { + return NULL; + } + for (size_t j = i; j < v->size - 1; j++) + { + v->data[j] = v->data[j + 1]; + } + + v->size--; + + if (v->size < v->capacity / 2) + { + if (vector_resize(v, v->capacity / 2) == NULL) + { + return NULL; + } + } + return v; +} diff --git a/rushs/tinyprintf/vector/vector.h b/rushs/tinyprintf/vector/vector.h new file mode 100644 index 0000000..5afada7 --- /dev/null +++ b/rushs/tinyprintf/vector/vector.h @@ -0,0 +1,64 @@ +#ifndef VECTOR_H +#define VECTOR_H + +#include <stddef.h> + +struct vector +{ + // The number of elements in the vector + size_t size; + // The maximum number of elements in the vector + size_t capacity; + // The elements themselves + int *data; +}; + +/* +** Initialize the vector with `n` capacity. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_init(size_t n); + +/* +** Release the memory used by the vector. +** Does nothing if `v` is `NULL`. +*/ +void vector_destroy(struct vector *v); + +/* +** Resize the vector to `n` capacity. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_resize(struct vector *v, size_t n); + +/* +** Append an element to the end of the vector. Expand the vector if needed. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_append(struct vector *v, int elt); + +/* +** Display the vector contents on `stdout`. +** Displays `\n` if `v` is `NULL`. +*/ +void vector_print(const struct vector *v); + +/* +** Remove all the elements of the vector, and resize it to `n` capacity. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_reset(struct vector *v, size_t n); + +/* +** Insert `n` at the index `i`. Expand the vector if needed. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_insert(struct vector *v, size_t i, int elt); + +/* +** Remove the element at the index `i`. +** Returns `NULL` if an error occured. +*/ +struct vector *vector_remove(struct vector *v, size_t i); + +#endif /* !VECTOR_H */ |
