├── .github └── workflows │ ├── build-demo.yml │ └── deploy-clojars.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.clj ├── deps.edn ├── dev.md ├── docs ├── blog.css ├── bootstrap.min.css ├── index.html └── js │ ├── main.js │ └── manifest.edn ├── inspector-resize.gif ├── inspector.gif ├── navigation.gif ├── package-lock.json ├── package.json ├── paging.gif ├── pom.xml ├── public ├── blog.css ├── bootstrap.min.css └── index.html ├── resources └── .keep ├── shadow-cljs.edn ├── src └── com │ └── phronemophobic │ ├── viscous.cljc │ └── viscous │ ├── cli.clj │ └── demo.cljs └── test └── com └── phronemophobic └── membrane └── pretty_view_test.clj /.github/workflows/build-demo.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy Web Demo 2 | on: 3 | push: 4 | jobs: 5 | build: 6 | 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Prepare java 11 | uses: actions/setup-java@v3.5.1 12 | with: 13 | distribution: 'zulu' 14 | java-version: '11' 15 | 16 | - uses: actions/checkout@v3.1.0 17 | - name: Setup Node 18 | uses: actions/setup-node@v3.5.0 19 | with: 20 | node-version: '17.4.0' 21 | 22 | - name: Install node dependencies 23 | run: npm install 24 | 25 | - name: Setup Clojure 26 | # You may pin to the exact commit or the version. 27 | # uses: DeLaGuardo/setup-clojure@5042876523f30f5efcf1d6feaa48bd1498d7814f 28 | uses: DeLaGuardo/setup-clojure@9.5 29 | with: 30 | # Clojure CLI version to make available on the path. 31 | cli: 1.10.3.1058 32 | 33 | - name: Install dependencies 34 | run: clojure -P 35 | - name: Build static 36 | run: clojure -M:shadow-cljs:cljs release app 37 | - name: Deploy 🚀 38 | uses: JamesIves/github-pages-deploy-action@v4.4.0 39 | with: 40 | branch: gh-pages # The branch the action should deploy to. 41 | folder: public # The folder the action should deploy. 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/deploy-clojars.yml: -------------------------------------------------------------------------------- 1 | name: Clojars deploy 2 | on: 3 | workflow_dispatch: 4 | jobs: 5 | build: 6 | 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Prepare java 11 | uses: actions/setup-java@v3.5.1 12 | with: 13 | distribution: 'zulu' 14 | java-version: '11' 15 | 16 | - uses: actions/checkout@v3.1.0 17 | - name: Setup Clojure 18 | # You may pin to the exact commit or the version. 19 | # uses: DeLaGuardo/setup-clojure@5042876523f30f5efcf1d6feaa48bd1498d7814f 20 | uses: DeLaGuardo/setup-clojure@9.5 21 | with: 22 | # Clojure CLI version to make available on the path. 23 | cli: 1.11.0.1100 24 | 25 | - name: Install dependencies 26 | run: clojure -P 27 | 28 | - name: Deploy 29 | env: 30 | CLOJARS_USERNAME: ${{ secrets.CLOJARS_USERNAME }} 31 | CLOJARS_PASSWORD: ${{ secrets.CLOJARS_PASSWORD }} 32 | run: clojure -T:build deploy 33 | 34 | 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | *.jar 5 | *.class 6 | /.calva/output-window/ 7 | /.cpcache 8 | /.lein-* 9 | /.lsp/sqlite*.db 10 | /.nrepl-history 11 | /.nrepl-port 12 | /.rebel_readline_history 13 | /.socket-repl-port 14 | .hgignore 15 | .hg/ 16 | out 17 | node_modules 18 | .shadow-cljs 19 | public/js -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## [Unreleased] 5 | ### Changed 6 | - Add a new arity to `make-widget-async` to provide a different widget shape. 7 | 8 | ## [0.1.1] - 2021-04-20 9 | ### Changed 10 | - Documentation on how to make the widgets. 11 | 12 | ### Removed 13 | - `make-widget-sync` - we're all async, all the time. 14 | 15 | ### Fixed 16 | - Fixed widget maker to keep working when daylight savings switches over. 17 | 18 | ## 0.1.0 - 2021-04-20 19 | ### Added 20 | - Files from the new template. 21 | - Widget maker public API - `make-widget-sync`. 22 | 23 | [Unreleased]: https://github.com/com.phronemophobic.membrane/pretty-view/compare/0.1.1...HEAD 24 | [0.1.1]: https://github.com/com.phronemophobic.membrane/pretty-view/compare/0.1.0...0.1.1 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor to control, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Viscous 2 | 3 | A visual data inspector/explorer that runs in constant space, time, and screen space. 4 | 5 | Built with [membrane](https://github.com/phronmophobic/membrane). 6 | 7 | ### Overview 8 | 9 | ![Overview](inspector.gif?raw=true) 10 | 11 | ### Resizing 12 | ![Resizing](inspector-resize.gif?raw=true) 13 | 14 | ### Paging 15 | ![Paging](paging.gif?raw=true) 16 | 17 | ### Navigating 18 | ![Navigating](navigation.gif?raw=true) 19 | 20 | ## Web Demo 21 | 22 | Try it! https://phronmophobic.github.io/viscous/ 23 | 24 | ## Dependency 25 | 26 | #### deps.edn 27 | ```clojure 28 | com.phronemophobic/viscous {:mvn/version "1.3.5"} 29 | ``` 30 | 31 | #### lein 32 | ```clojure 33 | [com.phronemophobic/viscous "1.3.5"] 34 | ``` 35 | 36 | ## Programmatic Usage 37 | 38 | ```clojure 39 | (require '[com.phronemophobic.viscous :as viscous]) 40 | 41 | (def my-data {:a {:b 42}}) 42 | 43 | ;; open inspector window 44 | (viscous/inspect my-data) 45 | 46 | ``` 47 | 48 | ## Cli usage 49 | 50 | Create an alias for viscous 51 | 52 | ```clojure 53 | 54 | { 55 | :aliases { 56 | ``` 57 | ```clojure 58 | :viscous 59 | {:replace-deps {com.phronemophobic/viscous {:mvn/version "1.3.5"} 60 | org.clojure/data.json {:mvn/version "2.4.0"}} 61 | :exec-fn com.phronemophobic.viscous.cli/main} 62 | ``` 63 | ```clojure 64 | } 65 | } 66 | ``` 67 | 68 | Read edn from stdin: 69 | ```sh 70 | cat data.edn | clojure -X:viscous :file - 71 | ``` 72 | 73 | Read edn from filename: 74 | ```sh 75 | clojure -X:viscous :file '"data.edn"' 76 | ``` 77 | 78 | Read json from stdin: 79 | ```sh 80 | cat data.json | clojure -X:viscous :json-file - 81 | ``` 82 | 83 | Read json from filename: 84 | ```sh 85 | clojure -X:viscous :json-file '"data.edn"' 86 | ``` 87 | 88 | ## Status 89 | 90 | Viscous is in beta. Behavior is subject to change. Feedback is welcome. 91 | 92 | ## Related 93 | 94 | I'm generally interested in finding better ways to represent and explore medium sized heterogenous data. If you like viscous, you may also be interested in [treemap-clj](https://github.com/phronmophobic/treemap-clj). 95 | 96 | ## License 97 | 98 | Copyright © 2025 Adrian Smith 99 | 100 | Distributed under the Eclipse Public License version 1.0. 101 | -------------------------------------------------------------------------------- /build.clj: -------------------------------------------------------------------------------- 1 | (ns build 2 | (:require [clojure.tools.build.api :as b] 3 | [clojure.string :as str])) 4 | 5 | (def lib 'com.phronemophobic/viscous) 6 | (def version "1.3.5") 7 | (def class-dir "target/classes") 8 | (def basis (b/create-basis {:project "deps.edn"})) 9 | (def jar-file (format "target/%s-%s.jar" (name lib) version)) 10 | 11 | (defn clean [_] 12 | (b/delete {:path "target"})) 13 | 14 | (defn jar [_] 15 | (b/write-pom {:class-dir class-dir 16 | :lib lib 17 | :version version 18 | :basis basis 19 | :src-dirs ["src"]}) 20 | (b/copy-dir {:src-dirs ["src" "resources"] 21 | :target-dir class-dir}) 22 | (b/jar {:class-dir class-dir 23 | :jar-file jar-file})) 24 | 25 | (defn deploy [opts] 26 | (jar opts) 27 | (try ((requiring-resolve 'deps-deploy.deps-deploy/deploy) 28 | (merge {:installer :remote 29 | :artifact jar-file 30 | :pom-file (b/pom-path {:lib lib :class-dir class-dir})} 31 | opts)) 32 | (catch Exception e 33 | (if-not (str/includes? (ex-message e) "redeploying non-snapshots is not allowed") 34 | (throw e) 35 | (println "This release was already deployed.")))) 36 | opts) 37 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"] 2 | :deps {org.clojure/clojure {:mvn/version "1.10.3"} 3 | com.phronemophobic/membrane {:mvn/version "0.14.1-beta" 4 | ;; :local/root "../membrane" 5 | }} 6 | :aliases 7 | {:test {:extra-paths ["test"] 8 | :extra-deps {org.clojure/test.check {:mvn/version "1.1.0"}}} 9 | 10 | 11 | :viscous {:exec-fn com.phronemophobic.viscous.cli/main 12 | :extra-deps {org.clojure/data.json {:mvn/version "2.4.0"}}} 13 | 14 | :cljs 15 | {:extra-deps {thheller/shadow-cljs {:mvn/version "2.20.3"}}} 16 | 17 | :build {:deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"} 18 | slipset/deps-deploy {:mvn/version "RELEASE"}} 19 | :ns-default build} 20 | 21 | :shadow-cljs 22 | {:extra-deps {thheller/shadow-cljs {:mvn/version "2.20.3"}} 23 | :main-opts ["-m" "shadow.cljs.devtools.cli"]} 24 | 25 | :project 26 | {:extra-deps {org.clojure/data.json {:mvn/version "2.4.0"} 27 | org.clojure/test.check {:mvn/version "0.9.0"} 28 | com.phronemophobic.membrane/skialib-macosx-aarch64 29 | {:mvn/version "RELEASE" 30 | ;; :local/root "csource/macos-aarch64" 31 | }}} 32 | 33 | :tagsoup 34 | {:extra-deps { 35 | org.clojure/data.xml {:mvn/version "0.0.8"} 36 | clj-tagsoup/clj-tagsoup {:mvn/version "0.3.0" 37 | :exclusions [org.clojure/data.xml]} 38 | }} 39 | 40 | :runner 41 | {:extra-deps {com.cognitect/test-runner 42 | {:git/url "https://github.com/cognitect-labs/test-runner" 43 | :sha "b6b3193fcc42659d7e46ecd1884a228993441182"}} 44 | :main-opts ["-m" "cognitect.test-runner" 45 | "-d" "test"]} 46 | :jar {:replace-deps {com.github.seancorfield/depstar {:mvn/version "2.0.211"}} 47 | :exec-fn hf.depstar/jar 48 | :exec-args {:jar "viscous.jar" :sync-pom true}} 49 | :install {:replace-deps {slipset/deps-deploy {:mvn/version "0.1.5"}} 50 | :exec-fn deps-deploy.deps-deploy/deploy 51 | :exec-args {:installer :local :artifact "viscous.jar"}} 52 | :deploy {:replace-deps {slipset/deps-deploy {:mvn/version "0.1.5"}} 53 | :exec-fn deps-deploy.deps-deploy/deploy 54 | :exec-args {:installer :remote :artifact "viscous.jar"}}}} 55 | -------------------------------------------------------------------------------- /dev.md: -------------------------------------------------------------------------------- 1 | ## Dev notes 2 | 3 | To update web demo, run the following from the root dir: 4 | 5 | ```sh 6 | # clean first 7 | rm -rf .shadow-cljs/builds/ 8 | clojure -M:shadow-cljs release app 9 | ``` 10 | 11 | This will write the js file to `public/js/main.js`. 12 | 13 | ```sh 14 | cp public/js/main.js docs/js/main.js 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /docs/blog.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Globals 3 | */ 4 | 5 | @media (min-width: 48em) { 6 | html { 7 | font-size: 18px; 8 | } 9 | } 10 | 11 | /* body { */ 12 | /* font-family: Georgia, "Times New Roman", Times, serif; */ 13 | /* color: #555; */ 14 | /* } */ 15 | 16 | /* h1, .h1, */ 17 | /* h2, .h2, */ 18 | /* h3, .h3, */ 19 | /* h4, .h4, */ 20 | /* h5, .h5, */ 21 | /* h6, .h6 { */ 22 | /* font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; */ 23 | /* font-weight: normal; */ 24 | /* color: #333; */ 25 | /* } */ 26 | 27 | 28 | /* 29 | * Override Bootstrap's default container. 30 | */ 31 | 32 | .container { 33 | max-width: 60rem; 34 | } 35 | 36 | 37 | /* 38 | * Masthead for nav 39 | */ 40 | 41 | .blog-masthead { 42 | margin-bottom: 3rem; 43 | background-color: #428bca; 44 | -webkit-box-shadow: inset 0 -.1rem .25rem rgba(0,0,0,.1); 45 | box-shadow: inset 0 -.1rem .25rem rgba(0,0,0,.1); 46 | } 47 | 48 | /* Nav links */ 49 | .nav-link { 50 | position: relative; 51 | padding: 1rem; 52 | font-weight: 500; 53 | color: #cdddeb; 54 | } 55 | .nav-link:hover, 56 | .nav-link:focus { 57 | color: #fff; 58 | background-color: transparent; 59 | } 60 | 61 | /* Active state gets a caret at the bottom */ 62 | .nav-link.active { 63 | color: #fff; 64 | } 65 | .nav-link.active:after { 66 | position: absolute; 67 | bottom: 0; 68 | left: 50%; 69 | width: 0; 70 | height: 0; 71 | margin-left: -.3rem; 72 | vertical-align: middle; 73 | content: ""; 74 | border-right: .3rem solid transparent; 75 | border-bottom: .3rem solid; 76 | border-left: .3rem solid transparent; 77 | } 78 | 79 | 80 | /* 81 | * Blog name and description 82 | */ 83 | 84 | .blog-header { 85 | padding-bottom: 1.25rem; 86 | margin-bottom: 2rem; 87 | border-bottom: .05rem solid #eee; 88 | } 89 | .blog-title { 90 | margin-bottom: 0; 91 | font-size: 2rem; 92 | font-weight: normal; 93 | } 94 | .blog-description { 95 | font-size: 1.1rem; 96 | color: #999; 97 | } 98 | 99 | @media (min-width: 40em) { 100 | .blog-title { 101 | font-size: 3.5rem; 102 | } 103 | } 104 | 105 | 106 | /* 107 | * Main column and sidebar layout 108 | */ 109 | 110 | /* Sidebar modules for boxing content */ 111 | .sidebar-module { 112 | padding: 1rem; 113 | /*margin: 0 -1rem 1rem;*/ 114 | } 115 | .sidebar-module-inset { 116 | padding: 1rem; 117 | background-color: #f5f5f5; 118 | border-radius: .25rem; 119 | } 120 | .sidebar-module-inset p:last-child, 121 | .sidebar-module-inset ul:last-child, 122 | .sidebar-module-inset ol:last-child { 123 | margin-bottom: 0; 124 | } 125 | 126 | 127 | /* Pagination */ 128 | .blog-pagination { 129 | margin-bottom: 4rem; 130 | } 131 | .blog-pagination > .btn { 132 | border-radius: 2rem; 133 | } 134 | 135 | 136 | /* 137 | * Blog posts 138 | */ 139 | 140 | .blog-post { 141 | margin-bottom: 4rem; 142 | } 143 | .blog-post-title { 144 | margin-bottom: .25rem; 145 | font-size: 2.5rem; 146 | } 147 | .blog-post-meta { 148 | margin-bottom: 1.25rem; 149 | color: #999; 150 | } 151 | 152 | 153 | /* 154 | * Footer 155 | */ 156 | 157 | .blog-footer { 158 | padding: 2.5rem 0; 159 | color: #999; 160 | text-align: center; 161 | background-color: #f9f9f9; 162 | border-top: .05rem solid #e5e5e5; 163 | } 164 | .blog-footer p:last-child { 165 | margin-bottom: 0; 166 | } 167 | 168 | 169 | blockquote { 170 | /* background: #f9f9f9; */ 171 | border-left: 10px solid #ccc; 172 | margin: 1.5em 10px; 173 | padding: 0.5em 10px; 174 | /* quotes: "\201C""\201D""\2018""\2019"; */ 175 | } 176 | /* blockquote:before { */ 177 | /* color: #ccc; */ 178 | /* content: open-quote; */ 179 | /* font-size: 4em; */ 180 | /* line-height: 0.1em; */ 181 | /* margin-right: 0.25em; */ 182 | /* vertical-align: -0.4em; */ 183 | /* } */ 184 | blockquote p { 185 | display: inline; 186 | } 187 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Viscous Demo 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | 24 |
25 |
26 | 27 |
28 |
29 |

