Compare commits

22 Commits

Author SHA1 Message Date
76510be028 convert from base to decimal 2025-11-14 09:10:55 +01:00
a1fec08cc4 int to varint works! 2025-11-13 14:08:54 +01:00
556cc85cde binary nightmares 2025-11-12 16:02:45 +01:00
2ebac1676f Update TOTP every 30 seconds 2025-11-05 00:03:16 +01:00
b6749bdb29 update every second 2025-11-03 16:17:23 +01:00
1b141173cc Delete stale compiled files 2025-11-03 15:09:58 +01:00
06174de597 trying to update progress bar 2025-11-03 14:55:19 +01:00
e6523e0a7b status bar changes 2025-11-03 12:48:43 +01:00
78da3c37c0 Empty status bar 2025-11-03 11:52:48 +01:00
3d305a0d70 Unified delay function 2025-11-03 08:45:46 +01:00
6166e930fe Copy text to clipboard 2025-11-03 08:21:28 +01:00
5edbfa4ce4 GUI 2025-11-03 07:23:43 +01:00
1071d9e5ee Create a simple GUI with seesaw 2025-10-13 01:53:45 +02:00
017291f784 Full modularized project 2025-10-13 01:22:03 +02:00
17a7a09ab0 Fully modularized project 2025-10-13 01:21:36 +02:00
3a6fd107c0 Generate a version if no one is provided 2025-10-12 12:34:48 +02:00
4c31950a88 Reestructured in subprojects 2025-10-12 12:28:40 +02:00
aa71cb1d76 Fix bug 2025-10-07 23:22:08 +02:00
c746675045 Force compression even if file exists 2025-10-07 23:20:24 +02:00
4052995ba8 Native compilation for Windows 2025-10-01 16:07:23 +02:00
44f48fced8 better native compile script 2025-10-01 15:49:23 +02:00
c78e89a94b Use example 2025-10-01 00:08:27 +02:00
54 changed files with 1607 additions and 106 deletions

2
.gitignore vendored
View File

@@ -1,5 +1,5 @@
/.clj-kondo/ /.clj-kondo/
/.cpcache/ /**/.cpcache/
/.lsp/ /.lsp/
/target/ /target/
.nrepl-port .nrepl-port

View File

