forked from metabase/metabase
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from getjerry/jerry/pii_masking
Jerry/pii masking
- Loading branch information
Showing
5,057 changed files
with
502,192 additions
and
208,957 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Update `clj-kondo` configs for libraries using | ||
|
||
```sh | ||
clj-kondo --copy-configs --dependencies --lint "$(clojure -Spath -A:dev)" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{:lint-as {babashka.fs/with-temp-dir clojure.core/let}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{:hooks {:macroexpand {sci.core/copy-ns sci.core/copy-ns}}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
(ns sci.core) | ||
|
||
(defmacro copy-ns | ||
([ns-sym sci-ns] | ||
`(copy-ns ~ns-sym ~sci-ns nil)) | ||
([ns-sym sci-ns opts] | ||
`[(quote ~ns-sym) | ||
~sci-ns | ||
(quote ~opts)])) |
145 changes: 145 additions & 0 deletions
145
.clj-kondo/better-cond/better-cond/better_cond/core.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
(ns better-cond.core | ||
"A clj-kondo hook to allow linting of better-cond `cond` macro. | ||
This supports better-cond version 2.0.0+. | ||
To use in a project, change the namespace to hooks.better-cond, | ||
put this code in file .clj-kondo/hooks/better_cond.clj, and include | ||
a config.edn entry in the :hooks key like: | ||
:hooks {:analyze-call {better-cond.core/cond hooks.better-cond/cond}} | ||
Note that the expansion of :when-let and :when-some forms currently | ||
takes a shortcut that *would* lead to incorrect values in some | ||
cases of restructuring during actual expansion/evaluation, e.g., | ||
:when-let [[x y] nil] would not abort the cond, though :when-let | ||
[[x y] [nil nil]] would. However, for linting purposes, the current | ||
expansion approach works just fine. It seems unnecessary to do the | ||
full expansion in these cases for linting purposes, though that could | ||
be done if needed." | ||
(:refer-clojure :exclude [cond]) | ||
(:require | ||
[clj-kondo.hooks-api :as api] | ||
[clojure.string :as str])) | ||
|
||
(def better-cond-simple-keys | ||
"Special constructs in better cond, either as keywords or symbols. | ||
This includes those keys that are simply transformed. Note that | ||
:when-let and :when-some are *not* included as better-cond allows | ||
multiple bindings but clojure does not. These two must be handled | ||
separately." | ||
#{:let :when :do | ||
'let 'when 'do}) | ||
|
||
(def better-cond-complex-keys | ||
"Special constructs in better cond, either as keywords or symbols. | ||
This includes those keys that require a multi-step transformation. | ||
For example, :when-let and :when-some get converted to a let | ||
wrapping a when, wrapping the continuing cond. Note that clojure | ||
does not support multiple bindings in the standard when-let and | ||
when-some macros." | ||
{:when-let 'identity | ||
'when-let 'identity | ||
:when-some 'some? | ||
'when-some 'some?}) | ||
|
||
(defn extract-binding-forms | ||
[bindings] | ||
(keep-indexed #(when (even? %1) %2) bindings)) | ||
|
||
(defn process-pairs | ||
"Transforms a `cond` with the clauses given as a collection of explicit pairs. | ||
Handles all the special better-cond constructs as keywords or symbols. | ||
Returns a rewrite-clj list-node representing the transformed code." | ||
[node-pairs] | ||
(loop [[[lhs rhs :as pair] & pairs] node-pairs | ||
new-body [(api/token-node 'clojure.core/cond)]] ; Avoid reprocessing the cond with ns here | ||
(if pair | ||
(let [lhs-sexpr (api/sexpr lhs)] | ||
(clojure.core/cond | ||
(= 1 (count pair)) ;; better-cond allows single clause for default | ||
, (api/list-node (conj new-body (api/keyword-node :else) lhs)) | ||
(better-cond-simple-keys lhs-sexpr) ;; Handle special better-cond constructs | ||
, (api/list-node | ||
(conj new-body | ||
(api/keyword-node :else) | ||
(api/list-node [(api/token-node (symbol #_"clojure.core" (name lhs-sexpr))) | ||
rhs | ||
(process-pairs pairs)]))) | ||
(better-cond-complex-keys lhs-sexpr) ;; Multi stage constructs | ||
, (api/list-node | ||
(conj new-body | ||
(api/keyword-node :else) | ||
(api/list-node [(api/token-node 'let) | ||
rhs | ||
(api/list-node [(api/token-node 'when) | ||
(api/list-node ;; ATTN: shortcut here; fine for linting | ||
[(api/token-node 'every?) | ||
(api/token-node (better-cond-complex-keys lhs-sexpr)) | ||
(api/vector-node (->> rhs | ||
api/sexpr | ||
extract-binding-forms | ||
(map api/token-node)))]) | ||
(process-pairs pairs)])]))) | ||
:else | ||
, (recur pairs (conj new-body lhs rhs)))) | ||
(api/list-node new-body)))) | ||
|
||
(defn cond-hook | ||
[{:keys [node]}] | ||
(let [expr (let [args (rest (:children node)) | ||
pairs (partition-all 2 args)] | ||
(process-pairs pairs))] | ||
{:node (with-meta expr | ||
(meta node))})) | ||
|
||
(defn process-if-let-pairs [pairs then else] | ||
(if (seq pairs) | ||
(let [[lhs rhs] (first pairs)] | ||
(if (and (api/keyword-node? lhs) | ||
(= :let (api/sexpr lhs))) | ||
(api/list-node (conj [(api/token-node 'clojure.core/let) rhs | ||
(process-if-let-pairs (next pairs) then else)])) | ||
(let [test (api/token-node (gensym "test"))] | ||
(api/list-node | ||
(conj [(api/token-node 'clojure.core/let) (api/vector-node [test rhs]) | ||
(api/list-node [(api/token-node 'if) test | ||
(api/list-node | ||
[(api/token-node 'clojure.core/let) | ||
(api/vector-node [lhs test]) | ||
(process-if-let-pairs (next pairs) then else)]) | ||
else])]))))) | ||
then)) | ||
|
||
(defn if-let-hook | ||
[{:keys [node]}] | ||
(let [expr (let [[binding-vec then else] (rest (:children node)) | ||
pairs (partition-all 2 (:children binding-vec)) | ||
node (process-if-let-pairs pairs then else)] | ||
node)] | ||
{:node (with-meta expr | ||
(meta node))})) | ||
|
||
(defn when-let-hook | ||
[{:keys [node]}] | ||
(let [expr (let [[binding-vec & body] (rest (:children node))] | ||
(api/list-node | ||
[(api/token-node 'better-cond.core/if-let) | ||
binding-vec | ||
(api/list-node (list* (api/token-node 'do) | ||
body))]))] | ||
{:node (with-meta expr | ||
(meta node))})) | ||
|
||
(defn defnc-hook [{:keys [node]}] | ||
(let [[defnc-node name-node arg-node & body] | ||
(:children node) | ||
new-node (api/list-node [(api/token-node (if (str/ends-with? (str defnc-node) | ||
"defnc-") | ||
'clojure.core/defn- | ||
'clojure.core/defn)) | ||
name-node | ||
arg-node | ||
(api/list-node | ||
(list* (api/token-node 'better-cond.core/cond) | ||
body))])] | ||
{:node new-node})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{:hooks | ||
{:analyze-call | ||
{better-cond.core/cond better-cond.core/cond-hook | ||
better-cond.core/defnc better-cond.core/defnc-hook | ||
better-cond.core/defnc- better-cond.core/defnc-hook | ||
better-cond.core/if-let better-cond.core/if-let-hook | ||
better-cond.core/if-some better-cond.core/if-let-hook | ||
better-cond.core/when-let better-cond.core/when-let-hook | ||
better-cond.core/when-some better-cond.core/when-let-hook}}} |
19 changes: 19 additions & 0 deletions
19
.clj-kondo/com.gfredericks/test.chuck/clj_kondo/com/gfredericks/test/chuck/checking.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
(ns clj-kondo.com.gfredericks.test.chuck.checking | ||
(:require | ||
[clj-kondo.hooks-api :as api])) | ||
|
||
(defn checking | ||
[{{:keys [children]} :node}] | ||
(let [[_checking desc & opt+bindings+body] children | ||
[opts binding-vec & body] (if (api/vector-node? (first opt+bindings+body)) | ||
(into [(api/map-node {})] opt+bindings+body) | ||
opt+bindings+body)] | ||
(when-not (even? (count (:children binding-vec))) | ||
(throw (ex-info "checking requires an even number of bindings" {}))) | ||
{:node (api/list-node | ||
(list* | ||
(api/token-node 'let) | ||
(api/vector-node (into [(api/token-node (symbol (gensym "_checking-desc"))) desc] | ||
(:children binding-vec))) | ||
opts | ||
body))})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{:hooks | ||
{:analyze-call | ||
{com.gfredericks.test.chuck.clojure-test/checking | ||
clj-kondo.com.gfredericks.test.chuck.checking/checking}}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{:lint-as | ||
{humane-are.core/are+ clojure.test/are}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{:config-paths | ||
["macros"] | ||
|
||
:lint-as | ||
{toucan2.core/build clojure.core/identity | ||
toucan2.core/compile clojure.core/identity | ||
toucan2.query/with-built-query clojure.core/let | ||
toucan2.tools.compile/build clojure.core/identity | ||
toucan2.tools.compile/compile clojure.core/identity} | ||
|
||
:hooks | ||
{:analyze-call | ||
{toucan2.connection/with-connection hooks.toucan2.connection/with-connection | ||
toucan2.connection/with-transaction hooks.toucan2.connection/with-transaction | ||
toucan2.core/with-connection hooks.toucan2.connection/with-connection | ||
toucan2.core/with-transaction hooks.toucan2.connection/with-transaction | ||
toucan2.tools.simple-out-transform/define-out-transform hooks.toucan2.tools.simple-out-transform/define-out-transform | ||
toucan2.tools.with-temp/with-temp hooks.toucan2.tools.with-temp/with-temp} | ||
|
||
:macroexpand | ||
{toucan.db/with-call-counting macros.toucan2.execute/with-call-count | ||
toucan.models/defmodel macros.toucan.models/defmodel | ||
toucan2.core/define-after-insert macros.toucan2.tools.after-insert/define-after-insert | ||
toucan2.core/define-after-select macros.toucan2.tools.helpers/define-after-select | ||
toucan2.core/define-after-update macros.toucan2.tools.after-update/define-after-update | ||
toucan2.core/define-before-delete macros.toucan2.tools.helpers/define-before-delete | ||
toucan2.core/define-before-insert macros.toucan2.tools.before-insert/define-before-insert | ||
toucan2.core/define-before-select macros.toucan2.tools.helpers/define-before-select | ||
toucan2.core/define-before-update macros.toucan2.tools.before-update/define-before-update | ||
toucan2.execute/with-call-count macros.toucan2.execute/with-call-count | ||
toucan2.tools.after-insert/define-after-insert macros.toucan2.tools.after-insert/define-after-insert | ||
toucan2.tools.after-select/define-after-select macros.toucan2.tools.helpers/define-after-select | ||
toucan2.tools.after-update/define-after-update macros.toucan2.tools.after-update/define-after-update | ||
toucan2.tools.before-delete/define-before-delete macros.toucan2.tools.helpers/define-before-delete | ||
toucan2.tools.before-insert/define-before-insert macros.toucan2.tools.before-insert/define-before-insert | ||
toucan2.tools.before-select/define-before-select macros.toucan2.tools.helpers/define-before-select | ||
toucan2.tools.before-update/define-before-update macros.toucan2.tools.before-update/define-before-update | ||
toucan2.tools.default-fields/define-default-fields macros.toucan2.tools.default-fields/define-default-fields | ||
toucan2.tools.named-query/define-named-query macros.toucan2.tools.named-query/define-named-query}}} |
14 changes: 14 additions & 0 deletions
14
.clj-kondo/com.github.camsaul/toucan2/hooks/toucan2/connection.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
(ns hooks.toucan2.connection | ||
(:require [clj-kondo.hooks-api :as hooks])) | ||
|
||
(defn with-connection [{{[_ bindings & body] :children} :node}] | ||
(let [[conn-binding connectable] (:children bindings)] | ||
{:node (hooks/list-node | ||
(list* | ||
(hooks/token-node 'let) | ||
(hooks/vector-node [conn-binding (or connectable | ||
(hooks/token-node 'nil))]) | ||
body))})) | ||
|
||
(defn with-transaction [node] | ||
(with-connection node)) |
37 changes: 37 additions & 0 deletions
37
.clj-kondo/com.github.camsaul/toucan2/hooks/toucan2/tools/simple_out_transform.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
(ns hooks.toucan2.tools.simple-out-transform | ||
(:require [clj-kondo.hooks-api :as hooks])) | ||
|
||
(defn- ignore-unused-binding [x] | ||
(vary-meta x assoc :clj-kondo/ignore [:unused-binding])) | ||
|
||
(defn define-out-transform | ||
[{{[_define-out-transform dispatch-value {[instance-binding] :children, :as bindings} & body] :children, :as node} :node}] | ||
{:node (-> (hooks/list-node | ||
[(hooks/token-node 'do) | ||
dispatch-value | ||
(hooks/list-node | ||
(list* | ||
(hooks/token-node 'fn) | ||
(-> (hooks/vector-node | ||
[(ignore-unused-binding (with-meta (hooks/token-node '&query-type) (meta bindings))) | ||
(ignore-unused-binding (with-meta (hooks/token-node '&model) (meta bindings))) | ||
instance-binding]) | ||
(with-meta (meta bindings))) | ||
body))]) | ||
(with-meta (meta node)))}) | ||
|
||
(comment | ||
(defn test-define-out-transform [] | ||
(as-> '(tools.simple-out-transform/define-out-transform [:toucan.query-type/select.instances ::after-select] | ||
[instance] | ||
(let [wow 1000] | ||
;; don't do after-select if this select is a result of doing something like insert-returning instances | ||
(if (isa? &query-type :toucan2.pipeline/select.instances-from-pks) | ||
instance | ||
(after-select instance)))) <> | ||
(hooks/parse-string (pr-str <>)) | ||
(define-out-transform {:node <>}) | ||
(:node <>) | ||
(hooks/sexpr <>) | ||
(binding [*print-meta* false #_true] | ||
(clojure.pprint/pprint <>))))) |
22 changes: 22 additions & 0 deletions
22
.clj-kondo/com.github.camsaul/toucan2/hooks/toucan2/tools/with_temp.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
(ns hooks.toucan2.tools.with-temp | ||
(:require [clj-kondo.hooks-api :as hooks])) | ||
|
||
(defn with-temp [{{[_with-temp {bindings :children} & body] :children} :node}] | ||
(let [bindings* (into | ||
[] | ||
(comp (partition-all 3) | ||
(mapcat (fn [[model binding attributes]] | ||
(let [binding (or binding (hooks/token-node '_)) | ||
attributes (or attributes (hooks/token-node 'nil))] | ||
[binding (hooks/list-node | ||
(list | ||
(hooks/token-node 'do) | ||
model | ||
attributes))])))) | ||
bindings) | ||
node* (hooks/list-node | ||
(list* | ||
(hooks/token-node 'let) | ||
(hooks/vector-node bindings*) | ||
body))] | ||
{:node node*})) |
5 changes: 5 additions & 0 deletions
5
.clj-kondo/com.github.camsaul/toucan2/macros/toucan/models.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
(ns macros.toucan.models) | ||
|
||
(defmacro defmodel | ||
[model _table-name] | ||
`(def ~model "Docstring." ~(keyword (name model)))) |
4 changes: 4 additions & 0 deletions
4
.clj-kondo/com.github.camsaul/toucan2/macros/toucan2/common.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
(ns macros.toucan2.common) | ||
|
||
(defn ignore-unused [symb] | ||
(vary-meta symb assoc :clj-kondo/ignore [:unused-binding])) |
6 changes: 6 additions & 0 deletions
6
.clj-kondo/com.github.camsaul/toucan2/macros/toucan2/execute.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
(ns macros.toucan2.execute) | ||
|
||
(defmacro with-call-count | ||
[[call-count-fn-binding] & body] | ||
`(let [~call-count-fn-binding (fn [])] | ||
~@body)) |
10 changes: 10 additions & 0 deletions
10
.clj-kondo/com.github.camsaul/toucan2/macros/toucan2/tools/after_insert.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
(ns macros.toucan2.tools.after-insert | ||
(:require [macros.toucan2.common :as common])) | ||
|
||
(defmacro define-after-insert | ||
[model [instance-binding] & body] | ||
`(do | ||
~model | ||
(fn [~(common/ignore-unused '&model) | ||
~instance-binding] | ||
~@body))) |
10 changes: 10 additions & 0 deletions
10
.clj-kondo/com.github.camsaul/toucan2/macros/toucan2/tools/after_update.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
(ns macros.toucan2.tools.after-update | ||
(:require [macros.toucan2.common :as common])) | ||
|
||
(defmacro define-after-update | ||
[model [instance-binding] & body] | ||
`(do | ||
~model | ||
(fn [~(common/ignore-unused '&model) | ||
~instance-binding] | ||
~@body))) |
10 changes: 10 additions & 0 deletions
10
.clj-kondo/com.github.camsaul/toucan2/macros/toucan2/tools/before_insert.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
(ns macros.toucan2.tools.before-insert | ||
(:require [macros.toucan2.common :as common])) | ||
|
||
(defmacro define-before-insert | ||
[model [instance-binding] & body] | ||
`(do | ||
~model | ||
(fn [~(common/ignore-unused '&model) | ||
~instance-binding] | ||
~@body))) |
10 changes: 10 additions & 0 deletions
10
.clj-kondo/com.github.camsaul/toucan2/macros/toucan2/tools/before_update.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
(ns macros.toucan2.tools.before-update | ||
(:require [macros.toucan2.common :as common])) | ||
|
||
(defmacro define-before-update | ||
[model [instance-binding] & body] | ||
`(do | ||
~model | ||
(fn [~(common/ignore-unused '&model) | ||
~instance-binding] | ||
~@body))) |
6 changes: 6 additions & 0 deletions
6
.clj-kondo/com.github.camsaul/toucan2/macros/toucan2/tools/default_fields.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
(ns macros.toucan2.tools.default-fields | ||
(:require [macros.toucan2.common :as common])) | ||
|
||
(defmacro define-default-fields [model & body] | ||
`(let [~(common/ignore-unused '&model) ~model] | ||
~@body)) |
Oops, something went wrong.