Viscous Demo

30 |

A visual data inspector/explorer that runs in constant space, time, and screen space.

31 |
32 |
33 | 34 |
35 | 36 |
37 | 38 |
39 | 40 | 41 |

Load Data

42 | 43 |
44 | 45 |
46 | 47 | 48 | 49 | 50 |
51 |
52 | 53 |
54 | 55 |
56 | 57 | 63 |
64 |
65 | 66 |
67 | 68 | 69 |
70 | 71 | 72 | 73 |
74 |
75 | 76 | 77 |
78 | 79 |
80 |

Viscous

81 | 82 |
83 | 84 |
85 | 86 |
87 |
88 |
89 | 90 | 91 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /docs/js/manifest.edn: -------------------------------------------------------------------------------- 1 | [{:module-id :main, :name :main, :output-name "main.js", :entries [com.phronemophobic.viscous.demo], :depends-on nil, :sources ["goog/base.js" "goog/debug/error.js" "goog/dom/nodetype.js" "goog/asserts/asserts.js" "goog/reflect/reflect.js" "goog/math/long.js" "goog/math/integer.js" "goog/dom/asserts.js" "goog/functions/functions.js" "goog/string/typedstring.js" "goog/string/const.js" "goog/i18n/bidi.js" "goog/html/trustedtypes.js" "goog/html/safescript.js" "goog/fs/url.js" "goog/fs/blob.js" "goog/html/trustedresourceurl.js" "goog/string/internal.js" "goog/html/safeurl.js" "goog/html/safestyle.js" "goog/object/object.js" "goog/html/safestylesheet.js" "goog/dom/htmlelement.js" "goog/dom/tagname.js" "goog/array/array.js" "goog/labs/useragent/useragent.js" "goog/labs/useragent/util.js" "goog/labs/useragent/browser.js" "goog/dom/tags.js" "goog/html/safehtml.js" "goog/html/uncheckedconversions.js" "goog/dom/safe.js" "goog/string/string.js" "goog/collections/maps.js" "goog/structs/structs.js" "goog/uri/utils.js" "goog/uri/uri.js" "goog/string/stringbuffer.js" "cljs/core.cljs" "membrane/ui.cljc" "goog/promise/thenable.js" "goog/async/freelist.js" "goog/async/workqueue.js" "goog/debug/entrypointregistry.js" "goog/labs/useragent/engine.js" "goog/labs/useragent/platform.js" "goog/useragent/useragent.js" "goog/dom/browserfeature.js" "goog/math/math.js" "goog/math/coordinate.js" "goog/math/size.js" "goog/dom/dom.js" "goog/async/nexttick.js" "goog/async/throwexception.js" "goog/async/run.js" "goog/promise/resolver.js" "goog/promise/promise.js" "goog/disposable/idisposable.js" "goog/disposable/dispose.js" "goog/disposable/disposeall.js" "goog/disposable/disposable.js" "goog/debug/errorcontext.js" "goog/debug/debug.js" "goog/events/eventid.js" "goog/events/event.js" "goog/events/browserfeature.js" "goog/events/eventtype.js" "goog/events/browserevent.js" "goog/events/eventlike.js" "goog/events/listenablekey.js" "goog/events/listenable.js" "goog/events/listener.js" "goog/events/listenermap.js" "goog/debug/errorhandler.js" "goog/events/eventhandler.js" "goog/events/eventwrapper.js" "goog/events/events.js" "goog/events/eventtarget.js" "goog/timer/timer.js" "goog/json/json.js" "goog/json/hybrid.js" "goog/log/log.js" "goog/net/errorcode.js" "goog/net/eventtype.js" "goog/net/httpstatus.js" "goog/net/xhrlike.js" "goog/net/xmlhttpfactory.js" "goog/net/wrapperxmlhttpfactory.js" "goog/net/xmlhttp.js" "goog/net/xhrio.js" "clojure/string.cljs" "cljs/tools/reader/impl/utils.cljs" "cljs/tools/reader/reader_types.cljs" "cljs/tools/reader/impl/inspect.cljs" "cljs/tools/reader/impl/errors.cljs" "cljs/tools/reader/impl/commons.cljs" "cljs/tools/reader.cljs" "cljs/tools/reader/edn.cljs" "cljs/reader.cljs" "clojure/edn.cljs" "com/rpl/specter/protocols.cljc" "clojure/walk.cljs" "com/rpl/specter/impl.cljc" "com/rpl/specter/navs.cljc" "clojure/set.cljs" "com/rpl/specter.cljc" "cljs/analyzer/impl.cljc" "cljs/analyzer/passes.cljc" "cljs/analyzer/passes/and_or.cljc" "cljs/env.cljc" "cljs/tagged_literals.cljc" "cljs/analyzer.cljc" "cljs/analyzer/api.cljc" "membrane/component.cljc" "membrane/basic_components.cljc" "membrane/toolkit.cljc" "com/phronemophobic/viscous.cljc" "membrane/audio.cljs" "shadow/js.js" "shadow$empty.js" "node_modules/base64-js/index.js" "node_modules/ieee754/index.js" "node_modules/isarray/index.js" "node_modules/buffer/index.js" "node_modules/opentype_DOT_js/dist/opentype.js" "membrane/webgl.cljs" "com/phronemophobic/viscous/demo.cljs" "shadow/module/main/append.js"]}] -------------------------------------------------------------------------------- /inspector-resize.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phronmophobic/viscous/7815e80d890d1a7a26e29ff6c311cbad8c847a44/inspector-resize.gif -------------------------------------------------------------------------------- /inspector.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phronmophobic/viscous/7815e80d890d1a7a26e29ff6c311cbad8c847a44/inspector.gif -------------------------------------------------------------------------------- /navigation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phronmophobic/viscous/7815e80d890d1a7a26e29ff6c311cbad8c847a44/navigation.gif -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "viscous", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "viscous", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "buffer": "4.9.2", 13 | "opentype.js": "1.3.4" 14 | }, 15 | "devDependencies": { 16 | "shadow-cljs": "^2.16.12" 17 | } 18 | }, 19 | "node_modules/asn1.js": { 20 | "version": "5.4.1", 21 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", 22 | "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", 23 | "dev": true, 24 | "dependencies": { 25 | "bn.js": "^4.0.0", 26 | "inherits": "^2.0.1", 27 | "minimalistic-assert": "^1.0.0", 28 | "safer-buffer": "^2.1.0" 29 | } 30 | }, 31 | "node_modules/asn1.js/node_modules/bn.js": { 32 | "version": "4.12.0", 33 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 34 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 35 | "dev": true 36 | }, 37 | "node_modules/assert": { 38 | "version": "1.5.0", 39 | "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", 40 | "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", 41 | "dev": true, 42 | "dependencies": { 43 | "object-assign": "^4.1.1", 44 | "util": "0.10.3" 45 | } 46 | }, 47 | "node_modules/assert/node_modules/inherits": { 48 | "version": "2.0.1", 49 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", 50 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", 51 | "dev": true 52 | }, 53 | "node_modules/assert/node_modules/util": { 54 | "version": "0.10.3", 55 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", 56 | "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", 57 | "dev": true, 58 | "dependencies": { 59 | "inherits": "2.0.1" 60 | } 61 | }, 62 | "node_modules/base64-js": { 63 | "version": "1.5.1", 64 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 65 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 66 | "funding": [ 67 | { 68 | "type": "github", 69 | "url": "https://github.com/sponsors/feross" 70 | }, 71 | { 72 | "type": "patreon", 73 | "url": "https://www.patreon.com/feross" 74 | }, 75 | { 76 | "type": "consulting", 77 | "url": "https://feross.org/support" 78 | } 79 | ] 80 | }, 81 | "node_modules/bn.js": { 82 | "version": "5.2.0", 83 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", 84 | "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", 85 | "dev": true 86 | }, 87 | "node_modules/brorand": { 88 | "version": "1.1.0", 89 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 90 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", 91 | "dev": true 92 | }, 93 | "node_modules/browserify-aes": { 94 | "version": "1.2.0", 95 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 96 | "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", 97 | "dev": true, 98 | "dependencies": { 99 | "buffer-xor": "^1.0.3", 100 | "cipher-base": "^1.0.0", 101 | "create-hash": "^1.1.0", 102 | "evp_bytestokey": "^1.0.3", 103 | "inherits": "^2.0.1", 104 | "safe-buffer": "^5.0.1" 105 | } 106 | }, 107 | "node_modules/browserify-cipher": { 108 | "version": "1.0.1", 109 | "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", 110 | "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", 111 | "dev": true, 112 | "dependencies": { 113 | "browserify-aes": "^1.0.4", 114 | "browserify-des": "^1.0.0", 115 | "evp_bytestokey": "^1.0.0" 116 | } 117 | }, 118 | "node_modules/browserify-des": { 119 | "version": "1.0.2", 120 | "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", 121 | "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", 122 | "dev": true, 123 | "dependencies": { 124 | "cipher-base": "^1.0.1", 125 | "des.js": "^1.0.0", 126 | "inherits": "^2.0.1", 127 | "safe-buffer": "^5.1.2" 128 | } 129 | }, 130 | "node_modules/browserify-rsa": { 131 | "version": "4.1.0", 132 | "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", 133 | "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", 134 | "dev": true, 135 | "dependencies": { 136 | "bn.js": "^5.0.0", 137 | "randombytes": "^2.0.1" 138 | } 139 | }, 140 | "node_modules/browserify-sign": { 141 | "version": "4.2.1", 142 | "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", 143 | "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", 144 | "dev": true, 145 | "dependencies": { 146 | "bn.js": "^5.1.1", 147 | "browserify-rsa": "^4.0.1", 148 | "create-hash": "^1.2.0", 149 | "create-hmac": "^1.1.7", 150 | "elliptic": "^6.5.3", 151 | "inherits": "^2.0.4", 152 | "parse-asn1": "^5.1.5", 153 | "readable-stream": "^3.6.0", 154 | "safe-buffer": "^5.2.0" 155 | } 156 | }, 157 | "node_modules/browserify-sign/node_modules/readable-stream": { 158 | "version": "3.6.0", 159 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 160 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 161 | "dev": true, 162 | "dependencies": { 163 | "inherits": "^2.0.3", 164 | "string_decoder": "^1.1.1", 165 | "util-deprecate": "^1.0.1" 166 | }, 167 | "engines": { 168 | "node": ">= 6" 169 | } 170 | }, 171 | "node_modules/browserify-zlib": { 172 | "version": "0.2.0", 173 | "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", 174 | "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", 175 | "dev": true, 176 | "dependencies": { 177 | "pako": "~1.0.5" 178 | } 179 | }, 180 | "node_modules/buffer": { 181 | "version": "4.9.2", 182 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 183 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 184 | "dependencies": { 185 | "base64-js": "^1.0.2", 186 | "ieee754": "^1.1.4", 187 | "isarray": "^1.0.0" 188 | } 189 | }, 190 | "node_modules/buffer-xor": { 191 | "version": "1.0.3", 192 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 193 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", 194 | "dev": true 195 | }, 196 | "node_modules/builtin-status-codes": { 197 | "version": "3.0.0", 198 | "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", 199 | "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", 200 | "dev": true 201 | }, 202 | "node_modules/cipher-base": { 203 | "version": "1.0.4", 204 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 205 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", 206 | "dev": true, 207 | "dependencies": { 208 | "inherits": "^2.0.1", 209 | "safe-buffer": "^5.0.1" 210 | } 211 | }, 212 | "node_modules/console-browserify": { 213 | "version": "1.2.0", 214 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", 215 | "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", 216 | "dev": true 217 | }, 218 | "node_modules/constants-browserify": { 219 | "version": "1.0.0", 220 | "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", 221 | "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", 222 | "dev": true 223 | }, 224 | "node_modules/core-util-is": { 225 | "version": "1.0.3", 226 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 227 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 228 | "dev": true 229 | }, 230 | "node_modules/create-ecdh": { 231 | "version": "4.0.4", 232 | "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", 233 | "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", 234 | "dev": true, 235 | "dependencies": { 236 | "bn.js": "^4.1.0", 237 | "elliptic": "^6.5.3" 238 | } 239 | }, 240 | "node_modules/create-ecdh/node_modules/bn.js": { 241 | "version": "4.12.0", 242 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 243 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 244 | "dev": true 245 | }, 246 | "node_modules/create-hash": { 247 | "version": "1.2.0", 248 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 249 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 250 | "dev": true, 251 | "dependencies": { 252 | "cipher-base": "^1.0.1", 253 | "inherits": "^2.0.1", 254 | "md5.js": "^1.3.4", 255 | "ripemd160": "^2.0.1", 256 | "sha.js": "^2.4.0" 257 | } 258 | }, 259 | "node_modules/create-hmac": { 260 | "version": "1.1.7", 261 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 262 | "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", 263 | "dev": true, 264 | "dependencies": { 265 | "cipher-base": "^1.0.3", 266 | "create-hash": "^1.1.0", 267 | "inherits": "^2.0.1", 268 | "ripemd160": "^2.0.0", 269 | "safe-buffer": "^5.0.1", 270 | "sha.js": "^2.4.8" 271 | } 272 | }, 273 | "node_modules/crypto-browserify": { 274 | "version": "3.12.0", 275 | "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", 276 | "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", 277 | "dev": true, 278 | "dependencies": { 279 | "browserify-cipher": "^1.0.0", 280 | "browserify-sign": "^4.0.0", 281 | "create-ecdh": "^4.0.0", 282 | "create-hash": "^1.1.0", 283 | "create-hmac": "^1.1.0", 284 | "diffie-hellman": "^5.0.0", 285 | "inherits": "^2.0.1", 286 | "pbkdf2": "^3.0.3", 287 | "public-encrypt": "^4.0.0", 288 | "randombytes": "^2.0.0", 289 | "randomfill": "^1.0.3" 290 | }, 291 | "engines": { 292 | "node": "*" 293 | } 294 | }, 295 | "node_modules/des.js": { 296 | "version": "1.0.1", 297 | "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", 298 | "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", 299 | "dev": true, 300 | "dependencies": { 301 | "inherits": "^2.0.1", 302 | "minimalistic-assert": "^1.0.0" 303 | } 304 | }, 305 | "node_modules/diffie-hellman": { 306 | "version": "5.0.3", 307 | "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", 308 | "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", 309 | "dev": true, 310 | "dependencies": { 311 | "bn.js": "^4.1.0", 312 | "miller-rabin": "^4.0.0", 313 | "randombytes": "^2.0.0" 314 | } 315 | }, 316 | "node_modules/diffie-hellman/node_modules/bn.js": { 317 | "version": "4.12.0", 318 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 319 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 320 | "dev": true 321 | }, 322 | "node_modules/domain-browser": { 323 | "version": "1.2.0", 324 | "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", 325 | "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", 326 | "dev": true, 327 | "engines": { 328 | "node": ">=0.4", 329 | "npm": ">=1.2" 330 | } 331 | }, 332 | "node_modules/elliptic": { 333 | "version": "6.5.4", 334 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", 335 | "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", 336 | "dev": true, 337 | "dependencies": { 338 | "bn.js": "^4.11.9", 339 | "brorand": "^1.1.0", 340 | "hash.js": "^1.0.0", 341 | "hmac-drbg": "^1.0.1", 342 | "inherits": "^2.0.4", 343 | "minimalistic-assert": "^1.0.1", 344 | "minimalistic-crypto-utils": "^1.0.1" 345 | } 346 | }, 347 | "node_modules/elliptic/node_modules/bn.js": { 348 | "version": "4.12.0", 349 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 350 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 351 | "dev": true 352 | }, 353 | "node_modules/events": { 354 | "version": "3.3.0", 355 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", 356 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", 357 | "dev": true, 358 | "engines": { 359 | "node": ">=0.8.x" 360 | } 361 | }, 362 | "node_modules/evp_bytestokey": { 363 | "version": "1.0.3", 364 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 365 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", 366 | "dev": true, 367 | "dependencies": { 368 | "md5.js": "^1.3.4", 369 | "safe-buffer": "^5.1.1" 370 | } 371 | }, 372 | "node_modules/hash-base": { 373 | "version": "3.1.0", 374 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", 375 | "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", 376 | "dev": true, 377 | "dependencies": { 378 | "inherits": "^2.0.4", 379 | "readable-stream": "^3.6.0", 380 | "safe-buffer": "^5.2.0" 381 | }, 382 | "engines": { 383 | "node": ">=4" 384 | } 385 | }, 386 | "node_modules/hash-base/node_modules/readable-stream": { 387 | "version": "3.6.0", 388 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 389 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 390 | "dev": true, 391 | "dependencies": { 392 | "inherits": "^2.0.3", 393 | "string_decoder": "^1.1.1", 394 | "util-deprecate": "^1.0.1" 395 | }, 396 | "engines": { 397 | "node": ">= 6" 398 | } 399 | }, 400 | "node_modules/hash.js": { 401 | "version": "1.1.7", 402 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 403 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 404 | "dev": true, 405 | "dependencies": { 406 | "inherits": "^2.0.3", 407 | "minimalistic-assert": "^1.0.1" 408 | } 409 | }, 410 | "node_modules/hmac-drbg": { 411 | "version": "1.0.1", 412 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 413 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", 414 | "dev": true, 415 | "dependencies": { 416 | "hash.js": "^1.0.3", 417 | "minimalistic-assert": "^1.0.0", 418 | "minimalistic-crypto-utils": "^1.0.1" 419 | } 420 | }, 421 | "node_modules/https-browserify": { 422 | "version": "1.0.0", 423 | "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", 424 | "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", 425 | "dev": true 426 | }, 427 | "node_modules/ieee754": { 428 | "version": "1.2.1", 429 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 430 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 431 | "funding": [ 432 | { 433 | "type": "github", 434 | "url": "https://github.com/sponsors/feross" 435 | }, 436 | { 437 | "type": "patreon", 438 | "url": "https://www.patreon.com/feross" 439 | }, 440 | { 441 | "type": "consulting", 442 | "url": "https://feross.org/support" 443 | } 444 | ] 445 | }, 446 | "node_modules/inherits": { 447 | "version": "2.0.4", 448 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 449 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 450 | "dev": true 451 | }, 452 | "node_modules/isarray": { 453 | "version": "1.0.0", 454 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 455 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 456 | }, 457 | "node_modules/isexe": { 458 | "version": "2.0.0", 459 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 460 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 461 | "dev": true 462 | }, 463 | "node_modules/md5.js": { 464 | "version": "1.3.5", 465 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", 466 | "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", 467 | "dev": true, 468 | "dependencies": { 469 | "hash-base": "^3.0.0", 470 | "inherits": "^2.0.1", 471 | "safe-buffer": "^5.1.2" 472 | } 473 | }, 474 | "node_modules/miller-rabin": { 475 | "version": "4.0.1", 476 | "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", 477 | "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", 478 | "dev": true, 479 | "dependencies": { 480 | "bn.js": "^4.0.0", 481 | "brorand": "^1.0.1" 482 | }, 483 | "bin": { 484 | "miller-rabin": "bin/miller-rabin" 485 | } 486 | }, 487 | "node_modules/miller-rabin/node_modules/bn.js": { 488 | "version": "4.12.0", 489 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 490 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 491 | "dev": true 492 | }, 493 | "node_modules/minimalistic-assert": { 494 | "version": "1.0.1", 495 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 496 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", 497 | "dev": true 498 | }, 499 | "node_modules/minimalistic-crypto-utils": { 500 | "version": "1.0.1", 501 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 502 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", 503 | "dev": true 504 | }, 505 | "node_modules/node-libs-browser": { 506 | "version": "2.2.1", 507 | "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", 508 | "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", 509 | "dev": true, 510 | "dependencies": { 511 | "assert": "^1.1.1", 512 | "browserify-zlib": "^0.2.0", 513 | "buffer": "^4.3.0", 514 | "console-browserify": "^1.1.0", 515 | "constants-browserify": "^1.0.0", 516 | "crypto-browserify": "^3.11.0", 517 | "domain-browser": "^1.1.1", 518 | "events": "^3.0.0", 519 | "https-browserify": "^1.0.0", 520 | "os-browserify": "^0.3.0", 521 | "path-browserify": "0.0.1", 522 | "process": "^0.11.10", 523 | "punycode": "^1.2.4", 524 | "querystring-es3": "^0.2.0", 525 | "readable-stream": "^2.3.3", 526 | "stream-browserify": "^2.0.1", 527 | "stream-http": "^2.7.2", 528 | "string_decoder": "^1.0.0", 529 | "timers-browserify": "^2.0.4", 530 | "tty-browserify": "0.0.0", 531 | "url": "^0.11.0", 532 | "util": "^0.11.0", 533 | "vm-browserify": "^1.0.1" 534 | } 535 | }, 536 | "node_modules/object-assign": { 537 | "version": "4.1.1", 538 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 539 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 540 | "dev": true, 541 | "engines": { 542 | "node": ">=0.10.0" 543 | } 544 | }, 545 | "node_modules/opentype.js": { 546 | "version": "1.3.4", 547 | "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", 548 | "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", 549 | "dependencies": { 550 | "string.prototype.codepointat": "^0.2.1", 551 | "tiny-inflate": "^1.0.3" 552 | }, 553 | "bin": { 554 | "ot": "bin/ot" 555 | }, 556 | "engines": { 557 | "node": ">= 8.0.0" 558 | } 559 | }, 560 | "node_modules/os-browserify": { 561 | "version": "0.3.0", 562 | "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", 563 | "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", 564 | "dev": true 565 | }, 566 | "node_modules/pako": { 567 | "version": "1.0.11", 568 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", 569 | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", 570 | "dev": true 571 | }, 572 | "node_modules/parse-asn1": { 573 | "version": "5.1.6", 574 | "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", 575 | "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", 576 | "dev": true, 577 | "dependencies": { 578 | "asn1.js": "^5.2.0", 579 | "browserify-aes": "^1.0.0", 580 | "evp_bytestokey": "^1.0.0", 581 | "pbkdf2": "^3.0.3", 582 | "safe-buffer": "^5.1.1" 583 | } 584 | }, 585 | "node_modules/path-browserify": { 586 | "version": "0.0.1", 587 | "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", 588 | "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", 589 | "dev": true 590 | }, 591 | "node_modules/pbkdf2": { 592 | "version": "3.1.2", 593 | "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", 594 | "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", 595 | "dev": true, 596 | "dependencies": { 597 | "create-hash": "^1.1.2", 598 | "create-hmac": "^1.1.4", 599 | "ripemd160": "^2.0.1", 600 | "safe-buffer": "^5.0.1", 601 | "sha.js": "^2.4.8" 602 | }, 603 | "engines": { 604 | "node": ">=0.12" 605 | } 606 | }, 607 | "node_modules/process": { 608 | "version": "0.11.10", 609 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 610 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", 611 | "dev": true, 612 | "engines": { 613 | "node": ">= 0.6.0" 614 | } 615 | }, 616 | "node_modules/process-nextick-args": { 617 | "version": "2.0.1", 618 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 619 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 620 | "dev": true 621 | }, 622 | "node_modules/public-encrypt": { 623 | "version": "4.0.3", 624 | "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", 625 | "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", 626 | "dev": true, 627 | "dependencies": { 628 | "bn.js": "^4.1.0", 629 | "browserify-rsa": "^4.0.0", 630 | "create-hash": "^1.1.0", 631 | "parse-asn1": "^5.0.0", 632 | "randombytes": "^2.0.1", 633 | "safe-buffer": "^5.1.2" 634 | } 635 | }, 636 | "node_modules/public-encrypt/node_modules/bn.js": { 637 | "version": "4.12.0", 638 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 639 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 640 | "dev": true 641 | }, 642 | "node_modules/punycode": { 643 | "version": "1.4.1", 644 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 645 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", 646 | "dev": true 647 | }, 648 | "node_modules/querystring": { 649 | "version": "0.2.0", 650 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 651 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", 652 | "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", 653 | "dev": true, 654 | "engines": { 655 | "node": ">=0.4.x" 656 | } 657 | }, 658 | "node_modules/querystring-es3": { 659 | "version": "0.2.1", 660 | "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", 661 | "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", 662 | "dev": true, 663 | "engines": { 664 | "node": ">=0.4.x" 665 | } 666 | }, 667 | "node_modules/randombytes": { 668 | "version": "2.1.0", 669 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 670 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 671 | "dev": true, 672 | "dependencies": { 673 | "safe-buffer": "^5.1.0" 674 | } 675 | }, 676 | "node_modules/randomfill": { 677 | "version": "1.0.4", 678 | "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", 679 | "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", 680 | "dev": true, 681 | "dependencies": { 682 | "randombytes": "^2.0.5", 683 | "safe-buffer": "^5.1.0" 684 | } 685 | }, 686 | "node_modules/readable-stream": { 687 | "version": "2.3.7", 688 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 689 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 690 | "dev": true, 691 | "dependencies": { 692 | "core-util-is": "~1.0.0", 693 | "inherits": "~2.0.3", 694 | "isarray": "~1.0.0", 695 | "process-nextick-args": "~2.0.0", 696 | "safe-buffer": "~5.1.1", 697 | "string_decoder": "~1.1.1", 698 | "util-deprecate": "~1.0.1" 699 | } 700 | }, 701 | "node_modules/readable-stream/node_modules/safe-buffer": { 702 | "version": "5.1.2", 703 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 704 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 705 | "dev": true 706 | }, 707 | "node_modules/readable-stream/node_modules/string_decoder": { 708 | "version": "1.1.1", 709 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 710 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 711 | "dev": true, 712 | "dependencies": { 713 | "safe-buffer": "~5.1.0" 714 | } 715 | }, 716 | "node_modules/readline-sync": { 717 | "version": "1.4.10", 718 | "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", 719 | "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", 720 | "dev": true, 721 | "engines": { 722 | "node": ">= 0.8.0" 723 | } 724 | }, 725 | "node_modules/ripemd160": { 726 | "version": "2.0.2", 727 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 728 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 729 | "dev": true, 730 | "dependencies": { 731 | "hash-base": "^3.0.0", 732 | "inherits": "^2.0.1" 733 | } 734 | }, 735 | "node_modules/safe-buffer": { 736 | "version": "5.2.1", 737 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 738 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 739 | "dev": true, 740 | "funding": [ 741 | { 742 | "type": "github", 743 | "url": "https://github.com/sponsors/feross" 744 | }, 745 | { 746 | "type": "patreon", 747 | "url": "https://www.patreon.com/feross" 748 | }, 749 | { 750 | "type": "consulting", 751 | "url": "https://feross.org/support" 752 | } 753 | ] 754 | }, 755 | "node_modules/safer-buffer": { 756 | "version": "2.1.2", 757 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 758 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 759 | "dev": true 760 | }, 761 | "node_modules/setimmediate": { 762 | "version": "1.0.5", 763 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 764 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", 765 | "dev": true 766 | }, 767 | "node_modules/sha.js": { 768 | "version": "2.4.11", 769 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 770 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 771 | "dev": true, 772 | "dependencies": { 773 | "inherits": "^2.0.1", 774 | "safe-buffer": "^5.0.1" 775 | }, 776 | "bin": { 777 | "sha.js": "bin.js" 778 | } 779 | }, 780 | "node_modules/shadow-cljs": { 781 | "version": "2.16.12", 782 | "resolved": "https://registry.npmjs.org/shadow-cljs/-/shadow-cljs-2.16.12.tgz", 783 | "integrity": "sha512-6JqOhN5X3n0IkxA/gSUcZ1lImwcW1LmpgzlaBDOC/u/pIysdNm0tiOxpOTEnExl9nKZBS/EYS7bXIIInywPJUA==", 784 | "dev": true, 785 | "dependencies": { 786 | "node-libs-browser": "^2.2.1", 787 | "readline-sync": "^1.4.7", 788 | "shadow-cljs-jar": "1.3.2", 789 | "source-map-support": "^0.4.15", 790 | "which": "^1.3.1", 791 | "ws": "^7.4.6" 792 | }, 793 | "bin": { 794 | "shadow-cljs": "cli/runner.js" 795 | }, 796 | "engines": { 797 | "node": ">=6.0.0" 798 | } 799 | }, 800 | "node_modules/shadow-cljs-jar": { 801 | "version": "1.3.2", 802 | "resolved": "https://registry.npmjs.org/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz", 803 | "integrity": "sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg==", 804 | "dev": true 805 | }, 806 | "node_modules/source-map": { 807 | "version": "0.5.7", 808 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 809 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 810 | "dev": true, 811 | "engines": { 812 | "node": ">=0.10.0" 813 | } 814 | }, 815 | "node_modules/source-map-support": { 816 | "version": "0.4.18", 817 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", 818 | "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", 819 | "dev": true, 820 | "dependencies": { 821 | "source-map": "^0.5.6" 822 | } 823 | }, 824 | "node_modules/stream-browserify": { 825 | "version": "2.0.2", 826 | "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", 827 | "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", 828 | "dev": true, 829 | "dependencies": { 830 | "inherits": "~2.0.1", 831 | "readable-stream": "^2.0.2" 832 | } 833 | }, 834 | "node_modules/stream-http": { 835 | "version": "2.8.3", 836 | "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", 837 | "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", 838 | "dev": true, 839 | "dependencies": { 840 | "builtin-status-codes": "^3.0.0", 841 | "inherits": "^2.0.1", 842 | "readable-stream": "^2.3.6", 843 | "to-arraybuffer": "^1.0.0", 844 | "xtend": "^4.0.0" 845 | } 846 | }, 847 | "node_modules/string_decoder": { 848 | "version": "1.3.0", 849 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 850 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 851 | "dev": true, 852 | "dependencies": { 853 | "safe-buffer": "~5.2.0" 854 | } 855 | }, 856 | "node_modules/string.prototype.codepointat": { 857 | "version": "0.2.1", 858 | "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", 859 | "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" 860 | }, 861 | "node_modules/timers-browserify": { 862 | "version": "2.0.12", 863 | "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", 864 | "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", 865 | "dev": true, 866 | "dependencies": { 867 | "setimmediate": "^1.0.4" 868 | }, 869 | "engines": { 870 | "node": ">=0.6.0" 871 | } 872 | }, 873 | "node_modules/tiny-inflate": { 874 | "version": "1.0.3", 875 | "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", 876 | "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" 877 | }, 878 | "node_modules/to-arraybuffer": { 879 | "version": "1.0.1", 880 | "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", 881 | "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", 882 | "dev": true 883 | }, 884 | "node_modules/tty-browserify": { 885 | "version": "0.0.0", 886 | "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", 887 | "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", 888 | "dev": true 889 | }, 890 | "node_modules/url": { 891 | "version": "0.11.0", 892 | "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", 893 | "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", 894 | "dev": true, 895 | "dependencies": { 896 | "punycode": "1.3.2", 897 | "querystring": "0.2.0" 898 | } 899 | }, 900 | "node_modules/url/node_modules/punycode": { 901 | "version": "1.3.2", 902 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 903 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", 904 | "dev": true 905 | }, 906 | "node_modules/util": { 907 | "version": "0.11.1", 908 | "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", 909 | "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", 910 | "dev": true, 911 | "dependencies": { 912 | "inherits": "2.0.3" 913 | } 914 | }, 915 | "node_modules/util-deprecate": { 916 | "version": "1.0.2", 917 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 918 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 919 | "dev": true 920 | }, 921 | "node_modules/util/node_modules/inherits": { 922 | "version": "2.0.3", 923 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 924 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 925 | "dev": true 926 | }, 927 | "node_modules/vm-browserify": { 928 | "version": "1.1.2", 929 | "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", 930 | "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", 931 | "dev": true 932 | }, 933 | "node_modules/which": { 934 | "version": "1.3.1", 935 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 936 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 937 | "dev": true, 938 | "dependencies": { 939 | "isexe": "^2.0.0" 940 | }, 941 | "bin": { 942 | "which": "bin/which" 943 | } 944 | }, 945 | "node_modules/ws": { 946 | "version": "7.5.6", 947 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", 948 | "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", 949 | "dev": true, 950 | "engines": { 951 | "node": ">=8.3.0" 952 | }, 953 | "peerDependencies": { 954 | "bufferutil": "^4.0.1", 955 | "utf-8-validate": "^5.0.2" 956 | }, 957 | "peerDependenciesMeta": { 958 | "bufferutil": { 959 | "optional": true 960 | }, 961 | "utf-8-validate": { 962 | "optional": true 963 | } 964 | } 965 | }, 966 | "node_modules/xtend": { 967 | "version": "4.0.2", 968 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 969 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 970 | "dev": true, 971 | "engines": { 972 | "node": ">=0.4" 973 | } 974 | } 975 | }, 976 | "dependencies": { 977 | "asn1.js": { 978 | "version": "5.4.1", 979 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", 980 | "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", 981 | "dev": true, 982 | "requires": { 983 | "bn.js": "^4.0.0", 984 | "inherits": "^2.0.1", 985 | "minimalistic-assert": "^1.0.0", 986 | "safer-buffer": "^2.1.0" 987 | }, 988 | "dependencies": { 989 | "bn.js": { 990 | "version": "4.12.0", 991 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 992 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 993 | "dev": true 994 | } 995 | } 996 | }, 997 | "assert": { 998 | "version": "1.5.0", 999 | "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", 1000 | "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", 1001 | "dev": true, 1002 | "requires": { 1003 | "object-assign": "^4.1.1", 1004 | "util": "0.10.3" 1005 | }, 1006 | "dependencies": { 1007 | "inherits": { 1008 | "version": "2.0.1", 1009 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", 1010 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", 1011 | "dev": true 1012 | }, 1013 | "util": { 1014 | "version": "0.10.3", 1015 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", 1016 | "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", 1017 | "dev": true, 1018 | "requires": { 1019 | "inherits": "2.0.1" 1020 | } 1021 | } 1022 | } 1023 | }, 1024 | "base64-js": { 1025 | "version": "1.5.1", 1026 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 1027 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" 1028 | }, 1029 | "bn.js": { 1030 | "version": "5.2.0", 1031 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", 1032 | "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", 1033 | "dev": true 1034 | }, 1035 | "brorand": { 1036 | "version": "1.1.0", 1037 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 1038 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", 1039 | "dev": true 1040 | }, 1041 | "browserify-aes": { 1042 | "version": "1.2.0", 1043 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 1044 | "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", 1045 | "dev": true, 1046 | "requires": { 1047 | "buffer-xor": "^1.0.3", 1048 | "cipher-base": "^1.0.0", 1049 | "create-hash": "^1.1.0", 1050 | "evp_bytestokey": "^1.0.3", 1051 | "inherits": "^2.0.1", 1052 | "safe-buffer": "^5.0.1" 1053 | } 1054 | }, 1055 | "browserify-cipher": { 1056 | "version": "1.0.1", 1057 | "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", 1058 | "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", 1059 | "dev": true, 1060 | "requires": { 1061 | "browserify-aes": "^1.0.4", 1062 | "browserify-des": "^1.0.0", 1063 | "evp_bytestokey": "^1.0.0" 1064 | } 1065 | }, 1066 | "browserify-des": { 1067 | "version": "1.0.2", 1068 | "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", 1069 | "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", 1070 | "dev": true, 1071 | "requires": { 1072 | "cipher-base": "^1.0.1", 1073 | "des.js": "^1.0.0", 1074 | "inherits": "^2.0.1", 1075 | "safe-buffer": "^5.1.2" 1076 | } 1077 | }, 1078 | "browserify-rsa": { 1079 | "version": "4.1.0", 1080 | "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", 1081 | "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", 1082 | "dev": true, 1083 | "requires": { 1084 | "bn.js": "^5.0.0", 1085 | "randombytes": "^2.0.1" 1086 | } 1087 | }, 1088 | "browserify-sign": { 1089 | "version": "4.2.1", 1090 | "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", 1091 | "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", 1092 | "dev": true, 1093 | "requires": { 1094 | "bn.js": "^5.1.1", 1095 | "browserify-rsa": "^4.0.1", 1096 | "create-hash": "^1.2.0", 1097 | "create-hmac": "^1.1.7", 1098 | "elliptic": "^6.5.3", 1099 | "inherits": "^2.0.4", 1100 | "parse-asn1": "^5.1.5", 1101 | "readable-stream": "^3.6.0", 1102 | "safe-buffer": "^5.2.0" 1103 | }, 1104 | "dependencies": { 1105 | "readable-stream": { 1106 | "version": "3.6.0", 1107 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 1108 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 1109 | "dev": true, 1110 | "requires": { 1111 | "inherits": "^2.0.3", 1112 | "string_decoder": "^1.1.1", 1113 | "util-deprecate": "^1.0.1" 1114 | } 1115 | } 1116 | } 1117 | }, 1118 | "browserify-zlib": { 1119 | "version": "0.2.0", 1120 | "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", 1121 | "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", 1122 | "dev": true, 1123 | "requires": { 1124 | "pako": "~1.0.5" 1125 | } 1126 | }, 1127 | "buffer": { 1128 | "version": "4.9.2", 1129 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 1130 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 1131 | "requires": { 1132 | "base64-js": "^1.0.2", 1133 | "ieee754": "^1.1.4", 1134 | "isarray": "^1.0.0" 1135 | } 1136 | }, 1137 | "buffer-xor": { 1138 | "version": "1.0.3", 1139 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 1140 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", 1141 | "dev": true 1142 | }, 1143 | "builtin-status-codes": { 1144 | "version": "3.0.0", 1145 | "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", 1146 | "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", 1147 | "dev": true 1148 | }, 1149 | "cipher-base": { 1150 | "version": "1.0.4", 1151 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 1152 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", 1153 | "dev": true, 1154 | "requires": { 1155 | "inherits": "^2.0.1", 1156 | "safe-buffer": "^5.0.1" 1157 | } 1158 | }, 1159 | "console-browserify": { 1160 | "version": "1.2.0", 1161 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", 1162 | "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", 1163 | "dev": true 1164 | }, 1165 | "constants-browserify": { 1166 | "version": "1.0.0", 1167 | "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", 1168 | "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", 1169 | "dev": true 1170 | }, 1171 | "core-util-is": { 1172 | "version": "1.0.3", 1173 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 1174 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 1175 | "dev": true 1176 | }, 1177 | "create-ecdh": { 1178 | "version": "4.0.4", 1179 | "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", 1180 | "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", 1181 | "dev": true, 1182 | "requires": { 1183 | "bn.js": "^4.1.0", 1184 | "elliptic": "^6.5.3" 1185 | }, 1186 | "dependencies": { 1187 | "bn.js": { 1188 | "version": "4.12.0", 1189 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 1190 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 1191 | "dev": true 1192 | } 1193 | } 1194 | }, 1195 | "create-hash": { 1196 | "version": "1.2.0", 1197 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 1198 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 1199 | "dev": true, 1200 | "requires": { 1201 | "cipher-base": "^1.0.1", 1202 | "inherits": "^2.0.1", 1203 | "md5.js": "^1.3.4", 1204 | "ripemd160": "^2.0.1", 1205 | "sha.js": "^2.4.0" 1206 | } 1207 | }, 1208 | "create-hmac": { 1209 | "version": "1.1.7", 1210 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 1211 | "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", 1212 | "dev": true, 1213 | "requires": { 1214 | "cipher-base": "^1.0.3", 1215 | "create-hash": "^1.1.0", 1216 | "inherits": "^2.0.1", 1217 | "ripemd160": "^2.0.0", 1218 | "safe-buffer": "^5.0.1", 1219 | "sha.js": "^2.4.8" 1220 | } 1221 | }, 1222 | "crypto-browserify": { 1223 | "version": "3.12.0", 1224 | "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", 1225 | "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", 1226 | "dev": true, 1227 | "requires": { 1228 | "browserify-cipher": "^1.0.0", 1229 | "browserify-sign": "^4.0.0", 1230 | "create-ecdh": "^4.0.0", 1231 | "create-hash": "^1.1.0", 1232 | "create-hmac": "^1.1.0", 1233 | "diffie-hellman": "^5.0.0", 1234 | "inherits": "^2.0.1", 1235 | "pbkdf2": "^3.0.3", 1236 | "public-encrypt": "^4.0.0", 1237 | "randombytes": "^2.0.0", 1238 | "randomfill": "^1.0.3" 1239 | } 1240 | }, 1241 | "des.js": { 1242 | "version": "1.0.1", 1243 | "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", 1244 | "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", 1245 | "dev": true, 1246 | "requires": { 1247 | "inherits": "^2.0.1", 1248 | "minimalistic-assert": "^1.0.0" 1249 | } 1250 | }, 1251 | "diffie-hellman": { 1252 | "version": "5.0.3", 1253 | "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", 1254 | "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", 1255 | "dev": true, 1256 | "requires": { 1257 | "bn.js": "^4.1.0", 1258 | "miller-rabin": "^4.0.0", 1259 | "randombytes": "^2.0.0" 1260 | }, 1261 | "dependencies": { 1262 | "bn.js": { 1263 | "version": "4.12.0", 1264 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 1265 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 1266 | "dev": true 1267 | } 1268 | } 1269 | }, 1270 | "domain-browser": { 1271 | "version": "1.2.0", 1272 | "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", 1273 | "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", 1274 | "dev": true 1275 | }, 1276 | "elliptic": { 1277 | "version": "6.5.4", 1278 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", 1279 | "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", 1280 | "dev": true, 1281 | "requires": { 1282 | "bn.js": "^4.11.9", 1283 | "brorand": "^1.1.0", 1284 | "hash.js": "^1.0.0", 1285 | "hmac-drbg": "^1.0.1", 1286 | "inherits": "^2.0.4", 1287 | "minimalistic-assert": "^1.0.1", 1288 | "minimalistic-crypto-utils": "^1.0.1" 1289 | }, 1290 | "dependencies": { 1291 | "bn.js": { 1292 | "version": "4.12.0", 1293 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 1294 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 1295 | "dev": true 1296 | } 1297 | } 1298 | }, 1299 | "events": { 1300 | "version": "3.3.0", 1301 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", 1302 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", 1303 | "dev": true 1304 | }, 1305 | "evp_bytestokey": { 1306 | "version": "1.0.3", 1307 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 1308 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", 1309 | "dev": true, 1310 | "requires": { 1311 | "md5.js": "^1.3.4", 1312 | "safe-buffer": "^5.1.1" 1313 | } 1314 | }, 1315 | "hash-base": { 1316 | "version": "3.1.0", 1317 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", 1318 | "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", 1319 | "dev": true, 1320 | "requires": { 1321 | "inherits": "^2.0.4", 1322 | "readable-stream": "^3.6.0", 1323 | "safe-buffer": "^5.2.0" 1324 | }, 1325 | "dependencies": { 1326 | "readable-stream": { 1327 | "version": "3.6.0", 1328 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 1329 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 1330 | "dev": true, 1331 | "requires": { 1332 | "inherits": "^2.0.3", 1333 | "string_decoder": "^1.1.1", 1334 | "util-deprecate": "^1.0.1" 1335 | } 1336 | } 1337 | } 1338 | }, 1339 | "hash.js": { 1340 | "version": "1.1.7", 1341 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 1342 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 1343 | "dev": true, 1344 | "requires": { 1345 | "inherits": "^2.0.3", 1346 | "minimalistic-assert": "^1.0.1" 1347 | } 1348 | }, 1349 | "hmac-drbg": { 1350 | "version": "1.0.1", 1351 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 1352 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", 1353 | "dev": true, 1354 | "requires": { 1355 | "hash.js": "^1.0.3", 1356 | "minimalistic-assert": "^1.0.0", 1357 | "minimalistic-crypto-utils": "^1.0.1" 1358 | } 1359 | }, 1360 | "https-browserify": { 1361 | "version": "1.0.0", 1362 | "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", 1363 | "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", 1364 | "dev": true 1365 | }, 1366 | "ieee754": { 1367 | "version": "1.2.1", 1368 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 1369 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" 1370 | }, 1371 | "inherits": { 1372 | "version": "2.0.4", 1373 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1374 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1375 | "dev": true 1376 | }, 1377 | "isarray": { 1378 | "version": "1.0.0", 1379 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1380 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 1381 | }, 1382 | "isexe": { 1383 | "version": "2.0.0", 1384 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1385 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1386 | "dev": true 1387 | }, 1388 | "md5.js": { 1389 | "version": "1.3.5", 1390 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", 1391 | "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", 1392 | "dev": true, 1393 | "requires": { 1394 | "hash-base": "^3.0.0", 1395 | "inherits": "^2.0.1", 1396 | "safe-buffer": "^5.1.2" 1397 | } 1398 | }, 1399 | "miller-rabin": { 1400 | "version": "4.0.1", 1401 | "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", 1402 | "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", 1403 | "dev": true, 1404 | "requires": { 1405 | "bn.js": "^4.0.0", 1406 | "brorand": "^1.0.1" 1407 | }, 1408 | "dependencies": { 1409 | "bn.js": { 1410 | "version": "4.12.0", 1411 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 1412 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 1413 | "dev": true 1414 | } 1415 | } 1416 | }, 1417 | "minimalistic-assert": { 1418 | "version": "1.0.1", 1419 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 1420 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", 1421 | "dev": true 1422 | }, 1423 | "minimalistic-crypto-utils": { 1424 | "version": "1.0.1", 1425 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 1426 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", 1427 | "dev": true 1428 | }, 1429 | "node-libs-browser": { 1430 | "version": "2.2.1", 1431 | "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", 1432 | "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", 1433 | "dev": true, 1434 | "requires": { 1435 | "assert": "^1.1.1", 1436 | "browserify-zlib": "^0.2.0", 1437 | "buffer": "^4.3.0", 1438 | "console-browserify": "^1.1.0", 1439 | "constants-browserify": "^1.0.0", 1440 | "crypto-browserify": "^3.11.0", 1441 | "domain-browser": "^1.1.1", 1442 | "events": "^3.0.0", 1443 | "https-browserify": "^1.0.0", 1444 | "os-browserify": "^0.3.0", 1445 | "path-browserify": "0.0.1", 1446 | "process": "^0.11.10", 1447 | "punycode": "^1.2.4", 1448 | "querystring-es3": "^0.2.0", 1449 | "readable-stream": "^2.3.3", 1450 | "stream-browserify": "^2.0.1", 1451 | "stream-http": "^2.7.2", 1452 | "string_decoder": "^1.0.0", 1453 | "timers-browserify": "^2.0.4", 1454 | "tty-browserify": "0.0.0", 1455 | "url": "^0.11.0", 1456 | "util": "^0.11.0", 1457 | "vm-browserify": "^1.0.1" 1458 | } 1459 | }, 1460 | "object-assign": { 1461 | "version": "4.1.1", 1462 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1463 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1464 | "dev": true 1465 | }, 1466 | "opentype.js": { 1467 | "version": "1.3.4", 1468 | "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", 1469 | "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", 1470 | "requires": { 1471 | "string.prototype.codepointat": "^0.2.1", 1472 | "tiny-inflate": "^1.0.3" 1473 | } 1474 | }, 1475 | "os-browserify": { 1476 | "version": "0.3.0", 1477 | "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", 1478 | "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", 1479 | "dev": true 1480 | }, 1481 | "pako": { 1482 | "version": "1.0.11", 1483 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", 1484 | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", 1485 | "dev": true 1486 | }, 1487 | "parse-asn1": { 1488 | "version": "5.1.6", 1489 | "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", 1490 | "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", 1491 | "dev": true, 1492 | "requires": { 1493 | "asn1.js": "^5.2.0", 1494 | "browserify-aes": "^1.0.0", 1495 | "evp_bytestokey": "^1.0.0", 1496 | "pbkdf2": "^3.0.3", 1497 | "safe-buffer": "^5.1.1" 1498 | } 1499 | }, 1500 | "path-browserify": { 1501 | "version": "0.0.1", 1502 | "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", 1503 | "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", 1504 | "dev": true 1505 | }, 1506 | "pbkdf2": { 1507 | "version": "3.1.2", 1508 | "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", 1509 | "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", 1510 | "dev": true, 1511 | "requires": { 1512 | "create-hash": "^1.1.2", 1513 | "create-hmac": "^1.1.4", 1514 | "ripemd160": "^2.0.1", 1515 | "safe-buffer": "^5.0.1", 1516 | "sha.js": "^2.4.8" 1517 | } 1518 | }, 1519 | "process": { 1520 | "version": "0.11.10", 1521 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 1522 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", 1523 | "dev": true 1524 | }, 1525 | "process-nextick-args": { 1526 | "version": "2.0.1", 1527 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1528 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 1529 | "dev": true 1530 | }, 1531 | "public-encrypt": { 1532 | "version": "4.0.3", 1533 | "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", 1534 | "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", 1535 | "dev": true, 1536 | "requires": { 1537 | "bn.js": "^4.1.0", 1538 | "browserify-rsa": "^4.0.0", 1539 | "create-hash": "^1.1.0", 1540 | "parse-asn1": "^5.0.0", 1541 | "randombytes": "^2.0.1", 1542 | "safe-buffer": "^5.1.2" 1543 | }, 1544 | "dependencies": { 1545 | "bn.js": { 1546 | "version": "4.12.0", 1547 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 1548 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", 1549 | "dev": true 1550 | } 1551 | } 1552 | }, 1553 | "punycode": { 1554 | "version": "1.4.1", 1555 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 1556 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", 1557 | "dev": true 1558 | }, 1559 | "querystring": { 1560 | "version": "0.2.0", 1561 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 1562 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", 1563 | "dev": true 1564 | }, 1565 | "querystring-es3": { 1566 | "version": "0.2.1", 1567 | "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", 1568 | "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", 1569 | "dev": true 1570 | }, 1571 | "randombytes": { 1572 | "version": "2.1.0", 1573 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1574 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1575 | "dev": true, 1576 | "requires": { 1577 | "safe-buffer": "^5.1.0" 1578 | } 1579 | }, 1580 | "randomfill": { 1581 | "version": "1.0.4", 1582 | "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", 1583 | "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", 1584 | "dev": true, 1585 | "requires": { 1586 | "randombytes": "^2.0.5", 1587 | "safe-buffer": "^5.1.0" 1588 | } 1589 | }, 1590 | "readable-stream": { 1591 | "version": "2.3.7", 1592 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 1593 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 1594 | "dev": true, 1595 | "requires": { 1596 | "core-util-is": "~1.0.0", 1597 | "inherits": "~2.0.3", 1598 | "isarray": "~1.0.0", 1599 | "process-nextick-args": "~2.0.0", 1600 | "safe-buffer": "~5.1.1", 1601 | "string_decoder": "~1.1.1", 1602 | "util-deprecate": "~1.0.1" 1603 | }, 1604 | "dependencies": { 1605 | "safe-buffer": { 1606 | "version": "5.1.2", 1607 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1608 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1609 | "dev": true 1610 | }, 1611 | "string_decoder": { 1612 | "version": "1.1.1", 1613 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1614 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1615 | "dev": true, 1616 | "requires": { 1617 | "safe-buffer": "~5.1.0" 1618 | } 1619 | } 1620 | } 1621 | }, 1622 | "readline-sync": { 1623 | "version": "1.4.10", 1624 | "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", 1625 | "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", 1626 | "dev": true 1627 | }, 1628 | "ripemd160": { 1629 | "version": "2.0.2", 1630 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 1631 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 1632 | "dev": true, 1633 | "requires": { 1634 | "hash-base": "^3.0.0", 1635 | "inherits": "^2.0.1" 1636 | } 1637 | }, 1638 | "safe-buffer": { 1639 | "version": "5.2.1", 1640 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1641 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1642 | "dev": true 1643 | }, 1644 | "safer-buffer": { 1645 | "version": "2.1.2", 1646 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1647 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1648 | "dev": true 1649 | }, 1650 | "setimmediate": { 1651 | "version": "1.0.5", 1652 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 1653 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", 1654 | "dev": true 1655 | }, 1656 | "sha.js": { 1657 | "version": "2.4.11", 1658 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 1659 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 1660 | "dev": true, 1661 | "requires": { 1662 | "inherits": "^2.0.1", 1663 | "safe-buffer": "^5.0.1" 1664 | } 1665 | }, 1666 | "shadow-cljs": { 1667 | "version": "2.16.12", 1668 | "resolved": "https://registry.npmjs.org/shadow-cljs/-/shadow-cljs-2.16.12.tgz", 1669 | "integrity": "sha512-6JqOhN5X3n0IkxA/gSUcZ1lImwcW1LmpgzlaBDOC/u/pIysdNm0tiOxpOTEnExl9nKZBS/EYS7bXIIInywPJUA==", 1670 | "dev": true, 1671 | "requires": { 1672 | "node-libs-browser": "^2.2.1", 1673 | "readline-sync": "^1.4.7", 1674 | "shadow-cljs-jar": "1.3.2", 1675 | "source-map-support": "^0.4.15", 1676 | "which": "^1.3.1", 1677 | "ws": "^7.4.6" 1678 | } 1679 | }, 1680 | "shadow-cljs-jar": { 1681 | "version": "1.3.2", 1682 | "resolved": "https://registry.npmjs.org/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz", 1683 | "integrity": "sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg==", 1684 | "dev": true 1685 | }, 1686 | "source-map": { 1687 | "version": "0.5.7", 1688 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 1689 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 1690 | "dev": true 1691 | }, 1692 | "source-map-support": { 1693 | "version": "0.4.18", 1694 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", 1695 | "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", 1696 | "dev": true, 1697 | "requires": { 1698 | "source-map": "^0.5.6" 1699 | } 1700 | }, 1701 | "stream-browserify": { 1702 | "version": "2.0.2", 1703 | "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", 1704 | "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", 1705 | "dev": true, 1706 | "requires": { 1707 | "inherits": "~2.0.1", 1708 | "readable-stream": "^2.0.2" 1709 | } 1710 | }, 1711 | "stream-http": { 1712 | "version": "2.8.3", 1713 | "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", 1714 | "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", 1715 | "dev": true, 1716 | "requires": { 1717 | "builtin-status-codes": "^3.0.0", 1718 | "inherits": "^2.0.1", 1719 | "readable-stream": "^2.3.6", 1720 | "to-arraybuffer": "^1.0.0", 1721 | "xtend": "^4.0.0" 1722 | } 1723 | }, 1724 | "string_decoder": { 1725 | "version": "1.3.0", 1726 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 1727 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 1728 | "dev": true, 1729 | "requires": { 1730 | "safe-buffer": "~5.2.0" 1731 | } 1732 | }, 1733 | "string.prototype.codepointat": { 1734 | "version": "0.2.1", 1735 | "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", 1736 | "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" 1737 | }, 1738 | "timers-browserify": { 1739 | "version": "2.0.12", 1740 | "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", 1741 | "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", 1742 | "dev": true, 1743 | "requires": { 1744 | "setimmediate": "^1.0.4" 1745 | } 1746 | }, 1747 | "tiny-inflate": { 1748 | "version": "1.0.3", 1749 | "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", 1750 | "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" 1751 | }, 1752 | "to-arraybuffer": { 1753 | "version": "1.0.1", 1754 | "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", 1755 | "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", 1756 | "dev": true 1757 | }, 1758 | "tty-browserify": { 1759 | "version": "0.0.0", 1760 | "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", 1761 | "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", 1762 | "dev": true 1763 | }, 1764 | "url": { 1765 | "version": "0.11.0", 1766 | "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", 1767 | "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", 1768 | "dev": true, 1769 | "requires": { 1770 | "punycode": "1.3.2", 1771 | "querystring": "0.2.0" 1772 | }, 1773 | "dependencies": { 1774 | "punycode": { 1775 | "version": "1.3.2", 1776 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 1777 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", 1778 | "dev": true 1779 | } 1780 | } 1781 | }, 1782 | "util": { 1783 | "version": "0.11.1", 1784 | "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", 1785 | "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", 1786 | "dev": true, 1787 | "requires": { 1788 | "inherits": "2.0.3" 1789 | }, 1790 | "dependencies": { 1791 | "inherits": { 1792 | "version": "2.0.3", 1793 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1794 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 1795 | "dev": true 1796 | } 1797 | } 1798 | }, 1799 | "util-deprecate": { 1800 | "version": "1.0.2", 1801 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1802 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1803 | "dev": true 1804 | }, 1805 | "vm-browserify": { 1806 | "version": "1.1.2", 1807 | "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", 1808 | "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", 1809 | "dev": true 1810 | }, 1811 | "which": { 1812 | "version": "1.3.1", 1813 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1814 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1815 | "dev": true, 1816 | "requires": { 1817 | "isexe": "^2.0.0" 1818 | } 1819 | }, 1820 | "ws": { 1821 | "version": "7.5.6", 1822 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", 1823 | "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", 1824 | "dev": true, 1825 | "requires": {} 1826 | }, 1827 | "xtend": { 1828 | "version": "4.0.2", 1829 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1830 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 1831 | "dev": true 1832 | } 1833 | } 1834 | } 1835 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "viscous", 3 | "version": "1.0.0", 4 | "description": "A visual data inspector/explorer that runs in constant space, time, and screen space.", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "doc", 8 | "example": "example", 9 | "test": "test" 10 | }, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/phronmophobic/viscous.git" 17 | }, 18 | "keywords": [], 19 | "author": "", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/phronmophobic/viscous/issues" 23 | }, 24 | "homepage": "https://github.com/phronmophobic/viscous#readme", 25 | "devDependencies": { 26 | "shadow-cljs": "^2.16.12" 27 | }, 28 | "dependencies": { 29 | "buffer": "4.9.2", 30 | "opentype.js": "1.3.4" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /paging.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phronmophobic/viscous/7815e80d890d1a7a26e29ff6c311cbad8c847a44/paging.gif -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.phronemophobic 5 | viscous 6 | 1.2 7 | com.phronemophobic/viscous 8 | A visual data inspector/explorer that runs in constant space, time, and screen space. 9 | https://github.com/com.phronemophobic/viscous 10 | 11 | 12 | Eclipse Public License 13 | http://www.eclipse.org/legal/epl-v10.html 14 | 15 | 16 | 17 | 18 | Adrian 19 | 20 | 21 | 22 | https://github.com/com.phronemophobic/viscous 23 | scm:git:git://github.com/com.phronemophobic/viscous.git 24 | scm:git:ssh://git@github.com/com.phronemophobic/viscous.git 25 | v1.2 26 | 27 | 28 | 29 | org.clojure 30 | clojure 31 | 1.10.3 32 | 33 | 34 | com.phronemophobic 35 | membrane 36 | 0.9.31.8-beta 37 | 38 | 39 | 40 | src 41 | 42 | 43 | 44 | clojars 45 | https://repo.clojars.org/ 46 | 47 | 48 | 49 | 50 | clojars 51 | Clojars repository 52 | https://clojars.org/repo 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /public/blog.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Globals 3 | */ 4 | 5 | @media (min-width: 48em) { 6 | html { 7 | font-size: 18px; 8 | } 9 | } 10 | 11 | /* body { */ 12 | /* font-family: Georgia, "Times New Roman", Times, serif; */ 13 | /* color: #555; */ 14 | /* } */ 15 | 16 | /* h1, .h1, */ 17 | /* h2, .h2, */ 18 | /* h3, .h3, */ 19 | /* h4, .h4, */ 20 | /* h5, .h5, */ 21 | /* h6, .h6 { */ 22 | /* font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; */ 23 | /* font-weight: normal; */ 24 | /* color: #333; */ 25 | /* } */ 26 | 27 | 28 | /* 29 | * Override Bootstrap's default container. 30 | */ 31 | 32 | .container { 33 | max-width: 60rem; 34 | } 35 | 36 | 37 | /* 38 | * Masthead for nav 39 | */ 40 | 41 | .blog-masthead { 42 | margin-bottom: 3rem; 43 | background-color: #428bca; 44 | -webkit-box-shadow: inset 0 -.1rem .25rem rgba(0,0,0,.1); 45 | box-shadow: inset 0 -.1rem .25rem rgba(0,0,0,.1); 46 | } 47 | 48 | /* Nav links */ 49 | .nav-link { 50 | position: relative; 51 | padding: 1rem; 52 | font-weight: 500; 53 | color: #cdddeb; 54 | } 55 | .nav-link:hover, 56 | .nav-link:focus { 57 | color: #fff; 58 | background-color: transparent; 59 | } 60 | 61 | /* Active state gets a caret at the bottom */ 62 | .nav-link.active { 63 | color: #fff; 64 | } 65 | .nav-link.active:after { 66 | position: absolute; 67 | bottom: 0; 68 | left: 50%; 69 | width: 0; 70 | height: 0; 71 | margin-left: -.3rem; 72 | vertical-align: middle; 73 | content: ""; 74 | border-right: .3rem solid transparent; 75 | border-bottom: .3rem solid; 76 | border-left: .3rem solid transparent; 77 | } 78 | 79 | 80 | /* 81 | * Blog name and description 82 | */ 83 | 84 | .blog-header { 85 | padding-bottom: 1.25rem; 86 | margin-bottom: 2rem; 87 | border-bottom: .05rem solid #eee; 88 | } 89 | .blog-title { 90 | margin-bottom: 0; 91 | font-size: 2rem; 92 | font-weight: normal; 93 | } 94 | .blog-description { 95 | font-size: 1.1rem; 96 | color: #999; 97 | } 98 | 99 | @media (min-width: 40em) { 100 | .blog-title { 101 | font-size: 3.5rem; 102 | } 103 | } 104 | 105 | 106 | /* 107 | * Main column and sidebar layout 108 | */ 109 | 110 | /* Sidebar modules for boxing content */ 111 | .sidebar-module { 112 | padding: 1rem; 113 | /*margin: 0 -1rem 1rem;*/ 114 | } 115 | .sidebar-module-inset { 116 | padding: 1rem; 117 | background-color: #f5f5f5; 118 | border-radius: .25rem; 119 | } 120 | .sidebar-module-inset p:last-child, 121 | .sidebar-module-inset ul:last-child, 122 | .sidebar-module-inset ol:last-child { 123 | margin-bottom: 0; 124 | } 125 | 126 | 127 | /* Pagination */ 128 | .blog-pagination { 129 | margin-bottom: 4rem; 130 | } 131 | .blog-pagination > .btn { 132 | border-radius: 2rem; 133 | } 134 | 135 | 136 | /* 137 | * Blog posts 138 | */ 139 | 140 | .blog-post { 141 | margin-bottom: 4rem; 142 | } 143 | .blog-post-title { 144 | margin-bottom: .25rem; 145 | font-size: 2.5rem; 146 | } 147 | .blog-post-meta { 148 | margin-bottom: 1.25rem; 149 | color: #999; 150 | } 151 | 152 | 153 | /* 154 | * Footer 155 | */ 156 | 157 | .blog-footer { 158 | padding: 2.5rem 0; 159 | color: #999; 160 | text-align: center; 161 | background-color: #f9f9f9; 162 | border-top: .05rem solid #e5e5e5; 163 | } 164 | .blog-footer p:last-child { 165 | margin-bottom: 0; 166 | } 167 | 168 | 169 | blockquote { 170 | /* background: #f9f9f9; */ 171 | border-left: 10px solid #ccc; 172 | margin: 1.5em 10px; 173 | padding: 0.5em 10px; 174 | /* quotes: "\201C""\201D""\2018""\2019"; */ 175 | } 176 | /* blockquote:before { */ 177 | /* color: #ccc; */ 178 | /* content: open-quote; */ 179 | /* font-size: 4em; */ 180 | /* line-height: 0.1em; */ 181 | /* margin-right: 0.25em; */ 182 | /* vertical-align: -0.4em; */ 183 | /* } */ 184 | blockquote p { 185 | display: inline; 186 | } 187 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Viscous Demo 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | 24 |
25 |
26 | 27 |
28 |
29 |

Viscous Demo

30 |

A visual data inspector/explorer that runs in constant space, time, and screen space.

31 |
32 |
33 | 34 |
35 | 36 |
37 | 38 |
39 | 40 | 41 |

Load Data

42 | 43 |
44 | 45 |
46 | 47 | 48 | 49 | 50 |
51 |
52 | 53 |
54 | 55 |
56 | 57 | 63 |
64 |
65 | 66 |
67 | 68 | 69 |
70 | 71 | 72 | 73 |
74 |
75 | 76 | 77 |
78 | 79 |
80 |

Viscous

81 | 82 |
83 | 84 |
85 | 86 |
87 |
88 |
89 | 90 | 91 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /resources/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phronmophobic/viscous/7815e80d890d1a7a26e29ff6c311cbad8c847a44/resources/.keep -------------------------------------------------------------------------------- /shadow-cljs.edn: -------------------------------------------------------------------------------- 1 | ;; shadow-cljs configuration 2 | { 3 | :deps {:aliases [:cljs]} 4 | :builds {:app { 5 | :modules {:main {:init-fn com.phronemophobic.viscous.demo/-main}} 6 | ;; :asset-path "js/compiled/out.webgltest" 7 | ;; :output-to "resources/public/js/compiled/webgltest.js" 8 | ;; :output-dir "resources/public/js/compiled/out.webgltest" 9 | :target :browser 10 | ;; :compiler-options 11 | ;; { 12 | ;; :source-map-timestamp true 13 | ;; ;;:optimizations :whitespace 14 | ;; } 15 | }}} 16 | -------------------------------------------------------------------------------- /src/com/phronemophobic/viscous.cljc: -------------------------------------------------------------------------------- 1 | (ns com.phronemophobic.viscous 2 | (:require 3 | [membrane.ui :as ui] 4 | [membrane.basic-components :as basic] 5 | [clojure.string :as str] 6 | [membrane.toolkit :as tk] 7 | #?(:cljs goog.object) 8 | [membrane.alpha.component.drag-and-drop :as dnd] 9 | [membrane.component :refer [defui defeffect] 10 | :as component])) 11 | 12 | (defonce toolkit 13 | (delay 14 | #?(:clj 15 | (if-let [tk (resolve 'membrane.skia/toolkit)] 16 | @tk 17 | @(requiring-resolve 'membrane.java2d/toolkit)) 18 | :cljs 19 | nil))) 20 | 21 | (def paragraph 22 | (resolve 'membrane.skia.paragraph/paragraph)) 23 | (def paragraph-intrinsic-width 24 | (resolve 'membrane.skia.paragraph/intrinsic-width)) 25 | 26 | 27 | 28 | (do 29 | #?@ 30 | (:cljs 31 | [(def monospaced (delay 32 | (ui/font "Ubuntu Mono" 33 | nil))) 34 | (def cell-width) 35 | (def cell-height)] 36 | 37 | :clj 38 | [(def monospaced 39 | (delay 40 | (if (tk/font-exists? @toolkit (ui/font "Menlo" 11)) 41 | (ui/font "Menlo" 11) 42 | (ui/font "monospaced" 11)))) 43 | (def cell-width 44 | (delay 45 | (tk/font-advance-x @toolkit @monospaced " "))) 46 | (def cell-height 47 | (delay 48 | (tk/font-line-height @toolkit @monospaced)))])) 49 | 50 | 51 | 52 | (defprotocol PWrapped 53 | (-unwrap [this])) 54 | 55 | (deftype APWrapped [obj] 56 | #?@(:clj 57 | [ 58 | clojure.lang.IDeref 59 | (deref [_] obj) 60 | 61 | clojure.lang.IHashEq 62 | (hasheq [_] (System/identityHashCode obj)) 63 | (hashCode [_] (System/identityHashCode obj)) 64 | (equals [this that] 65 | (if (instance? APWrapped that) 66 | (identical? obj (-unwrap that)) 67 | false))]) 68 | 69 | PWrapped 70 | (-unwrap [_] 71 | obj)) 72 | 73 | (defn wrap [o] 74 | (->APWrapped o)) 75 | 76 | 77 | (def colors 78 | {:keyword [0.46666666865348816 0.0 0.5333333611488342], 79 | :number 80 | [0.06666667014360428 0.4000000059604645 0.2666666805744171], 81 | :def [0.0 0.0 1.0], 82 | :positive 83 | [0.13333334028720856 0.6000000238418579 0.13333334028720856], 84 | :bracket 85 | [0.6000000238418579 0.6000000238418579 0.46666666865348816], 86 | :comment [0.6666666865348816 0.3333333432674408 0.0], 87 | :attribute [0.0 0.0 0.800000011920929], 88 | :type [0.0 0.5333333611488342 0.3333333432674408], 89 | :quote [0.0 0.6000000238418579 0.0], 90 | :header [0.0 0.0 1.0], 91 | :atom 92 | [0.13333334028720856 0.06666667014360428 0.6000000238418579], 93 | :builtin [0.20000000298023224 0.0 0.6666666865348816], 94 | :hr [0.6000000238418579 0.6000000238418579 0.6000000238418579], 95 | :string-2 [1.0 0.3333333432674408 0.0], 96 | :string 97 | [0.6666666865348816 0.06666667014360428 0.06666667014360428], 98 | :meta [0.3333333432674408 0.3333333432674408 0.3333333432674408], 99 | :tag [0.06666667014360428 0.46666666865348816 0.0], 100 | :qualifier 101 | [0.3333333432674408 0.3333333432674408 0.3333333432674408], 102 | :variable-2 [0.0 0.3333333432674408 0.6666666865348816]}) 103 | 104 | 105 | 106 | (defn indent [n] 107 | (ui/spacer (* n @cell-width) 0)) 108 | 109 | (defn inspector-dispatch [{:keys [obj width height]}] 110 | (if (or (<= width 0) 111 | (<= height 0)) 112 | :no-space 113 | (cond 114 | (string? obj) :string 115 | (integer? obj) :integer 116 | (float? obj) :float 117 | (double? obj) :double 118 | #?@(:clj [(ratio? obj) :ratio]) 119 | (char? obj) :char 120 | (map-entry? obj) :map-entry 121 | (map? obj) :map 122 | (set? obj) :set 123 | (list? obj) :list 124 | (vector? obj) :vector 125 | (symbol? obj) :symbol 126 | (keyword? obj) :keyword 127 | (boolean? obj) :boolean 128 | (nil? obj) :nil 129 | (uuid? obj) :uuid 130 | 131 | (coll? obj) :collection 132 | (seqable? obj) :seqable 133 | (tagged-literal? obj) :tagged-literal 134 | (satisfies? PWrapped obj) :pwrapped 135 | #?@(:clj [(instance? clojure.lang.IDeref obj) :deref]) 136 | (fn? obj) :fn 137 | #?@(:clj [(instance? Throwable obj) :throwable]) 138 | :else :object))) 139 | 140 | 141 | (defmulti inspector* inspector-dispatch) 142 | 143 | (defn ilabel [o width] 144 | (let [s (str o) 145 | len (count s) 146 | shortened 147 | (when (pos? len) 148 | (if (<= len width) 149 | s 150 | (case width 151 | 0 nil 152 | (1 2 3) (subs s 0 (min len width)) 153 | 154 | ;; else 155 | (str (subs s 0 (max 0 156 | (- width 3))) 157 | "..."))))] 158 | (when shortened 159 | (ui/label shortened @monospaced)))) 160 | 161 | (defn split-evenly [width n] 162 | (if (zero? n) 163 | [] 164 | (let [chunk-size (max 1 165 | (int (/ width n)))] 166 | (vec 167 | (reverse 168 | (loop [partitions [] 169 | width width] 170 | (cond 171 | (zero? width) partitions 172 | 173 | (>= (inc (count partitions)) 174 | n) 175 | (conj partitions width) 176 | 177 | :else (recur (conj partitions chunk-size) 178 | (- width chunk-size))))))))) 179 | 180 | (defn split-ratio [width r] 181 | (let [left (int (Math/ceil (* r width))) 182 | right (- width left)] 183 | [left right])) 184 | 185 | (def one-third (/ 1 3)) 186 | (defmethod inspector* :default 187 | [{:keys [obj width height]}] 188 | (let [[left right] (split-ratio width one-third)] 189 | (ui/horizontal-layout 190 | (ilabel (inspector-dispatch {:obj obj 191 | :width width 192 | :height height}) 193 | left) 194 | (ilabel (type obj) 195 | right)))) 196 | 197 | #?(:clj 198 | (defmethod inspector* :throwable 199 | [m] 200 | (inspector* (update m :obj Throwable->map)))) 201 | 202 | (defmethod inspector* :no-space 203 | [{:keys [obj width height]}] 204 | nil) 205 | 206 | (defmethod inspector* :string 207 | [{:keys [obj width height]}] 208 | (let [;; display empty strings as "" 209 | ;; otherwise, they're invisible. 210 | ;; this does mean that empty strings and 211 | ;; the string "\"\"" are indistinguishable. 212 | obj (if (zero? (count obj)) 213 | "\"\"" 214 | obj)] 215 | (if (and paragraph 216 | paragraph-intrinsic-width) 217 | (ui/translate 218 | 0 3 219 | (let [ ;; upper bound 220 | ;; only necessary for very large strings 221 | max-length (* width height) 222 | s (if (> (count obj) max-length) 223 | (subs obj 0 max-length) 224 | obj) 225 | p 226 | (paragraph 227 | s 228 | (* width @cell-width) 229 | {:paragraph-style/max-lines height 230 | :paragraph-style/text-style 231 | {:text-style/color (:string colors) 232 | :text-style/font-size 11 233 | :text-style/font-families ["Menlo" 234 | "monospaced"]}}) 235 | [pw ph] (ui/bounds p) 236 | intrinsic-width (paragraph-intrinsic-width p) 237 | w (min pw intrinsic-width)] 238 | (ui/fixed-bounds [w ph] 239 | p))) 240 | (ui/with-color (:string colors) 241 | (let [s obj 242 | len (count s) 243 | shortened 244 | (when (pos? len) 245 | (if (<= len (- width 2)) 246 | (str "\"" s "\"") 247 | (case width 248 | 0 nil 249 | 250 | 1 "\"" 251 | 252 | (2 3) (str "\"" (subs s 0 (dec width))) 253 | 254 | 4 "\"..." 255 | 256 | ;; else 257 | (str "\"" 258 | (subs s 0 (max 0 259 | (- width 4))) 260 | "..."))))] 261 | (when shortened 262 | (let [shortened (str/replace shortened #"\R" "↵" )] 263 | (ui/label shortened @monospaced)))))))) 264 | 265 | (defn wrap-selection [x path elem] 266 | (ui/wrap-on 267 | :mouse-down 268 | (fn [handler pos] 269 | (let [intents (handler pos)] 270 | (if (seq intents) 271 | intents 272 | [[::dnd/drag-start {::dnd/obj {:path path 273 | :x (wrap x)}}] 274 | [::select x path]]))) 275 | elem)) 276 | 277 | (defn wrap-highlight [path highlight-path elem] 278 | (let [body 279 | (ui/wrap-on 280 | :mouse-move 281 | (fn [handler pos] 282 | (let [intents (handler pos)] 283 | (if (seq intents) 284 | intents 285 | [[::highlight path]]))) 286 | elem)] 287 | (if (= path highlight-path) 288 | (ui/fill-bordered [0.2 0.2 0.2 0.1] 289 | 0 290 | body) 291 | body))) 292 | 293 | ;; There are some data structures that implement Counted in 294 | ;; linear time. Cruel! 295 | (defprotocol IBoundedCount 296 | (-bounded-count [this n])) 297 | 298 | (extend-protocol IBoundedCount 299 | #?(:clj Object 300 | :cljs default) 301 | (-bounded-count [this n] 302 | (bounded-count n this)) 303 | nil 304 | (-bounded-count [this n] 305 | 0)) 306 | 307 | (defn inspector-seq-horizontal [{:keys [obj 308 | width 309 | height 310 | highlight-path 311 | path 312 | offset 313 | open close]}] 314 | (let [open-close-width (+ (count open) 315 | (count close))] 316 | (when (> width open-close-width ) 317 | (let [body 318 | (loop [body [] 319 | i 0 320 | width (- width 321 | (count open) 322 | (count close)) 323 | ;; lazy sequences can throw here 324 | obj (try 325 | (seq obj) 326 | (catch #?(:clj Exception :cljs js/Error) e 327 | e))] 328 | (if (instance? #?(:clj Exception :cljs js/Error) obj) 329 | (conj body 330 | (inspector* {:obj obj 331 | :height height 332 | :width width 333 | :highlight-path highlight-path 334 | :path path})) 335 | (if (or (not obj) 336 | (<= width 0)) 337 | body 338 | (let [x (first obj) 339 | child-path (if (map-entry? x) 340 | (list 'find (key x)) 341 | (list 'nth i)) 342 | path (conj path 343 | child-path) 344 | elem 345 | (wrap-highlight 346 | path 347 | highlight-path 348 | (wrap-selection 349 | x 350 | path 351 | (inspector* {:obj x 352 | :height 1 353 | :highlight-path highlight-path 354 | :path path 355 | :width width}))) 356 | pix-width (ui/width elem) 357 | elem-width (int (Math/ceil (/ pix-width 358 | @cell-width)))] 359 | (recur (conj body elem) 360 | (inc i) 361 | (- width elem-width 362 | ;; add a space between elements 363 | 1 364 | ) 365 | ;; lazy sequences can throw here 366 | (try 367 | (next obj) 368 | (catch #?(:clj Exception :cljs js/Error) e 369 | e)))))))] 370 | (ui/horizontal-layout 371 | (ui/with-color (:bracket colors) 372 | (ilabel open (count open))) 373 | (when (pos? (count body)) 374 | (apply ui/horizontal-layout 375 | (interpose (indent 1) 376 | body))) 377 | (let [len (try 378 | (-bounded-count obj (inc (count body))) 379 | (catch #?(:clj Exception :cljs js/Error) e 380 | nil))] 381 | (when (= (count body) len) 382 | (ui/with-color (:bracket colors) 383 | (ilabel close (count close)))))))))) 384 | 385 | (def chunk-size 32) 386 | (defn inspector-seq [{:keys [obj 387 | width 388 | height 389 | highlight-path 390 | path 391 | offset 392 | open close] 393 | :as m}] 394 | (let [offset (or offset 0)] 395 | (if (<= height 3) 396 | (inspector-seq-horizontal m) 397 | (let [;; realize elements 398 | ;; lazy sequences can throw errors here 399 | chunk (try 400 | (loop [obj (seq (if (pos? offset) 401 | (drop offset obj) 402 | obj)) 403 | chunk []] 404 | (if (or (not obj) 405 | (>= (count chunk) 406 | chunk-size)) 407 | chunk 408 | (let [x (first obj)] 409 | (let [next-obj 410 | ;; lazy sequences can throw here 411 | (try 412 | (next obj) 413 | (catch #?(:clj Exception :cljs js/Error) e 414 | e))] 415 | (if (instance? #?(:clj Exception :cljs js/Error) next-obj) 416 | (conj chunk next-obj) 417 | (recur next-obj 418 | (conj chunk x))))))) 419 | (catch #?(:clj Exception :cljs js/Error) e 420 | e)) 421 | 422 | has-previous? (pos? offset) 423 | has-next? (let [len 424 | ;; lazy sequences can throw here 425 | (try 426 | (-bounded-count (drop offset obj) 427 | (inc chunk-size)) 428 | (catch #?(:clj Exception :cljs js/Error) e 429 | (println e) 430 | nil))] 431 | (and len 432 | (or (> len chunk-size) 433 | (> len (- height 434 | ;; open and close 435 | 2 436 | (if has-previous? 437 | 1 438 | 0)))))) 439 | 440 | children 441 | (if (instance? #?(:clj Exception :cljs js/Error) chunk) 442 | (inspector* {:obj chunk 443 | :height height 444 | :width width 445 | :highlight-path highlight-path 446 | :path path}) 447 | (let [heights (split-evenly 448 | ;; space for children is 449 | (- height 450 | ;; open and close 451 | 2 452 | (if has-previous? 1 0) 453 | (if has-next? 1 0) 454 | ) 455 | (count chunk))] 456 | (->> chunk 457 | (map (fn [i height obj] 458 | (let [child-path (if (map-entry? obj) 459 | (list 'find (key obj)) 460 | (list 'nth i)) 461 | path (conj path 462 | child-path) 463 | body 464 | (wrap-highlight 465 | path 466 | highlight-path 467 | (wrap-selection obj 468 | path 469 | (inspector* {:obj obj 470 | :height height 471 | :path path 472 | :highlight-path highlight-path 473 | :width (dec width)})))] 474 | (if (= path highlight-path) 475 | (ui/fill-bordered [0.2 0.2 0.2 0.1] 476 | 0 477 | body) 478 | body))) 479 | (range) 480 | heights) 481 | (apply ui/vertical-layout))))] 482 | (cond 483 | (instance? #?(:clj Exception :cljs js/Error) chunk) 484 | children 485 | 486 | (empty? chunk) 487 | (ui/with-color (:bracket colors) 488 | (ilabel (str open close) width)) 489 | 490 | ;; else not empty 491 | :else 492 | (ui/vertical-layout 493 | (ui/with-color (:bracket colors) 494 | (ilabel open width)) 495 | (ui/translate @cell-width 0 496 | (ui/vertical-layout 497 | (when has-previous? 498 | (ui/on 499 | :mouse-down 500 | (fn [_] 501 | ;; only for top level 502 | (when (empty? path) 503 | [[::previous-chunk]])) 504 | (ilabel "..." 3))) 505 | children 506 | (when has-next? 507 | (ui/on 508 | :mouse-down 509 | (fn [_] 510 | ;; only for top level 511 | (when (empty? path) 512 | [[::next-chunk (count children)]])) 513 | (ilabel "..." 3))) 514 | )) 515 | (ui/with-color (:bracket colors) 516 | (ilabel close width)))))))) 517 | 518 | 519 | (defmethod inspector* :vector 520 | [{:keys [obj width height] :as m}] 521 | (inspector-seq (assoc m 522 | :open "[" 523 | :close "]"))) 524 | 525 | (defmethod inspector* :seqable 526 | [{:keys [obj width height] :as m}] 527 | (inspector-seq (assoc m 528 | :open "(" 529 | :close ")"))) 530 | 531 | (defmethod inspector* :collection 532 | [{:keys [obj width height] :as m}] 533 | (inspector-seq (assoc m 534 | :open "(" 535 | :close ")"))) 536 | 537 | (defmethod inspector* :list 538 | [{:keys [obj width height] :as m}] 539 | (inspector-seq (assoc m 540 | :open "(" 541 | :close ")"))) 542 | 543 | (defmethod inspector* :set 544 | [{:keys [obj width height] :as m}] 545 | (inspector-seq (assoc m 546 | :open "#{" 547 | :close "}"))) 548 | 549 | 550 | 551 | (defmethod inspector* :map 552 | [{:keys [obj width height] :as m}] 553 | (inspector-seq (assoc m 554 | :open "{" 555 | :close "}")) 556 | ) 557 | 558 | #? 559 | (:cljs 560 | (defn ->map-entry [obj k] 561 | (MapEntry. k (goog.object/get obj k) nil))) 562 | 563 | #? 564 | (:cljs 565 | (defmethod inspector* :object 566 | [{:keys [obj width height] :as m}] 567 | (inspector-seq (assoc m 568 | :obj (map #(->map-entry obj %) (js-keys obj)) 569 | :open "{" 570 | :close "}")))) 571 | 572 | 573 | (defn inspector-keyword [{:keys [obj width height]}] 574 | (let [ns (namespace obj) 575 | [left right] (if ns 576 | (split-ratio (- width 2) one-third) 577 | [0 (- width 1)])] 578 | (ui/with-color (:keyword colors) 579 | (ui/horizontal-layout 580 | (ilabel ":" 1) 581 | (when ns 582 | (ui/horizontal-layout 583 | (ilabel ns left) 584 | (ilabel "/" 1))) 585 | (ilabel (name obj) right))))) 586 | (defmethod inspector* :keyword 587 | [{:keys [obj width height] :as m}] 588 | (inspector-keyword m)) 589 | 590 | 591 | (defn inspector-map-entry [{:keys [obj width height path highlight-path]}] 592 | (let [[left right] (split-ratio (- width 2) one-third) 593 | [k v] obj] 594 | (ui/horizontal-layout 595 | (let [child-path (conj path '(key))] 596 | (wrap-highlight 597 | child-path 598 | highlight-path 599 | (wrap-selection k 600 | child-path 601 | (inspector* {:obj k 602 | :height height 603 | :path child-path 604 | :highlight-path highlight-path 605 | :width left})))) 606 | (indent 1) 607 | (let [child-path (conj path '(val))] 608 | (wrap-highlight 609 | child-path 610 | highlight-path 611 | (wrap-selection v 612 | child-path 613 | (inspector* {:obj v 614 | :height height 615 | :path child-path 616 | :highlight-path highlight-path 617 | :width right}))))))) 618 | (defmethod inspector* :map-entry 619 | [{:keys [obj width height] :as m}] 620 | (inspector-map-entry m)) 621 | 622 | 623 | #? 624 | (:clj 625 | (defn inspector-deref [{:keys [obj width height path highlight-path]}] 626 | (let [[left right] (split-ratio (- width 2) one-third) 627 | k (symbol (.getName (class obj))) 628 | v (if (instance? clojure.lang.IPending obj) 629 | (if (realized? obj) 630 | @obj 631 | "unrealized?") 632 | (deref obj))] 633 | (ui/horizontal-layout 634 | (indent 1) 635 | (inspector* {:obj k 636 | :height height 637 | :width left}) 638 | (indent 1) 639 | (let [child-path (conj path '(deref))] 640 | (wrap-highlight 641 | child-path 642 | highlight-path 643 | (wrap-selection v 644 | child-path 645 | (inspector* {:obj v 646 | :height height 647 | :path child-path 648 | :highlight-path highlight-path 649 | :width right})))))))) 650 | #? 651 | (:clj 652 | (defmethod inspector* :deref 653 | [{:keys [obj width height] :as m}] 654 | (inspector-deref m))) 655 | 656 | 657 | (defn inspector-tagged-literal [{:keys [obj width height path highlight-path]}] 658 | (let [[left right] (split-ratio (- width 2) one-third) 659 | tag (:tag obj) 660 | form (:form obj)] 661 | (ui/horizontal-layout 662 | (when (pos? width) 663 | (ui/label "#")) 664 | (inspector* {:obj tag 665 | :height height 666 | :width left}) 667 | (indent 1) 668 | (let [child-path path] 669 | (wrap-highlight 670 | child-path 671 | highlight-path 672 | (wrap-selection form 673 | child-path 674 | (inspector* {:obj form 675 | :height height 676 | :path child-path 677 | :highlight-path highlight-path 678 | :width right}))))))) 679 | 680 | (defmethod inspector* :tagged-literal 681 | [{:keys [obj width height] :as m}] 682 | (inspector-tagged-literal m)) 683 | 684 | (defn inspector-uuid [{:keys [obj width height path highlight-path]}] 685 | (let [[left right] (split-ratio (- width 1) one-third) 686 | tag (symbol "#uuid")] 687 | (ui/horizontal-layout 688 | (inspector* {:obj tag 689 | :height height 690 | :width left}) 691 | (indent 1) 692 | (let [child-path (conj path '(str))] 693 | (wrap-highlight 694 | child-path 695 | highlight-path 696 | (wrap-selection (str obj) 697 | child-path 698 | (inspector* {:obj (str obj) 699 | :height height 700 | :path child-path 701 | :highlight-path highlight-path 702 | :width right}))))))) 703 | 704 | (defmethod inspector* :uuid 705 | [{:keys [obj width height] :as m}] 706 | (inspector-uuid m)) 707 | 708 | (defn inspector-pwrapped [{:keys [obj width height path highlight-path]}] 709 | (let [[left right] (split-ratio (- width 2) one-third) 710 | k 'PWrapped 711 | v (-unwrap obj)] 712 | (ui/horizontal-layout 713 | (indent 1) 714 | (inspector* {:obj k 715 | :height height 716 | :width left}) 717 | (indent 1) 718 | (let [child-path (conj path '(-unwrap))] 719 | (wrap-highlight 720 | child-path 721 | highlight-path 722 | (wrap-selection v 723 | child-path 724 | (inspector* {:obj v 725 | :height height 726 | :path child-path 727 | :highlight-path highlight-path 728 | :width right}))))))) 729 | 730 | (defmethod inspector* :pwrapped 731 | [{:keys [obj width height] :as m}] 732 | (inspector-pwrapped m)) 733 | 734 | (defn inspector-fn [{:keys [obj width height]}] 735 | (ilabel "#function" width)) 736 | 737 | (defmethod inspector* :fn 738 | [{:keys [obj width height] :as m}] 739 | (inspector-fn m)) 740 | 741 | 742 | (defn inspector-symbol [{:keys [obj width height]}] 743 | (let [ns (namespace obj) 744 | [left right] (if ns 745 | (split-ratio (- width 1) one-third) 746 | [0 width])] 747 | (ui/with-color (:qualifier colors) 748 | (ui/horizontal-layout 749 | (when ns 750 | (ui/horizontal-layout 751 | (ilabel ns left) 752 | (ilabel "/" 1))) 753 | (ilabel (name obj) right))))) 754 | (defmethod inspector* :symbol 755 | [{:keys [obj width height] :as m}] 756 | (inspector-symbol m)) 757 | 758 | 759 | (defn inspector-integer [{:keys [obj width height]}] 760 | (ui/with-color (:number colors) 761 | (ilabel obj width))) 762 | (defmethod inspector* :integer 763 | [{:keys [obj width height] :as m}] 764 | (inspector-integer m)) 765 | 766 | (defn inspector-float [{:keys [obj width height]}] 767 | (ui/with-color (:number colors) 768 | (ilabel obj width))) 769 | (defmethod inspector* :float 770 | [{:keys [obj width height] :as m}] 771 | (inspector-float m)) 772 | 773 | (defn inspector-double [{:keys [obj width height]}] 774 | (ui/with-color (:number colors) 775 | (ilabel obj width))) 776 | (defmethod inspector* :double 777 | [{:keys [obj width height] :as m}] 778 | (inspector-double m)) 779 | 780 | (defn inspector-ratio [{:keys [obj width height]}] 781 | (ui/with-color (:number colors) 782 | (ilabel obj width))) 783 | (defmethod inspector* :ratio 784 | [{:keys [obj width height] :as m}] 785 | (inspector-ratio m)) 786 | 787 | 788 | (defn inspector-char [{:keys [obj width height]}] 789 | (ui/with-color (:string colors) 790 | (ui/horizontal-layout 791 | (ilabel "\\" 1) 792 | (ilabel obj (dec width))))) 793 | (defmethod inspector* :char 794 | [{:keys [obj width height] :as m}] 795 | (inspector-char m)) 796 | 797 | (defn inspector-boolean [{:keys [obj width height]}] 798 | (ui/with-color (:number colors) 799 | (ui/horizontal-layout 800 | (ilabel obj width)))) 801 | (defmethod inspector* :boolean 802 | [{:keys [obj width height] :as m}] 803 | (inspector-boolean m)) 804 | 805 | (defn inspector-nil [{:keys [obj width height]}] 806 | (ilabel "nil" width)) 807 | (defmethod inspector* :nil 808 | [{:keys [obj width height] :as m}] 809 | (inspector-nil m)) 810 | 811 | 812 | (defui wrap-resizing [{:keys [resizing? 813 | width 814 | height 815 | body]}] 816 | (if-not resizing? 817 | body 818 | (let [w (+ (* width @cell-width)) 819 | h (+ (* height @cell-height)) 820 | temp-width (get extra ::temp-width w) 821 | temp-height (get extra ::temp-height h)] 822 | (ui/on 823 | :mouse-up 824 | (fn [_] 825 | [[:set $resizing? false]]) 826 | :mouse-move-global 827 | (fn [[x y]] 828 | [[:set $width (int (/ x @cell-width))] 829 | [:set $height (int (/ y @cell-height))] 830 | [:set $temp-width x] 831 | [:set $temp-height y]]) 832 | (ui/no-events 833 | [body 834 | (ui/with-color [0.2 0.2 0.2 0.2] 835 | (ui/with-style :membrane.ui/style-stroke 836 | (ui/rectangle w h))) 837 | (ui/spacer (+ temp-width 5) 838 | (+ temp-height 5))]))))) 839 | 840 | (defn wrap-drag-start [{:keys [obj path stack]} body] 841 | (ui/on 842 | ::dnd/drag-start 843 | (fn [m] 844 | (let [full-path 845 | (into [] 846 | cat 847 | [path 848 | (-> m ::dnd/obj :path)])] 849 | [[::dnd/drag-start 850 | (update m 851 | ::dnd/obj 852 | #(assoc % 853 | :obj obj 854 | :path full-path))]])) 855 | body)) 856 | 857 | (defui inspector [{:keys [obj width height show-context?] 858 | :or {width 40 859 | height 1}}] 860 | (let [stack (get extra [obj :stack] []) 861 | path (get extra [obj :path] []) 862 | offsets (get extra [obj :offsets] [0]) 863 | offset (peek offsets) 864 | specimen (get extra [obj :specimen] obj) 865 | resizing? (get extra :resizing?) 866 | highlight-path (get extra [obj :highlight-path])] 867 | (wrap-drag-start 868 | {:obj obj 869 | :path path 870 | :stack stack} 871 | (ui/vertical-layout 872 | (when show-context? 873 | (ui/vertical-layout 874 | (basic/button {:text "pop" 875 | :on-click 876 | (fn [] 877 | (when (seq stack) 878 | (let [{next-specimen :specimen 879 | next-path :path 880 | next-offsets :offets} (peek stack)] 881 | [[:set $specimen next-specimen] 882 | [:set $path next-path] 883 | [:set $offsets next-offsets] 884 | [:update $stack pop]])))}) 885 | (basic/button {:text "resizing" 886 | :on-click 887 | (fn [] 888 | [[:set $resizing? true]])}) 889 | (ui/label (str "offset: " offset)) 890 | (ui/label (str "path: " (pr-str path) )))) 891 | (wrap-resizing 892 | {:resizing? resizing? 893 | :width width 894 | :height height 895 | :body 896 | (let [elem 897 | (ui/on 898 | ::highlight 899 | (fn [path] 900 | [[:set $highlight-path path]]) 901 | ::previous-chunk 902 | (fn [] 903 | [[:update $offsets 904 | (fn [offsets] 905 | (if (> (count offsets) 1) 906 | (pop offsets) 907 | offsets))]]) 908 | ::next-chunk 909 | (fn [delta] 910 | [[:update $offsets 911 | (fn [offsets] 912 | (let [offset (peek offsets)] 913 | (conj offsets (+ offset delta))))]]) 914 | 915 | ::select 916 | (fn [x child-path] 917 | [[:update $stack conj {:specimen specimen 918 | :path path 919 | :offsets offsets}] 920 | [:delete $highlight-path] 921 | [:update $path into child-path] 922 | [:set $offsets [0]] 923 | [:set $specimen (wrap x)]]) 924 | (ui/wrap-on 925 | :mouse-down 926 | (fn [handler pos] 927 | (let [intents (handler pos)] 928 | (if (seq intents) 929 | intents 930 | [[::dnd/drag-start {::dnd/obj {:x specimen}}]]))) 931 | :mouse-move 932 | (fn [handler pos] 933 | (let [intents (handler pos)] 934 | (if (seq intents) 935 | intents 936 | [[:set $highlight-path nil]]))) 937 | (inspector* {:obj (-unwrap specimen) 938 | :height height 939 | :path [] 940 | :offset offset 941 | :highlight-path highlight-path 942 | :width width} ))) 943 | [ew eh] (ui/bounds elem) 944 | pop-button 945 | (ui/on 946 | :mouse-down 947 | (fn [_] 948 | (if (seq stack) 949 | (let [{next-specimen :specimen 950 | next-path :path 951 | next-offsets :offets} (peek stack)] 952 | [[:set $specimen next-specimen] 953 | [:set $path next-path] 954 | [:set $offsets next-offsets] 955 | [:update $stack pop]]) 956 | [[:delete $specimen] 957 | [:delete $path] 958 | [:delete $offsets] 959 | [:delete $stack]])) 960 | (ui/filled-rectangle [0 0 1 0.25] 961 | 8 8)) 962 | resize-button 963 | (ui/on 964 | :mouse-down 965 | (fn [_] 966 | [[:set $resizing? true]]) 967 | (ui/filled-rectangle [1 0 0 0.25] 968 | 8 8)) 969 | [rw rh] (ui/bounds resize-button)] 970 | [elem 971 | (ui/translate (- (* width @cell-width) 972 | rw) 973 | (- (* height @cell-height) 974 | rh) 975 | resize-button) 976 | (ui/translate (- (* width @cell-width) 977 | (* 2 rw)) 978 | (- (* height @cell-height) 979 | rh) 980 | pop-button)])}))))) 981 | 982 | 983 | 984 | 985 | 986 | (defn inspect 987 | "Open an inspector window to view obj." 988 | ([obj] 989 | (inspect obj {})) 990 | ([obj {:keys [width height show-context? sync?] :as opts 991 | :or {show-context? true}}] 992 | (let [width (or width 80) 993 | height (or height 40) 994 | app (component/make-app #'inspector 995 | {:obj (wrap obj) 996 | :width width 997 | :show-context? show-context? 998 | :height height}) 999 | 1000 | [empty-width empty-height] (ui/bounds ((component/make-app #'inspector 1001 | {:obj (wrap nil) 1002 | :width 0 1003 | :height 0}))) 1004 | window-width (+ 50 1005 | (max empty-width 1006 | (* @cell-width width))) 1007 | window-height (+ 100 1008 | empty-height 1009 | height 1010 | (* @cell-height (inc height))) 1011 | run (if sync? 1012 | tk/run-sync 1013 | tk/run)] 1014 | (run @toolkit 1015 | app 1016 | {:window-title "Inspect" 1017 | :window-start-width window-width 1018 | :window-start-height window-height})))) 1019 | 1020 | 1021 | 1022 | (comment 1023 | [clojure.spec.alpha :as s] 1024 | [clojure.spec.gen.alpha :as gen] 1025 | (s/def ::anything any? ) 1026 | 1027 | (do 1028 | (def obj (gen/generate (s/gen ::anything) ) 1029 | ) 1030 | (inspect (gen/sample (s/gen ::anything) 1031 | 100)) 1032 | obj) 1033 | 1034 | (backend/run #'inspector-test) 1035 | ,) 1036 | 1037 | 1038 | (comment 1039 | (require '[pl.danieljanus.tagsoup :as tagsoup]) 1040 | (require '[clojure.data.json :as json]) 1041 | 1042 | (inspect (read-string (slurp "deps.edn"))) 1043 | 1044 | (inspect ((requiring-resolve 'pl.danieljanus.tagsoup/parse-string) (slurp "https://clojure.org/reference/reader")) 1045 | {:height 10}) 1046 | 1047 | (inspect (gen/generate (s/gen ::anything))) 1048 | 1049 | (inspect (json/read-str (slurp "https://raw.githubusercontent.com/dreadwarrior/ext-giftcertificates/5e447a7316aea57a372203f2aa8de5aef3af671a/ExtensionBuilder.json")) ) 1050 | 1051 | , 1052 | ) 1053 | 1054 | (comment 1055 | (def a (atom nil)) 1056 | (def b (atom a)) 1057 | (reset! a b) 1058 | (inspect a) 1059 | ,) 1060 | 1061 | -------------------------------------------------------------------------------- /src/com/phronemophobic/viscous/cli.clj: -------------------------------------------------------------------------------- 1 | (ns com.phronemophobic.viscous.cli 2 | (:require [com.phronemophobic.viscous :as viscous] 3 | [clojure.edn :as edn] 4 | [clojure.java.io :as io]) 5 | (:import java.io.PushbackReader 6 | java.io.StringReader)) 7 | 8 | (defn read-edn [rdr] 9 | (with-open [rdr (java.io.PushbackReader. rdr)] 10 | (edn/read {:default tagged-literal} rdr))) 11 | 12 | 13 | (defn read-json [rdr] 14 | (with-open [rdr rdr] 15 | ((requiring-resolve 'clojure.data.json/read) rdr))) 16 | 17 | (def help-text 18 | "Open a viscous data inspector. 19 | 20 | Usage: 21 | 22 | Read edn from stdin: 23 | cat data.edn | clojure -X:viscous :file - 24 | 25 | Read edn from filename: 26 | clojure -X:viscous :file data.edn 27 | 28 | Read json from stdin: 29 | cat data.json | clojure -X:viscous :json-file - 30 | 31 | Read json from filename: 32 | clojure -X:viscous :json-file data.edn 33 | ") 34 | 35 | (defn main [{:keys [file edn json-file json] :as opts}] 36 | (let [obj 37 | (cond 38 | (= (str file) "-") (read-edn (io/reader *in*)) 39 | file (read-edn (io/reader (str file))) 40 | edn (read-edn (StringReader. (str edn))) 41 | 42 | (= (str json-file) "-") (read-json (io/reader *in*)) 43 | json-file (read-json (io/reader (str json-file))) 44 | json (read-json (StringReader. (str json))) 45 | 46 | :else ::print-help)] 47 | (if (= obj ::print-help) 48 | (println help-text) 49 | (viscous/inspect obj 50 | (merge 51 | (select-keys opts [:width :height :show-context?]) 52 | {:sync? true}))))) 53 | -------------------------------------------------------------------------------- /src/com/phronemophobic/viscous/demo.cljs: -------------------------------------------------------------------------------- 1 | (ns com.phronemophobic.viscous.demo 2 | (:require 3 | [membrane.ui :as ui] 4 | [goog.net.XhrIo :as xhr] 5 | clojure.edn 6 | [membrane.basic-components :as basic] 7 | [com.phronemophobic.viscous :as viscous] 8 | [membrane.webgl :as webgl] 9 | [membrane.component :refer [defui defeffect] 10 | :as component])) 11 | 12 | 13 | (defn $ [id] 14 | (js/document.getElementById id)) 15 | 16 | (def blob-area ($ "blobarea")) 17 | (def update-btn ($ "update-btn")) 18 | (def url-input ($ "url-input")) 19 | (def fetch-example-select ($ "fetch-example-select")) 20 | (def fetch-btn ($ "fetch-btn")) 21 | (def fetch-example-btn ($ "fetch-example-btn")) 22 | 23 | (def obj {:a {:b 42}}) 24 | (def width 80) 25 | (def height 40) 26 | (defonce repaint nil) 27 | (defonce demo-state (atom {:obj (viscous/wrap obj) 28 | :width 80 29 | :height 40 30 | :show-context? true})) 31 | (defn update-viscous [obj err] 32 | (swap! demo-state 33 | (fn [state] 34 | (-> state 35 | (assoc :obj (viscous/wrap obj)) 36 | (dissoc :membrane.component/extra)))) 37 | (repaint)) 38 | 39 | (defn parse-edn-or-json [s] 40 | (try 41 | [nil (clojure.edn/read-string {:default (fn [tag x] 42 | x)} 43 | s)] 44 | (catch js/Object edn-error 45 | (prn edn-error) 46 | (try 47 | [nil (js/JSON.parse s)] 48 | (catch js/Object json-error 49 | (prn json-error) 50 | [[edn-error json-error] 51 | nil]))))) 52 | 53 | (defonce button-listen (.addEventListener 54 | update-btn 55 | "click" 56 | (fn [] 57 | (let [blob (.-value blob-area) 58 | [errs obj] (parse-edn-or-json blob)] 59 | (update-viscous obj errs))))) 60 | 61 | 62 | 63 | (defonce fetch-listen (.addEventListener 64 | fetch-btn 65 | "click" 66 | (fn [] 67 | (let [url (.-value url-input)] 68 | (xhr/send url 69 | (fn [e] 70 | (let [x (.-target e) 71 | [errs obj] (parse-edn-or-json (.getResponseText ^js x))] 72 | (update-viscous obj errs)))))))) 73 | 74 | (defonce fetch-example-listen (.addEventListener 75 | fetch-example-btn 76 | "click" 77 | (fn [] 78 | (let [url (.-value fetch-example-select)] 79 | (xhr/send url 80 | (fn [e] 81 | (let [x (.-target e) 82 | [errs obj] (parse-edn-or-json (.getResponseText ^js x))] 83 | (update-viscous obj errs)))))))) 84 | 85 | 86 | 87 | (def canvas (.getElementById js/document "canvas")) 88 | (defn -main [] 89 | (webgl/load-font 90 | (:name @viscous/monospaced) 91 | "https://fonts.googleapis.com/css2?family=Ubuntu+Mono&display=swap" 92 | "https://fonts.gstatic.com/s/ubuntumono/v6/EgeuS9OtEmA0y_JRo03MQaCWcynf_cDxXwCLxiixG1c.ttf" 93 | 94 | (fn [] 95 | (let [freetype-font (webgl/get-font @viscous/monospaced) 96 | space-glyph (-> freetype-font 97 | (.-glyphs) 98 | (.-glyphs) 99 | (aget 3)) 100 | font-size (:size ui/default-font) 101 | fscale (membrane.webgl/font-scale freetype-font font-size) 102 | advance (* fscale (.-advanceWidth space-glyph))] 103 | (set! viscous/cell-width (delay advance)) 104 | (set! viscous/cell-height (delay (membrane.webgl/font-line-height @viscous/monospaced)))) 105 | 106 | #_(js/console.log (-> (.-fonts js/document) 107 | (.load (str 108 | (:size ui/default-font) "px" 109 | " " 110 | "\"Ubuntu Mono\"" 111 | ;;(:name ui/default-font) 112 | )))) 113 | 114 | (let [ 115 | 116 | app (component/make-app #'viscous/inspector 117 | demo-state) 118 | 119 | [empty-width empty-height] (ui/bounds ((component/make-app #'viscous/inspector 120 | {:obj (viscous/wrap nil) 121 | :width 0 122 | :height 0}))) 123 | window-width (max empty-width 124 | (* @viscous/cell-width width)) 125 | window-height (+ empty-height 126 | height 127 | (* @viscous/cell-height (inc height)))] 128 | (defonce canvas-info (membrane.webgl/run 129 | app 130 | {:container canvas})) 131 | (set! repaint (:membrane.webgl/repaint canvas-info)))))) 132 | 133 | -------------------------------------------------------------------------------- /test/com/phronemophobic/membrane/pretty_view_test.clj: -------------------------------------------------------------------------------- 1 | (ns com.phronemophobic.membrane.pretty-view-test 2 | (:require [clojure.test :refer :all] 3 | [com.phronemophobic.membrane.pretty-view :refer :all])) 4 | 5 | (deftest a-test 6 | (testing "FIXME, I fail." 7 | (is (= 0 1)))) 8 | --------------------------------------------------------------------------------