@@ -17,6 +17,8 @@ You can read more about the algorithm here:
## How to use ## How to use
![Use example](use_example.gif)
First, you must have installed a Java Runtime Environment. Check https://adoptium.net/es if you are First, you must have installed a Java Runtime Environment. Check https://adoptium.net/es if you are
unsure how to install. unsure how to install.
@@ -145,11 +147,17 @@ clj-totp.sh import <alias> "<url>"
- [x] Show several OTPs at once - [x] Show several OTPs at once
### v1.2 ### v1.2
- [x] Show progress bar
- [x] Styles for progress bar
- [x] Native compilation script corrections
### v2
- [x] Restructurate as a multiproject
- [ ] REST API - [ ] REST API
- [ ] User management - [ ] User management
- [ ] Robust BD backend (H2, datomic, or similar) - [ ] Robust BD backend (H2, datomic, or similar)
### v1.3 ### v3
- [ ] Simple web connected to REST API - [ ] Simple web connected to REST API
@@ -169,14 +177,14 @@ The first step is to install Java JDK, version 11 or newer (version 21 recommend
To execute manually the main function, simple use the `:run` alias: To execute manually the main function, simple use the `:run` alias:
```clojure ```bash
clojure -M:run <commands and parameters> clojure -M:run/cli <commands and parameters>
``` ```
To build the uberjar: To build the uberjar:
```clojure ```bash
clojure -T:build uber clojure -T:build :uber/cli
``` ```
There is a utility script to build a native executable using Graal VM. Please, edit the script and There is a utility script to build a native executable using Graal VM. Please, edit the script and

191
build.clj
View File

@@ -1,37 +1,174 @@
(ns build (ns build
(:require [clojure.tools.build.api :as b])) (:refer-clojure :exclude [test])
(:require [clojure.tools.build.api :as b]
[clojure.java.io :as io]
[clojure.pprint :as pp]
[clojure.java.basis :as basis]))
(def lib 'es.rcorral/clj-totp) (def lib-group "es.rcorral")
(def version (format "1.2.%s" (b/git-count-revs nil))) (def artifact-prefix "clj-totp")
(def target-dir "target") (def subprojs-base "projects")
(def class-dir (str target-dir "/classes")) (def curr-version (format "2.0.%s" (b/git-count-revs nil)))
(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version))
;; delay to defer side effects (artifact downloads)
(def basis (delay (b/create-basis {:project "deps.edn"})))
(defn clean [_]
(b/delete {:path "target"}))
(defn compile-java [_]
(b/javac {:src-dirs ["java"]
:class-dir class-dir
:basis @basis
:javac-opts ["-source" "11" "--target" "11" "-proc:none"]}))
;; Builds artifact's full descriptor for each subproject
(defn lib [subproj]
(symbol (str lib-group "/" artifact-prefix "-" subproj )))
;; Basis for each subproject, using their own deps.edn
;; Injects :extra-deps from :build as additional dependencies
(defn basis [subproj]
(delay (b/create-basis {:project (str subprojs-base "/" subproj "/deps.edn")
;; Inject extra deps as deps
:extra {:deps (get-in (basis/initial-basis) [:aliases :build :extra-deps])}
})))
;; Show basis generated for a subproject
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]} #_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
(defn uber [_] (defn show-basis [subproj]
(clean nil) (println (with-out-str
(b/copy-dir {:src-dirs ["src"] (pp/pprint
@(basis subproj)
;(basis/initial-basis)
))))
(comment
(pp/pprint (keys (basis/initial-basis)))
(pp/pprint (:deps (basis/initial-basis)))
(pp/pprint (:libs (basis/initial-basis)))
(pp/pprint (sort (keys (:aliases (basis/initial-basis)))))
(get-in (basis/initial-basis) [:aliases :build :extra-deps])
)
;; Target dir for each subproject
(defn target-dir [subproj]
(str "target/" subproj))
;; Path for compiled classes
(defn class-dir [subproj]
(str (target-dir subproj) "/" "classes"))
;; Jar file for each subproject. :uber type adds -standalone suffix
(defn jar-file [subproj version type]
(format "target/%s-%s-%s%s.jar" artifact-prefix subproj version
(if (= type :uber) "-standalone" "")))
;; Clean target dir for subproject
(defn clean [{:keys [subproj]}]
(b/delete {:path (target-dir subproj)})
(println "Project" subproj "cleaned"))
;; Compile java classes, only if java subdir exists
(defn compile-java [subproj]
(let [java-dir (str subprojs-base "/" subproj "/java")]
(when (.exists (io/file java-dir))
(println "Compiling java code for" subproj)
(b/javac {:src-dirs [java-dir]
:class-dir (class-dir subproj)
:basis @(basis subproj)
:javac-opts ["-source" "11" "--target" "11" "-proc:none"]}))))
;; Create a jar file
(defn jar
"Build a simple jar file, with no dependencies included."
[{:keys [subproj version]
:or {version curr-version}}]
(let [target-dir (target-dir subproj)
class-dir (class-dir subproj)
src-dir (str subprojs-base "/" subproj "/src")
resources-dir (str subprojs-base "/" subproj "/resources")
basis (basis subproj)
jar-file (jar-file subproj version :plain)]
;; Clean only class dir
(b/delete {:path class-dir})
;; Copy code
(b/copy-dir {:src-dirs [src-dir]
:target-dir class-dir}) :target-dir class-dir})
(b/copy-file {:src "resources/clj-totp.sh" ;; Copy resources
:target "target/clj-totp.sh"}) (b/copy-dir {:src-dirs [resources-dir]
(compile-java nil) :target-dir target-dir})
;; Compile java code, if exists
(compile-java subproj)
;; Build jar
(b/jar {:class-dir class-dir
:basis @basis
:jar-file jar-file
:lib (lib subproj)
:version version})
(println "Generated jar file:" jar-file)))
;; Create an uber jar, with all dependencies inside
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
(defn uber
"Build a uberjar with all dependencies included"
[{:keys [subproj version main-ns]
:or {version curr-version}}]
(let [target-dir (target-dir subproj)
basis (basis subproj)
class-dir (class-dir subproj)
src-dir (str subprojs-base "/" subproj "/src")
resources-dir (str subprojs-base "/" subproj "/resources")
uber-file (jar-file subproj version :uber)]
;(println "Using basis: ")(show-basis subproj)
(b/delete {:path class-dir})
(b/copy-dir {:src-dirs [src-dir]
:target-dir class-dir})
(b/copy-dir {:src-dirs [resources-dir]
:target-dir target-dir})
(compile-java subproj)
(b/compile-clj {:basis @basis (b/compile-clj {:basis @basis
:ns-compile '[totp.app] :src-dirs [src-dir] :class-dir class-dir})
:class-dir class-dir})
(b/uber {:class-dir class-dir (b/uber {:class-dir class-dir
:uber-file uber-file :uber-file uber-file
:basis @basis :basis @basis
:main 'totp.app})) :main main-ns})
(println "Generated uberjar executable:" uber-file)))
;; Multimethod to get the name of all subdirs in a dir.
;; Accepts strings or files
(defmulti get-subdirs type)
(defmethod get-subdirs
java.lang.String [dir]
(get-subdirs (io/file dir)))
(defmethod get-subdirs
java.io.File [dir]
(if (.isDirectory dir)
(filter #(.isDirectory %) (.listFiles dir))
(println "Directory" subprojs-base "doesn't exists!")))
;; Get the name of all subdir in a given directory
(defn get-subdir-names
"Get a list projects in the 'projects' directory"
[dir-name]
(map #(.getName %) (get-subdirs dir-name)))
(comment
(get-subdirs "projects")
(get-subdirs (io/file "projects"))
(get-subdir-names "projects")
)
;; Generate jar files for all projects
(defn jar-all
"Build jar files for all projects"
[& {:keys [version]
:or {version curr-version}}]
(dorun (map #(jar {:subproj % :version version}) (get-subdir-names subprojs-base))))
(comment
(jar-all )
)

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="BuildSystem">
<option name="buildSystemId" value="CLOJURE_DEPS" />
<option name="displayName" value="clj-totp" />
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Deps: org.clojure/clojure:1.12.1" level="project" />
<orderEntry type="library" name="Deps: lambdaisland/deep-diff2:2.11.216" level="project" />
<orderEntry type="library" name="Deps: org.clojure/core.specs.alpha:0.4.74" level="project" />
<orderEntry type="library" name="Deps: lambdaisland/kaocha:1.91.1392" level="project" />
<orderEntry type="library" name="Deps: expound:0.9.0" level="project" />
<orderEntry type="library" name="Deps: org.clojure/spec.alpha:0.5.238" level="project" />
<orderEntry type="library" name="Deps: org.clojure/tools.cli:1.1.230" level="project" />
<orderEntry type="library" name="Deps: lambdaisland/clj-diff:1.4.78" level="project" />
<orderEntry type="library" name="Deps: net.incongru.watchservice/barbary-watchservice:1.0" level="project" />
<orderEntry type="library" name="Deps: slingshot:0.12.2" level="project" />
<orderEntry type="library" name="Deps: fipp:0.6.26" level="project" />
<orderEntry type="library" name="Deps: com.nextjournal/beholder:1.0.2" level="project" />
<orderEntry type="library" name="Deps: aero:1.1.6" level="project" />
<orderEntry type="library" name="Deps: lambdaisland/tools.namespace:0.3.256" level="project" />
<orderEntry type="library" name="Deps: mvxcvi/arrangement:2.1.0" level="project" />
<orderEntry type="library" name="Deps: io.methvin/directory-watcher:0.17.3" level="project" />
<orderEntry type="library" name="Deps: progrock:0.1.2" level="project" />
<orderEntry type="library" name="Deps: org.clojure/java.classpath:1.0.0" level="project" />
<orderEntry type="library" name="Deps: clojure.java-time:1.4.3" level="project" />
<orderEntry type="library" name="Deps: org.clojure/core.rrb-vector:0.1.2" level="project" />
<orderEntry type="library" name="Deps: net.java.dev.jna/jna:5.12.1" level="project" />
<orderEntry type="library" name="Deps: org.clojure/tools.reader:1.3.6" level="project" />
<orderEntry type="library" name="Deps: org.tcrawley/dynapath:1.1.0" level="project" />
<orderEntry type="library" name="Deps: org.slf4j/slf4j-api:1.7.36" level="project" />
<orderEntry type="library" name="Deps: hawk:0.2.11" level="project" />
<orderEntry type="library" name="Deps: meta-merge:1.0.0" level="project" />
</component>
</module>

View File

@@ -1,4 +1,4 @@
#!/bin/env sh #!/bin/env sh
protoc --java_out java/protoc/ resources/proto/otpauth-migration.proto protoc --java_out projects/core/java/protoc/ projects/core/resources/proto/otpauth-migration.proto
#javac -cp resources/protobuf-java-3.25.8.jar -d target/classes/proto src/OtpauthMigration.java #javac -cp resources/protobuf-java-3.25.8.jar -d target/classes/proto src/OtpauthMigration.java

View File

@@ -1,30 +1,68 @@
{:paths ["src" "resources" "target/classes"] {:paths ["src" "resources" "target/classes"]
:deps {org.clojure/clojure {:mvn/version "1.12.1"} :deps {org.clojure/clojure {:mvn/version "1.12.1"}
io.github.clojure/tools.build {:mvn/version "0.10.10"} ;; Native image (GraalVM). Tutorial: https://shagunagrawal.me/posts/setup-clojure-with-graalvm-for-native-image/
mvxcvi/alphabase {:mvn/version "3.0.185"} ;; https://github.com/greglook/alphabase com.github.clj-easy/graal-build-time {:mvn/version "1.0.5"}
cli-matic/cli-matic {:mvn/version "0.5.4"} ;; https://github.com/l3nz/cli-matic ;; Local subprojects
;; For SQLite clj-totp/core {:local/root "projects/core"}
com.github.seancorfield/next.jdbc {:mvn/version "1.3.1048"} clj-totp/cli {:local/root "projects/cli"}
org.xerial/sqlite-jdbc {:mvn/version "3.50.3.0"} clj-totp/web {:local/root "projects/web"}
;; For Datomic local clj-totp/gui {:local/root "projects/gui"}
com.datomic/local {:mvn/version "1.0.291"};; https://docs.datomic.com/datomic-local.html
;; Native image (GraalVM)
com.github.clj-easy/graal-build-time {:mvn/version "1.0.5"};; Tutorial: https://shagunagrawal.me/posts/setup-clojure-with-graalvm-for-native-image/
;; Protobuf for java
com.google.protobuf/protobuf-java {:mvn/version "3.25.8"}
;; Progress bar
com.github.pmonks/spinner {:mvn/version "2.0.284"}
} }
:aliases {;; Execute the app :aliases {;; Execute the app.
:run {:main-opts ["-m" "totp.app"]} :run {:main-opts ["-m" "totp.app"]}
;:run {:exec-fn totp.app/-main}
;; Execute the app (prepared for more subprojects)
:run/cli {:main-opts ["-m" "totp.app"]}
:run/gui {:main-opts ["-m" "totp.gui"]}
;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha ;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
:test {:extra-paths ["test"] ;; Check test.edn for kaocha runner's config
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}} :test {:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}
lambdaisland/kaocha-cloverage {:mvn/version "1.1.89"}}
:main-opts ["-m" "kaocha.runner"]} :main-opts ["-m" "kaocha.runner"]}
;; Run with clj -T:build function-in-build ;; Run with clj -T:build function-in-build
:build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}} :build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:ns-default build}}} ;; Used by all compilations
:extra-deps {clj-totp/core {:local/root "projects/core"}}
:ns-default build}
;; Aliases for easy building
:build/core {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:ns-default build
:exec-fn jar
:exec-args {:subproj "core"}}
:build/cli {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}
clj-totp/core {:local/root "projects/core"}}
:ns-default build
:exec-fn jar
:exec-args {:subproj "cli"}}
:build/web {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:replace-deps {clj-totp/core {:local/root "projects/core"}}
:ns-default build
:exec-fn jar
:exec-args {:subproj "web"}}
:build/gui {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:replace-deps {clj-totp/core {:local/root "projects/core"}}
:ns-default build
:exec-fn jar
:exec-args {:subproj "gui"}}
;; Build the three libraries
:build/all {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:replace-deps {clj-totp/core {:local/root "projects/core"}}
:ns-default build
:exec-fn jar-all}
;; Build uber jar for CLI app
:uber/cli {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:ns-default build
:exec-fn uber
:exec-args {:subproj "cli" :main-ns "totp.app"}}}}

View File

@@ -24,7 +24,7 @@ for /f "delims=" %%a in ('dir /b /s target\clj-totp-*-standalone.jar') do @set U
echo Created uberjar: %UBERJAR% echo Created uberjar: %UBERJAR%
echo "Creating native image" echo "Creating native image"
cmd /c %NATIVE% -jar %UBERJAR% -o target\%BIN_FILE% -H:+ReportExceptionStackTraces --features=clj_easy.graal_build_time.InitClojureClasses --report-unsupported-elements-at-runtime --verbose --no-fallback -H:ReflectionConfigurationFiles=reflect_config.json -H:-CheckToolchain cmd /c %NATIVE% -jar %UBERJAR% -o target\%BIN_FILE% -H:+ReportExceptionStackTraces --features=clj_easy.graal_build_time.InitClojureClasses --report-unsupported-elements-at-runtime --verbose --no-fallback -H:ReflectionConfigurationFiles=reflect_config.json -H:-CheckToolchain --initialize-at-build-time=org.fusesource.jansi.Ansi
echo Executable created: target\%BIN_FILE%.exe echo Executable created: target\%BIN_FILE%.exe

View File

@@ -14,9 +14,17 @@ $NATIVE -jar target/$UBERJAR -o target/$BIN_FILE\
--verbose --no-fallback\ --verbose --no-fallback\
--features=clj_easy.graal_build_time.InitClojureClasses\ --features=clj_easy.graal_build_time.InitClojureClasses\
--report-unsupported-elements-at-runtime\ --report-unsupported-elements-at-runtime\
--strict-image-heap\
-march=native\
-R:MaxHeapSize=10m\
--initialize-at-build-time=org.fusesource.jansi.Ansi\ --initialize-at-build-time=org.fusesource.jansi.Ansi\
#--trace-class-initialization=org.fusesource.jansi.Ansi --initialize-at-build-time='org.fusesource.jansi.Ansi$Color'\
--initialize-at-build-time='org.fusesource.jansi.Ansi$Attribute'\
'--initialize-at-build-time=org.fusesource.jansi.Ansi$1'
echo "Executable created on target/$BIN_FILE" echo "Executable created on target/$BIN_FILE"
cp target/$BIN_FILE ~/bin cp target/$BIN_FILE ~/bin
echo "Copied to ~/bin/$BIN_FILE" echo "Copied to ~/bin/$BIN_FILE"
echo "Compress executable for distribution"
xz -fv target/$BIN_FILE

15
projects/cli/deps.edn Executable file
View File

@@ -0,0 +1,15 @@
{:paths ["src" "resources" "target/classes"]
:deps {;clj-totp/core {:local/root "../core"}
org.clojure/clojure {:mvn/version "1.12.1"}
cli-matic/cli-matic {:mvn/version "0.5.4"} ;; https://github.com/l3nz/cli-matic
;; Progress bar
com.github.pmonks/spinner {:mvn/version "2.0.284"}}
:aliases {;; Execute the app
;:run {:main-opts ["-m" "totp.app"]}
;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
:test {:extra-paths ["test"]
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
:main-opts ["-m" "kaocha.runner"]}}}

1
projects/cli/tests.edn Normal file
View File

@@ -0,0 +1 @@
#kaocha/v1 {}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
-m
kaocha.runner

12
projects/core/deps.edn Executable file
View File

@@ -0,0 +1,12 @@
{:paths ["src" "resources" "target/classes"]
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
mvxcvi/alphabase {:mvn/version "3.0.185"} ;; https://github.com/greglook/alphabase
;; Protobuf for java
com.google.protobuf/protobuf-java {:mvn/version "3.25.8"}
}
:aliases {;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
:test {:extra-paths ["test"]
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
:main-opts ["-m" "kaocha.runner"]}}}

View File

@@ -99,3 +99,29 @@
(rem (int (m/pow 10 digits)))))))) (rem (int (m/pow 10 digits))))))))
([secret] ([secret]
(get-otp secret "sha1" 6 30))) (get-otp secret "sha1" 6 30)))
(defn calculate-offset-millis
[period]
(let [step-millis (* 1000 period)
now (System/currentTimeMillis)]
(int (rem now step-millis))))
(defn calculate-delay-millis
[period]
(let [step-millis (* 1000 period)]
(- step-millis (calculate-offset-millis period))))
(comment
(let [now (System/currentTimeMillis)
off (calculate-offset-millis 30)
delay (calculate-delay-millis 30)
]
(println "Now: " (int (/ now 1000)) "secs" now "millis")
(println "Offset:" (int (/ off 1000)) "secs" off "millis")
(println "Delay: " (int (/ delay 1000)) "secs" delay "millis")
(println "Total: " (+ (int (/ off 1000)) (int (/ delay 1000))) "secs" (+ delay off) "millis")
)
)

View File

@@ -89,11 +89,16 @@
(defn list-apps (defn list-apps
[cfg] [cfg]
(map :name (->> cfg
(filter #(contains? % :name) cfg))) (filter #(contains? % :name))
(map :name)))
(comment (comment
(list-apps (load-config))) (list-apps (load-config))
(with-config #_{:clj-kondo/ignore [:unresolved-symbol]}
(list-apps cfg))
)
(defn get-app (defn get-app
[cfg name] [cfg name]

View File

@@ -0,0 +1,186 @@
(ns totp.otp-import
(:require [alphabase.bytes :as b]
[alphabase.base16 :as hex]
[alphabase.base64 :as b64]
[alphabase.base2 :as b2]
[clojure.math :as m]
[clojure.string :as s]))
;; Original description of the export protocol uses Google's Protocol Buffers
;; https://protobuf.dev/
(comment
(let [encoded "CkkKEJ0M4MyHfITKCwCfqPIttjESFHJ1YmVuY2pAMThCMTY5RDVGRjAwGgRTTldMIAEoATACQhMzYjkxMDQxNzI3NzgzNDIzNDYyEAIYASAA"
decoded (b64/decode encoded)]
(print (hex/encode decoded))
(print (b/to-string decoded))
)
)
(defn len-bits
"How may blocks of n bits are needed to encode this number?
We use the following formula, for calculating the number of digits required
to encode the number n in the base b:
digits = ceil ( log_n ( x + 1 ) )
"
[x n]
(case x
nil 0 ;; nill is encoded with zero bytes
0 1 ;; One block to zero
9223372036854775807 (len-bits (dec x) n) ;; Beware the overflow!! it's best to lose some precision
(when (and (>= x 0) (some? n) (> n 0))
(int (m/ceil (/ (m/log (inc x)) (m/log (m/pow 2 n))))))))
(comment
(len-bits 513 8)
(len-bits Long/MAX_VALUE 8)
(len-bits (dec Long/MAX_VALUE) 8)
)
(defn len-bytes
"How may bytes are needed to encode this number?"
[x]
(len-bits x 8))
(defn integer>bytes
"Converts an integer to a byte array"
[x]
(when x (let [len (len-bytes x)
hex-len (* 2 len)]
(hex/decode (String/format (str "%0" hex-len "x") (into-array [x]))))))
(comment
(integer>bytes 513)
10r3
3r10
)
(defn decimal-to-base
"Converts a decimal number to an arbitrary base. Each digit is encoded as an
integer with value between 0 and base-1.
For example, 10 in base 4 will be encoded as:
[2 0 2]
, 127 in base 126 will be:
[1 1]
and so on.
We will use the sucessive division method: do a integer division of the number
to the base until the quotient is zero, and take the reminders backwards. For
example, if we want to converto 127 to base 5:
127 / 5 = 25 rem 2
25 / 5 = 5 rem 0
5 / 5 = 1 rem 0
1 / 5 = 0 rem 1
so, 127 in base 5 is 1002.
"
([n base]
(decimal-to-base n base true))
([n base reverse?]
(when (and n base)
(if (or (nil? n) (nil? base) (zero? n) (zero? base)) ;; Allways [0] for base zero or number zero
[0]
(loop [acc []
x n]
(if (zero? x)
(vec (if reverse? (reverse acc) acc)) ;; When x is zero, we have finished
(recur
(conj acc (rem x base)) ;; Accumulate the remainder
(quot x base)))))))) ;; Pass the quotient to the next step
(comment
(decimal-to-base 8 2)
2r1000
)
(defn base-to-decimal
"Converts from an array with values in an arbitrary base into decimal values"
[n base]
(if (or (nil? n) (nil? base) (zero? (count n)))
0
(int (reduce-kv
(fn [acc k v]
(+ acc (* v (m/pow base k))))
0 (vec (reverse n))))))
(comment
(reduce-kv #(+ %1 (* %3 (m/pow 2 %2))) 0 [1 0 0 0])
(reduce-kv
(fn [acc k v]
(+ acc (* v (m/pow 2 k))))
0 (vec (reverse [1 0 0 0])))
(base-to-decimal [1 0 0 0] 2)
)
(defn int->varint
"Converts a integer value to a varint, that is encoded in 7 bits, where the first
bit is used to indicate if there are more bytes.
For example, the number 255 is usually encoded in a byte as follows:
11111111
but in a varint it will turn to:
10000001 01111111
First byte has the MSB set to 1, because there is another byte after it. The
second byte is the last one, so the MSB is set to 0.
The result is a byte array.
"
[x]
(let [b128 (decimal-to-base x 128 false)]
(byte-array (conj
(vec (map #(bit-or 2r10000000 %) (butlast b128)))
(bit-and 2r01111111 (peek b128))))))
(defn to-fancy-bin
"Return a string with bits from number in a fancy manner"
[x]
(s/join " "
(map s/join
(partition 8 (b2/encode (byte-array (map #(b/to-byte %) x)))))))
(defn to-fancy-hex
"Return a string with hex values from number in a fancy manner"
([x]
(to-fancy-hex x 2))
([x group-size]
(s/join " "
(map s/join
(partition group-size (hex/encode (byte-array (map #(b/to-byte %) x))))))))
(comment
(hex/decode (String/format "%08x" (into-array [1023])))
(to-fancy-bin [150] )
(to-fancy-bin (int->varint 150))
(to-fancy-bin (int->varint 151))
(to-fancy-hex (int->varint 150))
(to-fancy-hex (int->varint 151) 4)
(to-fancy-bin (int->varint Long/MAX_VALUE))
(to-fancy-bin (int->varint (dec Long/MAX_VALUE)))
(to-fancy-hex (int->varint (dec Long/MAX_VALUE)))
(to-fancy-bin [2r10010110 2r00000001])
[2r10010110 2r00000001]
[2r0010110 2r0000001]
)

Binary file not shown.

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env sh
JAVA_EXECUTABLE=java
UBER_JAR=$(realpath clj-totp-*-standalone.jar)
OPTS="-Xms256m -Xmx256m -client -Dclojure.spec.skip-macros=true"
$JAVA_EXECUTABLE $OPTS -jar $UBER_JAR $@

View File

@@ -0,0 +1,83 @@
(ns totp.otp-import-test
#_{:clj-kondo/ignore [:refer-all]}
(:require [clojure.test :refer :all]
[totp.otp-import :refer :all]
[alphabase.bytes :as b]
[alphabase.base16 :as hex]
[alphabase.base64 :as b64]
[alphabase.base32 :as b32]))
(deftest len-bits-test
(testing "Check required number of blocks to encode a number in n bits"
(is (nil? (len-bits 10 nil)))
(is (= 0 (len-bits nil 10)))
(is (= 1 (len-bits 1 2)))
(is (= 2 (len-bits 10 2)))
(is (= 2 (len-bits 15 2)))
(is (= 3 (len-bits 16 2)))
(is (= 1 (len-bits 255 8)))
(is (= 2 (len-bits 255 7)))
)
)
(deftest len-bytes-test
(testing "Check required number of bytes to encode a number"
(is (= 0 (len-bytes nil)))
(is (= 1 (len-bytes 0)))
(is (= 1 (len-bytes 1)))
(is (= 1 (len-bytes 255)))
(is (= 2 (len-bytes 256)))
(is (= 2 (len-bytes 65535)))
(is (= 3 (len-bytes 65536)))
)
)
(deftest integer>bytes-test
(testing "Convert several ints to a byte array"
(is (nil? (integer>bytes nil)))
(is (b/bytes= (b/init-bytes [0]) (integer>bytes 0)))
(is (b/bytes= (b/init-bytes [1]) (integer>bytes 1)))
(is (b/bytes= (b/init-bytes [-1]) (integer>bytes 255)))
(is (b/bytes= (b/init-bytes [1 0]) (integer>bytes 256)))
(is (b/bytes= (b/init-bytes [-1 -1]) (integer>bytes 65535)))
(is (b/bytes= (b/init-bytes [127 -1 -1 -1 -1 -1 -1 -1]) (integer>bytes Long/MAX_VALUE)))
)
)
(deftest decimal-to-base-test
(testing "Convert from decimal base to an arbitrary base"
(is (= [0] (decimal-to-base 10 nil)))
(is (= [0] (decimal-to-base nil 10)))
(is (= [0] (decimal-to-base 0 2)))
(is (= [0] (decimal-to-base 2 0)))
(is (= [1 0 0 0] (decimal-to-base 8 2)))
(is (= [2 2] (decimal-to-base 8 3)))
(is (= [2 0] (decimal-to-base 8 4)))
(is (= [1 3] (decimal-to-base 8 5)))
(is (= [3 1] (decimal-to-base 8 5 false)))
(is (= [0] (decimal-to-base 0 5)))
)
)
(deftest base-to-decimal-test
(testing "Convert from arbitrary base to decimal"
(is (zero? (base-to-decimal nil 2)))
(is (zero? (base-to-decimal [] 2)))
(is (zero? (base-to-decimal [1] nil)))
(is (= 8 (base-to-decimal [1 0 0 0] 2)))
(is (= 8 (base-to-decimal [2 2] 3)))
(is (= 8 (base-to-decimal [2 0] 4)))
(is (= 8 (base-to-decimal [1 3] 5)))
)
)
(deftest decimal-base-decimal-test
(testing "Check if convert from decimal to a base and back preserves the original number"
(is (= 8 (base-to-decimal (decimal-to-base 8 2) 2)))
(is (= 127 (base-to-decimal (decimal-to-base 127 2) 2)))
(is (= 417 (base-to-decimal (decimal-to-base 417 13) 13)))
))

1
projects/core/tests.edn Normal file
View File

@@ -0,0 +1 @@
#kaocha/v1 {}

7
projects/gui/deps.edn Executable file
View File

@@ -0,0 +1,7 @@
{:paths ["src" "target/classes"]
:deps {;;org.clojure/clojure {:mvn/version "1.12.1"}
cli-matic/cli-matic {:mvn/version "0.5.4"} ;; https://github.com/l3nz/cli-matic
;; GUI
seesaw/seesaw {:mvn/version "1.5.0"}}
}

View File

@@ -0,0 +1,166 @@
(ns totp.gui
#_{:clj-kondo/ignore [:refer-all]}
(:require [totp.core :refer :all]
[totp.data :refer :all]
[clojure.pprint :as pp]
[seesaw.core :refer :all]
[seesaw.mig :refer :all]
[seesaw.clipboard :as cp]
[seesaw.dev :refer :all])
(:import [java.util Date TimerTask Timer]))
(defn content-test
[]
(let [choose (fn [e] (alert "I should open a file chooser"))]
(flow-panel
:items ["File" [:fill-h 5]
(text (System/getProperty "user.dir")) [:fill-h 5]
(action :handler choose :name "...")])))
(defn content-test2
[name category date comment]
(mig-panel
:constraints ["wrap 2"
"[shrink 0]20px[200, grow, fill]"
"[shrink 0]5px[]"]
:items [["name:"] [(text (or name ""))]
["category:"] [(text (or category ""))]
["date:"] [(text (or date ""))]
["comment:"] [(text (or comment ""))]]))
(defn copy-handler
"Copies TOTP from text with id field-id, to system clipboard"
[field-id e]
(let [b-name (str "#" field-id)
b-obj (select (to-root e) [(keyword b-name)])
b-text (config b-obj :text)]
(println "Copying text value: " b-text)
(cp/contents! b-text)
))
(defn make-otp-list
"Make panel with OTPs"
[]
(mig-panel
:constraints ["wrap 3"
"[shrink 0]20px[200, grow, fill]10px[shrink 0]"]
:items (let [apps (with-config (filter some? #_{:clj-kondo/ignore [:unresolved-symbol]} cfg))
]
(reduce (fn [acc a]
(let [{:keys [name secret algorithm digits period]} a
field-id (str "field-totp-" name)]
(-> acc
(conj [name])
(conj [(text :text (get-otp secret algorithm digits period)
:editable? false
:id field-id)])
(conj [(action :name "copy"
:handler (partial copy-handler field-id)
:command (str "cmd-" name))]))))
[] apps))))
(comment
(make-otp-list)
)
(defn make-time-bar
"Make the progress bar with the remaining time"
[init-val]
(border-panel
:hgap 5
:center (progress-bar :id "timer-bar"
:value init-val
:max 30)
:east (text :id "timer-text"
:text init-val
:editable? false
:columns 2
:halign :right)
))
(defn make-frame-content
[]
(border-panel :hgap 10 :vgap 10
:center (make-otp-list)
:north (make-time-bar (int(/ (calculate-offset-millis 30) 1000)))
;:south "SOUTH"
;:east "EAST"
;:west "WEST"
))
(defn make-frame
"Make main frame's content"
[]
(frame :title "TOTP",
:content (make-frame-content)
;:minimum-size [320 :by 240]
;;:on-close :exit
:on-close :dispose))
(defn update-totps
"Update all totps"
[root]
(let [apps (with-config (filter some? #_{:clj-kondo/ignore [:unresolved-symbol]} cfg))]
(doseq [app apps]
(let [{:keys [name secret algorithm digits period]} app
field-id (str "field-totp-" name)
field (select root [(keyword (str "#" field-id))])
current-otp (get-otp secret algorithm digits period)]
(println "Updating" field-id "with otp" current-otp)
(config! field :text current-otp)))))
(defn update-progress
[root]
(let [time-bar (select root [:#timer-bar])
time-text (select root [:#timer-text])
offset (inc (int (/ (calculate-offset-millis 30) 1000)))]
(println "Updating at at" (System/currentTimeMillis))
(config! time-bar :value offset)
(config! time-text :text offset)
(when (= 1 offset)
(println "update TOTP")
(update-totps root))
))
(defn start-updater
[root]
(let [now (System/currentTimeMillis)
now-seconds (int (/ now 1000))
delay (- 1000 (- now (* 1000 now-seconds)))]
(. (new Timer) (scheduleAtFixedRate
(proxy [TimerTask] []
(run [] (update-progress root)))
delay 1000))
(println "Now" now "Delay" delay)
))
(defn -main [& args]
(native!)
(invoke-later
(-> (make-frame)
pack!
show!
start-updater))
(println "Gui started"))
(comment
;; This kills your REPL connection
(-main)
(show-options (frame))
(show-options (text))
)

18
projects/web/deps.edn Executable file
View File

@@ -0,0 +1,18 @@
{:paths ["src" "resources" "target/classes"]
:deps {;clj-totp/core {:local/root "../core"}
org.clojure/clojure {:mvn/version "1.12.1"}
;; For SQLite
com.github.seancorfield/next.jdbc {:mvn/version "1.3.1048"}
org.xerial/sqlite-jdbc {:mvn/version "3.50.3.0"}
;; For Datomic local
com.datomic/local {:mvn/version "1.0.291"};; https://docs.datomic.com/datomic-local.html
}
:aliases {;; Execute the app
;:run {:main-opts ["-m" "totp.app"]}
;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
:test {:extra-paths ["test"]
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
:main-opts ["-m" "kaocha.runner"]}}}

1
projects/web/tests.edn Normal file
View File

@@ -0,0 +1 @@
#kaocha/v1 {}

View File

@@ -1 +1,6 @@
#kaocha/v1 {} #kaocha/v1
{:tests [{:test-paths ["projects/core/src" "projects/core/test"]}]
:plugins [:kaocha.plugin/cloverage]
:cloverage/opts {:src-ns-path ["projects/core/src" "projects/core/test"]
:ns-regex ["totp\\..*(?<!test)$"] ;; All starting with "totp" but not ending by "test"
}}

812
use_example.cast Normal file
View File

@@ -0,0 +1,812 @@
{"version": 2, "width": 130, "height": 40, "timestamp": 1759268913, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[0.176989, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:48 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[1.762001, "o", "#"]
[3.322002, "o", " "]
[4.343358, "o", "L"]
[5.091238, "o", "\b\u001b[K"]
[5.587452, "o", "S"]
[5.746296, "o", "h"]
[5.797527, "o", "o"]
[5.877536, "o", "w"]
[6.021713, "o", " "]
[6.138177, "o", "a"]
[6.262353, "o", "l"]
[6.439976, "o", "l"]
[6.559555, "o", " "]
[6.698153, "o", "o"]
[6.854063, "o", "p"]
[6.949519, "o", "t"]
[7.743221, "o", "i"]
[7.810171, "o", "o"]
[8.002195, "o", "n"]
[8.102527, "o", "s"]
[9.149834, "o", "\r\n\u001b[?2004l\r"]
[9.164586, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:48 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[13.250329, "o", "\u001b[7mtotp\u001b[27m"]
[14.043554, "o", "\r\u001b[C\u001b[Ctotp\r\n\u001b[?2004l\r"]
[14.056176, "o", "** ERROR: **\r\nNo sub-command specified.\r\n\r\n\r\n"]
[14.056426, "o", "NAME:\r\n totp - Generate a TOTP\r\n\r\nUSAGE:\r\n totp [global-options] command [command options] [arguments...]\r\n\r\nVERSION:\r\n 1.2\r\n\r\nCOMMANDS:\r\n generate Generate one TOTP for a BASE32 secret, ignoring configured apps\r\n get, g Generate one TOTP for a configured app\r\n config, c Manage configuration\r\n list, l List existing apps\r\n add, a Add a new application with an unique name\r\n import, i Import a TOTP config from a URL\r\n delete, d Removes an existing application by it's unique name\r\n\r\nGLOBAL OPTIONS:\r\n -?, --help\r\n\r\n"]
[14.075216, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:48 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;204;36;29m\u001b[0m "]
[17.138979, "o", "#"]
[17.583635, "o", " "]
[17.929988, "o", "g"]
[18.069244, "o", "e"]
[18.198196, "o", "n"]
[18.270251, "o", "e"]
[18.318014, "o", "r"]
[18.417589, "o", "a"]
[18.574066, "o", "t"]
[18.649313, "o", "e"]
[18.850539, "o", " "]
[19.006152, "o", "a"]
[19.126994, "o", " "]
[19.34653, "o", "s"]
[19.430616, "o", "i"]
[19.583429, "o", "m"]
[19.675425, "o", "p"]
[20.261871, "o", "l"]
[20.398368, "o", "e"]
[20.567488, "o", " "]
[20.886076, "o", "t"]
[21.001264, "o", "o"]
[21.125369, "o", "t"]
[21.241288, "o", "p"]
[22.32187, "o", "\r\n\u001b[?2004l\r"]
[22.336755, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:48 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;204;36;29m\u001b[0m "]
[34.302699, "o", "\u001b[7mtotp\u001b[27m"]
[35.866271, "o", "\r\u001b[C\u001b[C\u001b[1Ptot"]
[37.185679, "o", "t"]
[37.617081, "o", "\b\u001b[K"]
[37.989199, "o", "p"]
[38.081063, "o", " "]
[43.738456, "o", "\u001b[7mgenerate JBSWY3DPEHPK3PXP\u001b[27m"]
[44.621944, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cgenerate JBSWY3DPEHPK3PXP\r\n\u001b[?2004l\r"]
[44.635244, "o", "159410\r\n"]
[44.654801, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:49 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[47.843229, "o", "#"]
[48.209818, "o", " "]
[48.413046, "o", "n"]
[48.505043, "o", "i"]
[48.877725, "o", "c"]
[49.098866, "o", "e"]
[49.457645, "o", ","]
[49.516937, "o", " "]
[49.864976, "o", "l"]
[50.525075, "o", "\b\u001b[K"]
[50.945054, "o", "n"]
[51.000961, "o", "o"]
[51.133706, "o", "w"]
[51.465572, "o", ","]
[51.537081, "o", " "]
[53.649628, "o", "g"]
[53.816856, "o", "e"]
[53.921891, "o", "n"]
[53.969913, "o", "e"]
[54.630876, "o", "r"]
[54.725743, "o", "a"]
[54.861157, "o", "t"]
[54.932831, "o", "e"]
[55.074689, "o", " "]
[55.6697, "o", "*"]
[55.909582, "o", "a"]
[56.0267, "o", "n"]
[56.065065, "o", "d"]
[56.37366, "o", "*"]
[56.521083, "o", " "]
[56.734656, "o", "u"]
[56.921009, "o", "p"]
[57.025878, "o", "d"]
[57.105928, "o", "a"]
[57.221608, "o", "t"]
[57.29692, "o", "e"]
[58.005352, "o", "\r\n\u001b[?2004l\r"]
[58.020059, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:49 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[64.138603, "o", "\u001b[7mtotp generate -c JBSWY3DPEHPK3PXP\u001b[27m"]
[65.09814, "o", "\r\u001b[C\u001b[Ctotp generate -c JBSWY3DPEHPK3PXP\r\n\u001b[?2004l\r"]
[65.110699, "o", "\r\n <Generating continuosly, press enter to stop>\r\n\r\n"]
[65.111, "o", "Refresing in 21 seconds\r\n"]
[65.111575, "o", "\r\n[1759268978747] 908667\r\n\r\n"]
[65.112729, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 9/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[66.114963, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 10/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[67.117234, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 11/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[68.12148, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 12/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[69.125246, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 13/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[70.129928, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 14/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[70.141157, "o", "\r\n"]
[70.161973, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:49 \u001b[0m\u001b[38;2;60;56;54m \u001b[0mtook \u001b[1;33m5s\u001b[0m \r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[72.341232, "o", "#"]
[73.225094, "o", " "]
[76.03286, "o", "l"]
[76.176549, "o", "e"]
[76.540956, "o", "\b\u001b[K"]
[76.692529, "o", "\b\u001b[K"]
[77.10447, "o", "w"]
[77.220492, "o", "i"]
[77.384462, "o", " "]
[77.744525, "o", "\b\u001b[K"]
[77.912457, "o", "\b\u001b[K"]
[78.08847, "o", "\b\u001b[K"]
[80.10545, "o", "w"]
[80.201343, "o", "e"]
[80.376923, "o", " "]
[80.797294, "o", "w"]
[80.86962, "o", "i"]
[81.096974, "o", "l"]
[81.256371, "o", "l"]
[81.352347, "o", " "]
[81.740674, "o", "s"]
[81.992616, "o", "t"]
[82.12436, "o", "o"]
[82.240303, "o", "r"]
[82.297093, "o", "e"]
[82.421136, "o", " "]
[84.272464, "o", "t"]
[84.372248, "o", "h"]
[84.496211, "o", "i"]
[84.622221, "o", "s"]
[84.746303, "o", " "]
[84.921847, "o", "c"]
[84.9407, "o", "o"]
[85.02135, "o", "n"]
[85.105464, "o", "f"]
[85.216459, "o", "i"]
[85.301386, "o", "g"]
[85.432453, "o", "u"]
[85.602839, "o", "r"]
[85.950362, "o", "\b\u001b[K"]
[86.096569, "o", "\b\u001b[K"]
[86.252261, "o", "\b\u001b[K"]
[86.384954, "o", "\b\u001b[K"]
[86.504287, "o", "\b\u001b[K"]
[86.636345, "o", "\b\u001b[K"]
[86.768411, "o", "\b\u001b[K"]
[87.220431, "o", "\b\u001b[K"]
[87.448385, "o", "d"]
[87.562457, "o", "a"]
[87.684574, "o", "t"]
[87.776284, "o", "e"]
[88.772657, "o", "\b\u001b[K"]
[88.896276, "o", "a"]
[90.472592, "o", " "]
[90.652377, "o", "u"]
[90.776294, "o", "s"]
[90.920295, "o", "i"]
[91.084256, "o", "n"]
[91.184256, "o", "g"]
[91.292257, "o", " "]
[91.380229, "o", "l"]
[91.560883, "o", "o"]
[91.648839, "o", "c"]
[91.765128, "o", "a"]
[91.864932, "o", "l"]
[91.992656, "o", " "]
[92.120836, "o", "c"]
[92.160275, "o", "o"]
[92.236934, "o", "n"]
[92.317385, "o", "f"]
[92.405098, "o", "i"]
[92.509016, "o", "g"]
[92.572204, "o", "u"]
[92.689152, "o", "r"]
[92.773425, "o", "a"]
[92.896795, "o", "t"]
[92.960195, "o", "i"]
[93.016197, "o", "o"]
[93.056162, "o", "n"]
[93.684574, "o", "\r\n\u001b[?2004l\r"]
[93.699621, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:50 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[95.700291, "o", "#"]
[96.017982, "o", "f"]
[96.14066, "o", "i"]
[96.260872, "o", "r"]
[96.388124, "o", "s"]
[96.548141, "o", "t"]
[96.748096, "o", " "]
[97.684556, "o", "\b\u001b[K"]
[97.960221, "o", ","]
[98.068189, "o", " "]
[98.41609, "o", "w"]
[98.877924, "o", "\b\u001b[K"]
[100.213156, "o", "w"]
[100.341245, "o", "h"]
[100.430133, "o", "e"]
[100.536017, "o", "r"]
[100.635989, "o", "e"]
[100.793695, "o", " "]
[100.997081, "o", "i"]
[101.073151, "o", "s"]
[101.236518, "o", " "]
[101.372497, "o", "t"]
[101.472003, "o", "h"]
[101.551994, "o", "e"]
[101.684209, "o", " "]
[102.634076, "o", "c"]
[102.716541, "o", "o"]
[102.809801, "o", "n"]
[102.897178, "o", "f"]
[103.033125, "o", "i"]
[103.116694, "o", "g"]
[103.231916, "o", "u"]
[103.3456, "o", "r"]
[103.401105, "o", "a"]
[103.552214, "o", "t"]
[103.607996, "o", "i"]
[103.671962, "o", "o"]
[103.731929, "o", "n"]
[103.82512, "o", " "]
[103.968845, "o", "f"]
[104.065441, "o", "i"]
[104.245532, "o", "l"]
[104.308966, "o", "e"]
[104.592765, "o", "?"]
[104.949829, "o", "\r\n\u001b[?2004l\r"]
[104.966403, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:50 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[110.735684, "o", "\u001b[7mtotp config info\u001b[27m"]
[111.585646, "o", "\r\u001b[C\u001b[Ctotp config info\r\n\u001b[?2004l\r"]
[111.599116, "o", "Configuration file: not found. Expected location: /home/ruben/.config/totp/apps.edn\r\n"]
[111.61847, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:50 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[117.168242, "o", "n"]
[117.215739, "o", "o"]
[117.355702, "o", " "]
[117.733603, "o", "\b\u001b[K"]
[117.908862, "o", "\b\u001b[K"]
[118.077682, "o", "\b\u001b[K"]
[118.444922, "o", "#"]
[118.693748, "o", " "]
[118.885488, "o", "n"]
[118.944353, "o", "o"]
[119.044626, "o", " "]
[119.212729, "o", "f"]
[119.325414, "o", "o"]
[119.384939, "o", "n"]
[119.640383, "o", "g"]
[119.936985, "o", "\b\u001b[K"]
[120.072503, "o", "\b\u001b[K"]
[120.216486, "o", "\b\u001b[K"]
[120.36447, "o", "\b\u001b[K"]
[120.471851, "o", "c"]
[120.584431, "o", "o"]
[120.65574, "o", "n"]
[120.731969, "o", "f"]
[120.848454, "o", "i"]
[120.924386, "o", "g"]
[121.027572, "o", "u"]
[121.112001, "o", "r"]
[121.189835, "o", "a"]
[121.343833, "o", "t"]
[121.451598, "o", "i"]
[121.483569, "o", "o"]
[121.544645, "o", "n"]
[121.693602, "o", " "]
[121.79612, "o", "f"]
[122.761645, "o", "o"]
[122.901749, "o", "r"]
[123.145145, "o", " "]
[123.304789, "o", "n"]
[123.372733, "o", "o"]
[123.473625, "o", "w"]
[124.049661, "o", "\r\n\u001b[?2004l\r"]
[124.065701, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:50 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[130.128615, "o", "#"]
[130.692546, "o", " "]
[130.93938, "o", "l"]
[131.043615, "o", "e"]
[131.13983, "o", "s"]
[131.555945, "o", "\b\u001b[K"]
[131.663469, "o", "t"]
[131.723532, "o", "s"]
[131.843418, "o", " "]
[131.987492, "o", "a"]
[132.096224, "o", "d"]
[132.25656, "o", "d"]
[132.352497, "o", " "]
[132.572509, "o", "s"]
[132.692485, "o", "o"]
[132.796747, "o", "m"]
[132.92812, "o", "e"]
[133.040381, "o", " "]
[133.21634, "o", "c"]
[133.268543, "o", "o"]
[133.316484, "o", "n"]
[133.396408, "o", "f"]
[133.496, "o", "i"]
[133.584045, "o", "g"]
[134.036184, "o", "\r\n\u001b[?2004l\r"]
[134.051459, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:50 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[135.546399, "o", "\u001b[7mtotp add test JBSWY3DPEHPK3PXP\u001b[27m"]
[136.875925, "o", "\r\u001b[C\u001b[Ctotp add test JBSWY3DPEHPK3PXP\r\n\u001b[?2004l\r"]
[136.889149, "o", "Config not found. Creating new config\r\nCreating /home/ruben/.config/totp/apps.edn\r\n"]
[136.890105, "o", "App test not found\r\n"]
[136.893221, "o", "App test added or updated.\r\n"]
[136.912416, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:50 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[140.795747, "o", "t"]
[140.88717, "o", "o"]
[141.015232, "o", "t"]
[141.139247, "o", "p"]
[141.299209, "o", " "]
[141.447423, "o", "l"]
[141.540391, "o", "i"]
[141.563636, "o", "s"]
[141.647284, "o", "t"]
[142.235768, "o", "\r\n\u001b[?2004l\r"]
[142.248069, "o", "List mode: list\r\n"]
[142.248867, "o", "test\r\n"]
[142.267845, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:50 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[147.531311, "o", "#"]
[147.883753, "o", " "]
[148.339198, "o", "n"]
[148.407112, "o", "o"]
[148.519068, "o", "e"]
[148.56398, "o", "w"]
[149.175509, "o", "\b\u001b[K"]
[149.323071, "o", "\b\u001b[K"]
[149.431036, "o", "w"]
[149.739772, "o", ","]
[149.835045, "o", " "]
[150.267209, "o", "l"]
[150.395079, "o", "e"]
[150.467278, "o", "t"]
[150.719059, "o", "'"]
[150.931756, "o", "s"]
[151.184173, "o", " "]
[151.611112, "o", "u"]
[151.762964, "o", "s"]
[151.844066, "o", "e"]
[152.024966, "o", " "]
[152.295203, "o", "i"]
[152.347119, "o", "t"]
[153.263554, "o", "\r\n\u001b[?2004l\r"]
[153.278788, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:51 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[155.303403, "o", "t"]
[156.036697, "o", "\b\u001b[K"]
[161.713757, "o", "\u001b[7mtotp get test\u001b[27m"]
[164.459119, "o", "\r\u001b[C\u001b[Ctotp get test\r\n\u001b[?2004l\r"]
[164.47357, "o", "[1759269078109] test -> 538187\r\n"]
[164.494047, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:51 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[167.643612, "o", "n"]
[167.743908, "o", "i"]
[167.907667, "o", "c"]
[168.11663, "o", "e"]
[168.679846, "o", "\b\u001b[K"]
[168.835568, "o", "\b\u001b[K"]
[168.987573, "o", "\b\u001b[K"]
[169.134704, "o", "\b\u001b[K"]
[169.664678, "o", "#"]
[169.944556, "o", "n"]
[170.036654, "o", "i"]
[170.655785, "o", "c"]
[170.720607, "o", "c"]
[170.871841, "o", "e"]
[171.087914, "o", ","]
[171.176657, "o", " "]
[171.728478, "o", "\b\u001b[K"]
[171.880337, "o", "\b\u001b[K"]
[172.028366, "o", "\b\u001b[K"]
[172.163433, "o", "\b\u001b[K"]
[172.307877, "o", "e"]
[172.80039, "o", ","]
[172.875822, "o", " "]
[173.263396, "o", "b"]
[173.32745, "o", "u"]
[173.592525, "o", "t"]
[173.744595, "o", " "]
[175.150913, "o", "i"]
[175.275145, "o", "t"]
[175.370513, "o", " "]
[175.680036, "o", "c"]
[175.780515, "o", "a"]
[175.87158, "o", "n"]
[175.971182, "o", " "]
[176.163563, "o", "b"]
[176.404005, "o", "e"]
[176.496397, "o", " "]
[176.77961, "o", "b"]
[177.07975, "o", "e"]
[177.539027, "o", "t"]
[177.682551, "o", "t"]
[177.827595, "o", "e"]
[177.924439, "o", "r"]
[178.038649, "o", ","]
[178.132454, "o", " "]
[178.272441, "o", "l"]
[178.351211, "o", "e"]
[178.471602, "o", "s"]
[178.971113, "o", "\b\u001b[K"]
[179.0676, "o", "t"]
[179.123609, "o", "s"]
[179.247413, "o", " "]
[180.082803, "o", "u"]
[180.2324, "o", "p"]
[180.394597, "o", "d"]
[180.482853, "o", "a"]
[180.648252, "o", "t"]
[180.723541, "o", "e"]
[181.03104, "o", " "]
[182.038726, "o", "\b\u001b[K"]
[182.669551, "o", "\b\u001b[K"]
[182.708688, "o", "\b\u001b[K"]
[182.748425, "o", "\b\u001b[K"]
[182.788279, "o", "\b\u001b[K"]
[182.829023, "o", "\b\u001b[K"]
[182.868831, "o", "\b\u001b[K"]
[182.908891, "o", "\b\u001b[K"]
[182.948819, "o", "\b\u001b[K"]
[183.134335, "o", "\b\u001b[K"]
[183.31039, "o", "\b\u001b[K"]
[183.462279, "o", "\b\u001b[K"]
[183.626415, "o", "\b\u001b[K"]
[184.226378, "o", " "]
[184.548189, "o", "w"]
[184.64351, "o", "i"]
[184.842896, "o", "t"]
[184.95423, "o", "h"]
[185.182882, "o", " "]
[185.410352, "o", "a"]
[185.531177, "o", "u"]
[185.626453, "o", "t"]
[185.71036, "o", "o"]
[185.798217, "o", " "]
[185.939366, "o", "u"]
[186.087955, "o", "p"]
[186.264704, "o", "d"]
[186.311424, "o", "a"]
[186.483026, "o", "t"]
[186.555381, "o", "e"]
[186.888118, "o", "\r\n\u001b[?2004l\r"]
[186.904273, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:51 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[194.832903, "o", "\u001b[7mtotp get test -c -s ascii-basic\u001b[27m"]
[195.895065, "o", "\r\u001b[C\u001b[Ctotp get test -c -s ascii-basic\r\n\u001b[?2004l\r"]
[195.907922, "o", "\r\n <Generating continuosly, press enter to stop>\r\n\r\n"]
[195.908159, "o", "Refresing in 10 seconds\r\n\r\n\r\n"]
[195.908736, "o", "[1759269109544] test -> 993001\r\n\r\n"]
[195.910021, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m###################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 20/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[196.913521, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m#####################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 21/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[197.914821, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m#######################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 22/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[198.916125, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m########################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 23/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[199.917646, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m##########################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 24/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[200.918974, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m############################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 25/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[201.920305, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m##############################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 26/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[202.921624, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m###############################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 27/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[203.922865, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m#################################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 28/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[204.924224, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m###################################################\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 29/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[205.925493, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m####################################################\u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 30/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[206.365098, "o", "\r\n\r\n"]
[206.365278, "o", "[1759269120001] test -> 539013\r\n\r\n"]
[206.365606, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m##\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 1/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[206.910784, "o", "\r\u001b[K"]
[207.367214, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m####\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 2/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[208.368552, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m######\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 3/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[209.369936, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[39m[\u001b[m\u001b[m\u001b[49m\u001b[39m#######\u001b[m\u001b[m\u001b[49m\u001b[39m \u001b[m\u001b[m\u001b[49m\u001b[39m]\u001b[m\u001b[m\u001b[49m\u001b[39m 4/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[209.410133, "o", "\r\n"]
[209.430893, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:52 \u001b[0m\u001b[38;2;60;56;54m \u001b[0mtook \u001b[1;33m13s\u001b[0m \r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[210.699351, "o", "#"]
[211.038494, "o", " "]
[211.309807, "o", "s"]
[211.882298, "o", "\b\u001b[K"]
[211.949712, "o", "a"]
[211.99763, "o", "s"]
[212.105601, "o", " "]
[212.410208, "o", "y"]
[212.489736, "o", "o"]
[212.653977, "o", "u"]
[212.993745, "o", " "]
[213.370889, "o", "c"]
[213.470001, "o", "a"]
[213.53479, "o", "n"]
[213.663549, "o", " "]
[213.763578, "o", "s"]
[214.043568, "o", "e"]
[214.173681, "o", "e"]
[214.466255, "o", ","]
[214.549634, "o", " "]
[216.30996, "o", "t"]
[216.461652, "o", "e"]
[216.493704, "o", "h"]
[217.06972, "o", "\b\u001b[K"]
[217.205766, "o", "\b\u001b[K"]
[217.413748, "o", "h"]
[217.481597, "o", "e"]
[217.594439, "o", "r"]
[217.698256, "o", "e"]
[217.823511, "o", " "]
[217.934876, "o", "a"]
[218.234185, "o", "r"]
[218.325626, "o", "e"]
[218.521534, "o", " "]
[220.314138, "o", "s"]
[220.377731, "o", "o"]
[220.585578, "o", "m"]
[220.733803, "o", "e"]
[220.781393, "o", " "]
[221.510396, "o", "s"]
[221.665754, "o", "t"]
[221.857486, "o", "y"]
[222.083464, "o", "l"]
[222.206997, "o", "e"]
[222.262264, "o", "s"]
[222.330128, "o", " "]
[222.497639, "o", "f"]
[222.58273, "o", "o"]
[222.686721, "o", "r"]
[222.821483, "o", " "]
[222.913548, "o", "t"]
[223.033543, "o", "h"]
[223.149439, "o", "e"]
[223.20627, "o", " "]
[223.335623, "o", "p"]
[223.418267, "o", "r"]
[223.534662, "o", "o"]
[223.654181, "o", "g"]
[223.838228, "o", "r"]
[223.90657, "o", "e"]
[223.965747, "o", "s"]
[224.122669, "o", "s"]
[224.269633, "o", " "]
[224.434395, "o", "b"]
[224.574579, "o", "a"]
[224.64739, "o", "r"]
[225.626113, "o", "\r\n\u001b[?2004l\r"]
[225.641031, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:52 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[233.457421, "o", "#"]
[235.829555, "o", " "]
[236.685245, "o", "l"]
[238.381942, "o", "e"]
[238.613414, "o", "t"]
[239.501198, "o", "'"]
[239.585226, "o", "s"]
[239.701157, "o", " "]
[239.879208, "o", "d"]
[240.37912, "o", "e"]
[240.5226, "o", "l"]
[240.650743, "o", "e"]
[240.789392, "o", "t"]
[240.869225, "o", "e"]
[240.973015, "o", " "]
[241.305866, "o", "t"]
[241.416959, "o", "h"]
[241.577133, "o", "e"]
[241.69785, "o", " "]
[242.019033, "o", "c"]
[242.033506, "o", "o"]
[242.137762, "o", "n"]
[242.209209, "o", "f"]
[242.341133, "o", "i"]
[242.433165, "o", "g"]
[242.573055, "o", "u"]
[242.641041, "o", "r"]
[242.713105, "o", "a"]
[242.83762, "o", "t"]
[242.917079, "o", "i"]
[242.969032, "o", "o"]
[243.013048, "o", "n"]
[243.138504, "o", " "]
[243.473234, "o", "\""]
[243.685267, "o", "t"]
[243.760932, "o", "e"]
[243.869004, "o", "s"]
[243.973005, "o", "t"]
[244.373051, "o", "\""]
[244.654483, "o", "\r\n\u001b[?2004l\r"]
[244.669815, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:52 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[251.917944, "o", "\u001b[7mtotp delete test\u001b[27m"]
[252.989446, "o", "\r\u001b[C\u001b[Ctotp delete test\r\n\u001b[?2004l\r"]
[253.02292, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:52 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[255.301036, "o", "t"]
[255.504806, "o", "o"]
[255.65279, "o", "t"]
[255.800825, "o", "p"]
[257.001238, "o", " "]
[257.224701, "o", "l"]
[257.304734, "o", "i"]
[257.324649, "o", "s"]
[257.436758, "o", "t"]
[257.757304, "o", "\r\n\u001b[?2004l\r"]
[257.769018, "o", "List mode: list\r\n"]
[257.788948, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:52 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[258.944879, "o", "#"]
[259.517298, "o", " "]
[259.784678, "o", "n"]
[259.840851, "o", "o"]
[259.932589, "o", " "]
[260.278845, "o", "c"]
[260.3467, "o", "o"]
[260.425825, "o", "n"]
[260.493876, "o", "f"]
[260.598613, "o", "i"]
[260.677442, "o", "g"]
[260.768652, "o", "u"]
[260.880472, "o", "r"]
[260.953382, "o", "a"]
[261.060749, "o", "t"]
[261.112634, "o", "i"]
[261.180594, "o", "o"]
[261.204656, "o", "n"]
[261.348611, "o", "s"]
[261.554583, "o", " "]
[261.789793, "o", "s"]
[261.861763, "o", "o"]
[262.198226, "o", " "]
[262.341632, "o", "f"]
[262.492809, "o", "a"]
[262.593517, "o", "r"]
[263.625065, "o", "\r\n\u001b[?2004l\r"]
[263.640423, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:52 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[267.84483, "o", "w"]
[268.512968, "o", "\b\u001b[K"]
[268.896408, "o", "#"]
[269.113218, "o", " "]
[269.372569, "o", "w"]
[269.500297, "o", "e"]
[269.661237, "o", " "]
[269.854302, "o", "c"]
[269.989274, "o", "a"]
[270.078315, "o", "n"]
[270.152714, "o", " "]
[270.309658, "o", "i"]
[270.485438, "o", "m"]
[270.570015, "o", "p"]
[270.596809, "o", "o"]
[270.641587, "o", "r"]
[270.832613, "o", "t"]
[270.952398, "o", " "]
[271.408861, "o", "f"]
[271.621126, "o", "r"]
[271.696271, "o", "o"]
[271.752437, "o", "m"]
[271.85841, "o", " "]
[272.000574, "o", "a"]
[272.124981, "o", " "]
[272.305481, "o", "d"]
[272.938453, "o", "\b\u001b[K"]
[273.452832, "o", "d"]
[273.613687, "o", "e"]
[273.833281, "o", "c"]
[274.154276, "o", "o"]
[274.253164, "o", "d"]
[274.432922, "o", "e"]
[274.588231, "o", "d"]
[274.733447, "o", " "]
[274.981022, "o", "Q"]
[275.050288, "o", "R"]
[275.362007, "o", " "]
[277.496889, "o", "\r\n\u001b[?2004l\r"]
[277.512098, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:53 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[285.370066, "o", "\u001b[7mtotp import test2 \"otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example\"\u001b[27m"]
[287.308788, "o", "\r\u001b[C\u001b[Ctotp import test2 \"otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example\"\r\n\u001b[?2004l\r"]
[287.322431, "o", "App test2 not found\r\n"]
[287.326283, "o", "Import successful\r\n"]
[287.346185, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:53 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[288.769428, "o", "#"]
[289.141148, "o", " "]
[290.424621, "o", "b"]
[290.725468, "o", "e"]
[290.868228, "o", " "]
[291.173075, "o", "c"]
[291.297181, "o", "a"]
[291.426014, "o", "r"]
[291.548835, "o", "e"]
[291.900446, "o", "f"]
[292.025023, "o", "u"]
[292.278039, "o", "l"]
[292.432302, "o", "l"]
[292.548875, "o", " "]
[293.284385, "o", "\b\u001b[K"]
[293.531889, "o", ","]
[293.631761, "o", " "]
[294.360849, "o", "e"]
[295.140282, "o", "\b\u001b[K"]
[295.475851, "o", "u"]
[295.54373, "o", "s"]
[295.612843, "o", "e"]
[295.760867, "o", " "]
[297.521913, "o", "\""]
[298.656149, "o", " "]
[300.597656, "o", "w"]
[300.749634, "o", "h"]
[300.892144, "o", "e"]
[301.180181, "o", "n"]
[301.296973, "o", " "]
[302.500014, "o", "p"]
[302.615858, "o", "a"]
[302.67969, "o", "s"]
[302.849466, "o", "s"]
[302.961937, "o", "i"]
[303.101489, "o", "n"]
[303.180088, "o", "g"]
[303.35366, "o", " "]
[303.48116, "o", "a"]
[303.604602, "o", " "]
[303.816902, "o", "u"]
[303.976617, "o", "r"]
[304.101316, "o", "l"]
[307.059903, "o", "\r\n\u001b[?2004l\r"]
[307.075511, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:53 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[308.748767, "o", "w"]
[308.912618, "o", "e"]
[309.091714, "o", " "]
[309.255696, "o", "c"]
[309.36445, "o", "a"]
[309.464001, "o", "n"]
[309.528542, "o", " "]
[309.688527, "o", "u"]
[309.731301, "o", "s"]
[309.829634, "o", "e"]
[310.060886, "o", " "]
[310.572134, "o", "t"]
[310.651382, "o", "h"]
[310.755376, "o", "e"]
[310.873195, "o", " "]
[311.636149, "o", "i"]
[311.815418, "o", "m"]
[311.884555, "o", "p"]
[311.944949, "o", "o"]
[311.984584, "o", "r"]
[312.220074, "o", "t"]
[312.283313, "o", "e"]
[312.508213, "o", " "]
[312.600614, "o", "c"]
[312.953066, "o", "\b\u001b[K"]
[313.088559, "o", "\b\u001b[K"]
[313.281026, "o", "d"]
[313.459927, "o", " "]
[313.621497, "o", "c"]
[313.676178, "o", "o"]
[313.716444, "o", "n"]
[313.807705, "o", "f"]
[313.90908, "o", "i"]
[313.99701, "o", "g"]
[314.111396, "o", "u"]
[314.208486, "o", "r"]
[314.277257, "o", "a"]
[314.407495, "o", "t"]
[314.47123, "o", "i"]
[314.527248, "o", "o"]
[314.584277, "o", "n"]
[315.059961, "o", "\r\n\u001b[?2004l\r"]
[315.190478, "o", "we: no se encontró la orden\r\n"]
[315.214549, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:53 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;204;36;29m\u001b[0m "]
[315.32342, "o", "t"]
[315.379208, "o", "o"]
[315.556049, "o", "t"]
[315.631347, "o", "p"]
[315.823791, "o", " "]
[316.115847, "o", "l"]
[316.167385, "o", "i"]
[316.212386, "o", "s"]
[316.323384, "o", "t"]
[316.652722, "o", "\r\n\u001b[?2004l\r"]
[316.66479, "o", "List mode: list\r\n"]
[316.665415, "o", "test2\r\n"]
[316.684175, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:53 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[323.48764, "o", "\u001b[7mtotp get test2 -c\u001b[27m"]
[324.439742, "o", "\r\u001b[C\u001b[Ctotp get test2 -c\r\n\u001b[?2004l\r"]
[324.452596, "o", "\r\n <Generating continuosly, press enter to stop>\r\n\r\n"]
[324.452846, "o", "Refresing in 1 seconds\r\n\r\n\r\n"]
[324.453445, "o", "[1759269238089] test2 -> 957725\r\n\r\n"]
[324.454681, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉\u001b[m\u001b[m\u001b[49m\u001b[39m 29/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[325.456238, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[39m 30/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[326.364838, "o", "\r\n\r\n"]
[326.364948, "o", "[1759269240001] test2 -> 227087\r\n\r\n"]
[326.365295, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 1/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[326.45472, "o", "\r\u001b[K"]
[327.366772, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 2/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[328.368886, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 3/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[329.370693, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 4/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[330.372132, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 5/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[331.373589, "o", "\u001b[25l\r\u001b[49m\u001b[39mNext TOTP: \u001b[m\u001b[m\u001b[49m\u001b[97m▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[93m▉\u001b[m\u001b[m\u001b[49m\u001b[90m▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉\u001b[m\u001b[m\u001b[49m\u001b[39m 6/30\u001b[m\u001b[m\u001b[K\u001b[25h"]
[331.57506, "o", "\r\n"]
[331.594921, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:54 \u001b[0m\u001b[38;2;60;56;54m \u001b[0mtook \u001b[1;33m7s\u001b[0m \r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[332.515102, "o", "#"]
[333.135521, "o", " "]
[333.803007, "o", "h"]
[333.882813, "o", "a"]
[334.21893, "o", "v"]
[334.403614, "o", "e"]
[334.52687, "o", " "]
[334.871466, "o", "f"]
[334.951931, "o", "u"]
[335.148189, "o", "n"]
[335.488484, "o", "!"]
[336.103143, "o", "\r\n\u001b[?2004l\r"]
[336.118171, "o", "\u001b[?2004h\r\n\u001b[38;2;214;93;14m\u001b[48;2;214;93;14;38;2;251;241;199m󰕈 ruben\u001b[48;2;215;153;33;38;2;214;93;14m\u001b[38;2;251;241;199m …/clj-totp \u001b[48;2;104;157;106;38;2;215;153;33m\u001b[38;2;251;241;199m  main ? \u001b[48;2;69;133;136;38;2;104;157;106m\u001b[38;2;251;241;199m  v21.0.8 \u001b[48;2;102;92;84;38;2;69;133;136m\u001b[48;2;60;56;54;38;2;102;92;84m\u001b[38;2;251;241;199m  23:54 \u001b[0m\u001b[38;2;60;56;54m \u001b[0m\r\n\u001b[1;38;2;152;151;26m\u001b[0m "]
[336.90336, "o", "\u001b[?2004l\r\r\nexit\r\n"]

BIN
use_example.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB