From ed7d4e22f1c65aaad51654a47e0dfc20996d092e Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Mon, 19 Dec 2022 23:39:24 +0000 Subject: [PATCH] Documentation --- doc/Using_ActivityPub.md | 4 +- doc/intro.md | 83 ++- docs/cloverage/clj_activitypub/core.clj.html | 449 ++++++++++++++ .../clj_activitypub/internal/crypto.clj.html | 116 ++++ .../internal/http_util.clj.html | 83 +++ .../internal/thread_cache.clj.html | 140 +++++ .../clj_activitypub/webfinger.clj.html | 104 ++++ docs/cloverage/codecov.json | 54 ++ docs/cloverage/coverage.css | 40 ++ docs/cloverage/coverage.xml | 1 + .../dog_and_duck/quack/quack.clj.html | 569 ++++++++++++++++++ .../dog_and_duck/scratch/core.clj.html | 26 + .../dog_and_duck/scratch/parser.clj.html | 143 +++++ .../dog_and_duck/scratch/scratch.clj.html | 188 ++++++ docs/cloverage/index.html | 164 +++++ docs/codox/Using_ActivityPub.html | 112 ++++ docs/codox/clj-activitypub.core.html | 3 + .../clj-activitypub.internal.crypto.html | 3 + .../clj-activitypub.internal.http-util.html | 3 + ...clj-activitypub.internal.thread-cache.html | 3 + docs/codox/clj-activitypub.webfinger.html | 3 + docs/codox/css/default.css | 551 +++++++++++++++++ docs/codox/css/highlight.css | 97 +++ docs/codox/dog-and-duck.quack.quack.html | 14 + docs/codox/dog-and-duck.scratch.core.html | 3 + docs/codox/dog-and-duck.scratch.parser.html | 3 + docs/codox/dog-and-duck.scratch.scratch.html | 3 + docs/codox/index.html | 3 + docs/codox/intro.html | 46 ++ docs/codox/js/highlight.min.js | 2 + docs/codox/js/jquery.min.js | 4 + docs/codox/js/page_effects.js | 112 ++++ docs/index.html | 14 + project.clj | 22 +- .../public/images/Dog_and_Duck_tavern.jpg | Bin 0 -> 24594 bytes src/clj_activitypub/internal/crypto.clj | 9 +- src/clj_activitypub/internal/http_util.clj | 3 + src/clj_activitypub/internal/thread_cache.clj | 31 +- 38 files changed, 3182 insertions(+), 26 deletions(-) create mode 100644 docs/cloverage/clj_activitypub/core.clj.html create mode 100644 docs/cloverage/clj_activitypub/internal/crypto.clj.html create mode 100644 docs/cloverage/clj_activitypub/internal/http_util.clj.html create mode 100644 docs/cloverage/clj_activitypub/internal/thread_cache.clj.html create mode 100644 docs/cloverage/clj_activitypub/webfinger.clj.html create mode 100644 docs/cloverage/codecov.json create mode 100644 docs/cloverage/coverage.css create mode 100644 docs/cloverage/coverage.xml create mode 100644 docs/cloverage/dog_and_duck/quack/quack.clj.html create mode 100644 docs/cloverage/dog_and_duck/scratch/core.clj.html create mode 100644 docs/cloverage/dog_and_duck/scratch/parser.clj.html create mode 100644 docs/cloverage/dog_and_duck/scratch/scratch.clj.html create mode 100644 docs/cloverage/index.html create mode 100644 docs/codox/Using_ActivityPub.html create mode 100644 docs/codox/clj-activitypub.core.html create mode 100644 docs/codox/clj-activitypub.internal.crypto.html create mode 100644 docs/codox/clj-activitypub.internal.http-util.html create mode 100644 docs/codox/clj-activitypub.internal.thread-cache.html create mode 100644 docs/codox/clj-activitypub.webfinger.html create mode 100644 docs/codox/css/default.css create mode 100644 docs/codox/css/highlight.css create mode 100644 docs/codox/dog-and-duck.quack.quack.html create mode 100644 docs/codox/dog-and-duck.scratch.core.html create mode 100644 docs/codox/dog-and-duck.scratch.parser.html create mode 100644 docs/codox/dog-and-duck.scratch.scratch.html create mode 100644 docs/codox/index.html create mode 100644 docs/codox/intro.html create mode 100644 docs/codox/js/highlight.min.js create mode 100644 docs/codox/js/jquery.min.js create mode 100644 docs/codox/js/page_effects.js create mode 100644 docs/index.html create mode 100644 resources/public/images/Dog_and_Duck_tavern.jpg diff --git a/doc/Using_ActivityPub.md b/doc/Using_ActivityPub.md index b6755eb..b306543 100644 --- a/doc/Using_ActivityPub.md +++ b/doc/Using_ActivityPub.md @@ -1,5 +1,6 @@ # Using ActivityPub +```clojure user=> (require '[clj-activitypub.core :as activitypub]) nil user=> (require '[clj-activitypub.webfinger :as webfinger]) @@ -107,4 +108,5 @@ user=> (pprint sb) [{:type "PropertyValue", :name "Home Page", :value - "https://www.journeyman.cc/~simon/"}]} \ No newline at end of file + "https://www.journeyman.cc/~simon/"}]} +``` diff --git a/doc/intro.md b/doc/intro.md index f75e04e..97d9ad0 100644 --- a/doc/intro.md +++ b/doc/intro.md @@ -1,3 +1,82 @@ -# Introduction to dog-and-duck +# The Old Dog and Duck -TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) +A Clojure library designed to implement the ActivityPub protocol, obviously. + +## Introduction + +The Old Dog and Duck is clearly a pub, and it's a pub related to an activity; to whit, hunting ducks with dogs. Yes, of course one could also hunt dogs with ducks, but in practice that doesn't work so well. The point isn't whether or not I approve of hunting ducks with dogs (or vice versa); to be clear, I don't. The point is that it's a pub related to an activity, and is therefore an [ActivityPub](https://www.w3.org/TR/activitypub/). + +Are we clear? + +Good. + +Let us proceed. + +**The Old Dog and Duck** is intended to be a set of libraries to enable people to build stuff which interacts with ActivityPub. It isn't intended to be a replacement for, or clone of, Mastodon. I do think I might implement my own ActivityPub server on top of The Old Dog and Duck, that specifically might allow for user-pluggable feed-sorting algorithms and with my own user interface/user experience take, but that project is not (yet, at any rate) this project. + +## Status + +This is a long way pre-alpha. Everything will change. Feel free to play, but do so at your own risk. Contributions welcome. + +## Architecture + +There are a number of separate concerns required to implement ActivityPub. They include + +1. Parsing ActivityStreams messages received from peers and from clients; +2. Persisting ActivityStreams objects; +3. Delivering ActivityStreams objects to peers; +4. Delivering ActivityStreams objects to clients. + +**NOTE THAT** what Mastodon delivers to clients is not actually in ActivityStreams format; this seems to be an ad-hoc hack that's just never been fixed and has therefore become a de-facto standard for communication between ActivityPub hosts and their clients. + +My proposal would be to deliver exactly the same ActivityStreams format to my client as to other servers. There may be a valid reason for not doing this, but if there is I will discover it in due course. + +## Proposed dog-and-duck libraries + +**NOTE THAT** at the present stage all the proposed libraries are in one package, namely this package, but that it is proposed that in future they will form separate libraries in separate packages. + +### Bar + +Where conversations happen. Handle interactions with clients. + +### Cellar + +Where things are stored. Persistance for ActivityStreams objects; I may at least initially simply copy the Mastodon postgres schema, but equally I may not. + +### Pantry + +Where deliveries are ordered and arrive; and from where deliveries onwards are despatched. Handle interactions with peers. + +### Quack + +Duck-typing for ActivityStreams objects. + +As of version 0.1.0, this is substantially the only part that is yet at all useful, and it is still a long way from finished or robust. + +### Scratch + +What the dog does when bored. Essentially, a place where I can learn how to make this stuff work, but perhaps eventually an ActivityPub server in its own right. + +## Usage + +At present, only the duck-typing functions work. To play with them, use + +```clojure +(require '[dog-and-duck.quack.quack :as q]) +``` + +## Testing + +Prior to testing, you should clone [activitystreams-test-documents](https://github.com/w3c-social/activitystreams-test-documents) into the `resources` directory. You can then test with + +```bash +lein test +``` + +## License + +Copyright © Simon Brooke, 2022. + +This program and the accompanying materials are made available under the +terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your +option) any later version. diff --git a/docs/cloverage/clj_activitypub/core.clj.html b/docs/cloverage/clj_activitypub/core.clj.html new file mode 100644 index 0000000..d0e28ea --- /dev/null +++ b/docs/cloverage/clj_activitypub/core.clj.html @@ -0,0 +1,449 @@ + + + + clj_activitypub/core.clj + + + + 001  (ns clj-activitypub.core +
+ + 002    (:require [clj-activitypub.internal.crypto :as crypto] +
+ + 003              [clj-activitypub.internal.thread-cache :as thread-cache] +
+ + 004              [clj-activitypub.internal.http-util :as http] +
+ + 005              [clj-http.client :as client] +
+ + 006              [clojure.string :as str])) +
+ + 007   +
+ + 008  (defn config +
+ + 009    "Creates hash of computed data relevant for most ActivityPub utilities." +
+ + 010    [{:keys [domain username username-route public-key private-key] +
+ + 011      :or {username-route "/users/" +
+ + 012           public-key nil +
+ + 013           private-key nil}}] +
+ + 014    (let [base-url (str "https://" domain)] +
+ + 015      {:domain domain +
+ + 016       :base-url base-url +
+ + 017       :username username +
+ + 018       :user-id (str base-url username-route username) +
+ + 019       :public-key public-key +
+ + 020       :private-key (when private-key +
+ + 021                      (crypto/private-key private-key))})) +
+ + 022   +
+ + 023  (defn parse-account +
+ + 024    "Given an ActivityPub handle (e.g. @jahfer@mastodon.social), produces +
+ + 025     a map containing {:domain ... :username ...}." +
+ + 026    [handle] +
+ + 027    (let [[username domain] (filter #(not (str/blank? %)) +
+ + 028                                    (str/split handle #"@"))] +
+ + 029      {:domain domain :username username})) +
+ + 030   +
+ + 031  (def ^:private user-cache (thread-cache/make)) +
+ + 032  (defn fetch-user +
+ + 033    "Fetches the customer account details located at user-id from a remote +
+ + 034     server. Will return cached results if they exist in memory." +
+ + 035    [user-id] +
+ + 036    ((:get-v user-cache) +
+ + 037     user-id +
+ + 038     #(:body +
+ + 039       (client/get user-id {:as :json-string-keys +
+ + 040                            :throw-exceptions false +
+ + 041                            :ignore-unknown-host? true +
+ + 042                            :headers {"Accept" "application/activity+json"}})))) +
+ + 043   +
+ + 044  (defn actor +
+ + 045    "Accepts a config, and returns a map in the form expected by the ActivityPub +
+ + 046     spec. See https://www.w3.org/TR/activitypub/#actor-objects for reference." +
+ + 047    [{:keys [user-id username public-key]}] +
+ + 048    {"@context" ["https://www.w3.org/ns/activitystreams" +
+ + 049                 "https://w3id.org/security/v1"] +
+ + 050     :id user-id +
+ + 051     :type "Person" +
+ + 052     :preferredUsername username +
+ + 053     :inbox (str user-id "/inbox") +
+ + 054     :outbox (str user-id "/outbox") +
+ + 055     :publicKey {:id (str user-id "#main-key") +
+ + 056                 :owner user-id +
+ + 057                 :publicKeyPem (or public-key "")}}) +
+ + 058   +
+ + 059  (def signature-headers ["(request-target)" "host" "date" "digest"]) +
+ + 060   +
+ + 061  (defn- str-for-signature [headers] +
+ + 062    (let [headers-xf (reduce-kv +
+ + 063                      (fn [m k v] +
+ + 064                        (assoc m (str/lower-case k) v)) {} headers)] +
+ + 065      (->> signature-headers +
+ + 066           (select-keys headers-xf) +
+ + 067           (reduce-kv (fn [coll k v] (conj coll (str k ": " v))) []) +
+ + 068           (interpose "\n") +
+ + 069           (apply str)))) +
+ + 070   +
+ + 071  (defn gen-signature-header +
+ + 072    "Generates a HTTP Signature string based on the provided map of headers." +
+ + 073    [config headers] +
+ + 074    (let [{:keys [user-id private-key]} config +
+ + 075          string-to-sign (str-for-signature headers) +
+ + 076          signature (crypto/base64-encode (crypto/sign string-to-sign private-key)) +
+ + 077          sig-header-keys {"keyId" user-id +
+ + 078                           "headers" (str/join " " signature-headers) +
+ + 079                           "signature" signature}] +
+ + 080      (->> sig-header-keys +
+ + 081           (reduce-kv (fn [m k v] +
+ + 082                        (conj m (str k "=" "\"" v "\""))) []) +
+ + 083           (interpose ",") +
+ + 084           (apply str)))) +
+ + 085   +
+ + 086  (defn auth-headers +
+ + 087    "Given a config and request map of {:body ... :headers ...}, returns the +
+ + 088     original set of headers with Signature and Digest attributes appended." +
+ + 089    [config {:keys [body headers]}] +
+ + 090    (let [digest (http/digest body) +
+ + 091          h (-> headers +
+ + 092                (assoc "Digest" digest) +
+ + 093                (assoc "(request-target)" "post /inbox"))] +
+ + 094      (assoc headers +
+ + 095             "Signature" (gen-signature-header config h) +
+ + 096             "Digest" digest))) +
+ + 097   +
+ + 098  (defmulti obj +
+ + 099    "Produces a map representing an ActivityPub object which can be serialized +
+ + 100     directly to JSON in the form expected by the ActivityStreams 2.0 spec. +
+ + 101     See https://www.w3.org/TR/activitystreams-vocabulary/ for reference." +
+ + 102    (fn [_config object-data] (:type object-data))) +
+ + 103   +
+ + 104  (defmethod obj :note +
+ + 105    [{:keys [user-id]} +
+ + 106     {:keys [id published inReplyTo content to] +
+ + 107      :or {published (http/date) +
+ + 108           inReplyTo "" +
+ + 109           to "https://www.w3.org/ns/activitystreams#Public"}}] +
+ + 110    {"id" (str user-id "/notes/" id) +
+ + 111     "type" "Note" +
+ + 112     "published" published +
+ + 113     "attributedTo" user-id +
+ + 114     "inReplyTo" inReplyTo +
+ + 115     "content" content +
+ + 116     "to" to}) +
+ + 117   +
+ + 118  (defmulti activity +
+ + 119    "Produces a map representing an ActivityPub activity which can be serialized +
+ + 120     directly to JSON in the form expected by the ActivityStreams 2.0 spec. +
+ + 121     See https://www.w3.org/TR/activitystreams-vocabulary/ for reference." +
+ + 122    (fn [_config activity-type _data] activity-type)) +
+ + 123   +
+ + 124  (defmethod activity :create [{:keys [user-id]} _ data] +
+ + 125    {"@context" ["https://www.w3.org/ns/activitystreams" +
+ + 126                 "https://w3id.org/security/v1"] +
+ + 127     "type" "Create" +
+ + 128     "actor" user-id +
+ + 129     "object" data}) +
+ + 130   +
+ + 131  (defmethod activity :delete [{:keys [user-id]} _ data] +
+ + 132    {"@context" ["https://www.w3.org/ns/activitystreams" +
+ + 133                 "https://w3id.org/security/v1"] +
+ + 134     "type" "Delete" +
+ + 135     "actor" user-id +
+ + 136     "object" data}) +
+ + 137   +
+ + 138  (defn with-config +
+ + 139    "Returns curried forms of the #activity and #obj multimethods in the form +
+ + 140     {:activity ... :obj ...}, with the initial parameter set to config." +
+ + 141    [config] +
+ + 142    (let [f (juxt +
+ + 143             #(partial activity %) +
+ + 144             #(partial obj %)) +
+ + 145          [activity-fn obj-fn] (f config)] +
+ + 146      {:activity activity-fn +
+ + 147       :obj obj-fn})) +
+ + diff --git a/docs/cloverage/clj_activitypub/internal/crypto.clj.html b/docs/cloverage/clj_activitypub/internal/crypto.clj.html new file mode 100644 index 0000000..dc72564 --- /dev/null +++ b/docs/cloverage/clj_activitypub/internal/crypto.clj.html @@ -0,0 +1,116 @@ + + + + clj_activitypub/internal/crypto.clj + + + + 001  (ns clj-activitypub.internal.crypto +
+ + 002    (:require [clojure.java.io :as io]) +
+ + 003    (:import (java.util Base64) +
+ + 004             (java.security MessageDigest SecureRandom Signature))) +
+ + 005   +
+ + 006  (java.security.Security/addProvider +
+ + 007   (org.bouncycastle.jce.provider.BouncyCastleProvider.)) +
+ + 008   +
+ + 009  (defn- keydata [reader] +
+ + 010    (->> reader +
+ + 011         (org.bouncycastle.openssl.PEMParser.) +
+ + 012         (.readObject))) +
+ + 013   +
+ + 014  (defn- pem-string->key-pair [string] +
+ + 015    (let [kd (keydata (io/reader (.getBytes string)))] +
+ + 016      (.getKeyPair (org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter.) kd))) +
+ + 017   +
+ + 018  (defn private-key [private-pem-str] +
+ + 019    (-> private-pem-str +
+ + 020        (pem-string->key-pair) +
+ + 021        (.getPrivate))) +
+ + 022   +
+ + 023  (defn base64-encode [bytes] +
+ + 024    (.encodeToString (Base64/getEncoder) bytes)) +
+ + 025   +
+ + 026  (defn sha256-base64 [data] +
+ + 027    (let [digest (.digest (MessageDigest/getInstance "SHA-256") (.getBytes data))] +
+ + 028      (base64-encode digest))) +
+ + 029   +
+ + 030  (defn sign [data private-key]  +
+ + 031    (let [bytes (.getBytes data) +
+ + 032          signer (doto (Signature/getInstance "SHA256withRSA") +
+ + 033                (.initSign private-key (SecureRandom.)) +
+ + 034                (.update bytes))] +
+ + 035      (.sign signer))) +
+ + 036   +
+ + diff --git a/docs/cloverage/clj_activitypub/internal/http_util.clj.html b/docs/cloverage/clj_activitypub/internal/http_util.clj.html new file mode 100644 index 0000000..16768c7 --- /dev/null +++ b/docs/cloverage/clj_activitypub/internal/http_util.clj.html @@ -0,0 +1,83 @@ + + + + clj_activitypub/internal/http_util.clj + + + + 001  (ns clj-activitypub.internal.http-util +
+ + 002    (:require [clj-activitypub.internal.crypto :as crypto]) +
+ + 003    (:import (java.net URLEncoder) +
+ + 004             (java.time OffsetDateTime ZoneOffset) +
+ + 005             (java.time.format DateTimeFormatter))) +
+ + 006   +
+ + 007  (defn encode-url-params [params] +
+ + 008    (->> params +
+ + 009         (reduce-kv +
+ + 010          (fn [coll k v] +
+ + 011            (conj coll +
+ + 012                  (str (URLEncoder/encode (name k)) "=" (URLEncoder/encode (str v))))) +
+ + 013          []) +
+ + 014         (interpose "&") +
+ + 015         (apply str))) +
+ + 016   +
+ + 017  (defn date [] +
+ + 018    (-> (OffsetDateTime/now (ZoneOffset/UTC)) +
+ + 019        (.format DateTimeFormatter/RFC_1123_DATE_TIME))) +
+ + 020   +
+ + 021  (defn digest +
+ + 022    "Accepts body from HTTP request and generates string +
+ + 023     for use in HTTP `Digest` request header." +
+ + 024    [body] +
+ + 025    (str "sha-256=" (crypto/sha256-base64 body))) +
+ + diff --git a/docs/cloverage/clj_activitypub/internal/thread_cache.clj.html b/docs/cloverage/clj_activitypub/internal/thread_cache.clj.html new file mode 100644 index 0000000..5082b7b --- /dev/null +++ b/docs/cloverage/clj_activitypub/internal/thread_cache.clj.html @@ -0,0 +1,140 @@ + + + + clj_activitypub/internal/thread_cache.clj + + + + 001  (ns clj-activitypub.internal.thread-cache) +
+ + 002   +
+ + 003  (defn- current-time  +
+ + 004    "Returns current time using UNIX epoch." +
+ + 005    [] +
+ + 006    (System/currentTimeMillis)) +
+ + 007   +
+ + 008  (defn- update-read-at [store k v] +
+ + 009    (dosync +
+ + 010     (commute store assoc k +
+ + 011              (merge v {:read-at (current-time)})))) +
+ + 012   +
+ + 013  (defn make  +
+ + 014    "Creates a thread-local cache." +
+ + 015    ([] (make false)) +
+ + 016    ([cache-if-nil] +
+ + 017     (let [store (ref {})] +
+ + 018       (letfn [(cache-kv ([k v] +
+ + 019                          (dosync +
+ + 020                           (commute store assoc k +
+ + 021                                    {:write-at (current-time)  +
+ + 022                                     :read-at (current-time)  +
+ + 023                                     :value v}) +
+ + 024                           v))) +
+ + 025               (get-v ([k] +
+ + 026                       (when-let [data (get @store k)] +
+ + 027                         (update-read-at store k data) +
+ + 028                         (:value data))) +
+ + 029                      ([k compute-fn] +
+ + 030                       (let [storage @store] +
+ + 031                         (if (contains? storage k) +
+ + 032                           (get-v k) +
+ + 033                           (let [v (compute-fn)] +
+ + 034                             (when (or (not (nil? v)) cache-if-nil) +
+ + 035                               (cache-kv k v) +
+ + 036                               (get-v k))))))) +
+ + 037               (lru ([] +
+ + 038                     (mapv +
+ + 039                      (fn [[k v]] [k (:value v)]) +
+ + 040                      (sort-by #(-> % val :read-at) < @store))))] +
+ + 041         {:cache-kv cache-kv  +
+ + 042          :get-v get-v +
+ + 043          :cache-if-nil cache-if-nil +
+ + 044          :lru lru})))) +
+ + diff --git a/docs/cloverage/clj_activitypub/webfinger.clj.html b/docs/cloverage/clj_activitypub/webfinger.clj.html new file mode 100644 index 0000000..a834d7a --- /dev/null +++ b/docs/cloverage/clj_activitypub/webfinger.clj.html @@ -0,0 +1,104 @@ + + + + clj_activitypub/webfinger.clj + + + + 001  (ns clj-activitypub.webfinger +
+ + 002    (:require [clj-http.client :as client] +
+ + 003              [clj-activitypub.internal.http-util :as http] +
+ + 004              [clj-activitypub.internal.thread-cache :as thread-cache])) +
+ + 005   +
+ + 006  (def remote-uri-path "/.well-known/webfinger") +
+ + 007   +
+ + 008  (defn- resource-str [domain username] +
+ + 009    (str "acct:" username "@" domain)) +
+ + 010   +
+ + 011  (defn resource-url +
+ + 012    "Builds a URL pointing to the user's account on the remote server." +
+ + 013    [domain username & [params]] +
+ + 014    (let [resource (resource-str domain username) +
+ + 015          query-str (http/encode-url-params (merge params {:resource resource}))] +
+ + 016      (str "https://" domain remote-uri-path "?" query-str))) +
+ + 017   +
+ + 018  (def ^:private user-id-cache +
+ + 019    (thread-cache/make)) +
+ + 020   +
+ + 021  (defn fetch-user-id +
+ + 022    "Follows the webfinger request to a remote domain, retrieving the ID of the requested +
+ + 023     account. Typically returns a string in the form of a URL." +
+ + 024    [domain username] +
+ + 025    ((:get-v user-id-cache) +
+ + 026     (str domain "@" username) ;; cache key +
+ + 027     (fn [] +
+ + 028       (let [response (some-> (resource-url domain username {:rel "self"}) +
+ + 029                              (client/get {:as :json :throw-exceptions false :ignore-unknown-host? true}))] +
+ + 030         (some->> response :body :links +
+ + 031                  (some #(when (= (:type %) "application/activity+json") %)) +
+ + 032                  :href))))) +
+ + diff --git a/docs/cloverage/codecov.json b/docs/cloverage/codecov.json new file mode 100644 index 0000000..766b60c --- /dev/null +++ b/docs/cloverage/codecov.json @@ -0,0 +1,54 @@ +{"coverage": + {"dog_and_duck/quack/quack.clj": + [null, 1, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, 1, null, + null, null, null, null, null, null, null, null, null, null, null, + 17, null, 1, null, null, null, null, null, true, 5, null, null, 1, + null, 1, null, null, null, null, 1, null, null, null, null, null, 1, + null, null, 4, null, 1, null, null, null, null, 1, null, null, null, + null, 1, null, null, 4, null, 1, null, null, null, null, 1, null, + null, null, null, null, null, true, 10, 9, true, 2, null, null, + null, true, 2, null, 1, null, null, true, 2, 2, 0, 0, 0, null, null, + 1, null, null, 0, 0, 0, 0, 0, 0, 0, null, null, null, 1, null, null, + 0, 0, 0, null, null, 1, null, null, null, null, null, 0, 0, 0, null, + null, 1, null, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + null, null, 0, 0, null, 1, null, null, 0, null, 1, null, null, 0, + null, 1, null, null, 0, null, 1, null, null, 0, null, null], + "clj_activitypub/internal/http_util.clj": + [null, 1, null, null, null, null, null, 1, 1, 1, 1, 2, 2, 1, 1, 1, + null, 1, 0, 0, null, 1, null, null, null, 0], + "clj_activitypub/internal/thread_cache.clj": + [null, 1, null, 1, null, null, 8, null, 1, 4, 4, 4, null, 1, null, 2, + null, 2, 2, 2, 2, 2, 2, 2, 2, null, 4, 4, 4, null, 4, 4, 2, 2, true, + 2, 2, null, 0, 0, 0, 2, 2, 2, 2], + "dog_and_duck/scratch/parser.clj": + [null, 1, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, + null, 1, null, null, null, 7, 7, 7, 7, 7, true, 0, null, 1, null, 1, + 0, 0, 0, 0, 0, 0, 1], + "clj_activitypub/core.clj": + [null, 1, null, null, null, null, null, null, 1, null, null, null, + null, null, 0, 0, 0, 0, 0, 0, 0, 0, null, 1, null, null, null, 6, 2, + 2, null, 1, 1, null, null, null, 1, 1, 1, 1, null, null, 1, null, 1, + null, null, null, 0, null, 0, null, 0, 0, 0, 0, 0, 0, null, 1, null, + 1, 0, 0, 0, 0, 0, 0, 0, 0, null, 1, null, null, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, null, 1, null, null, null, 0, 0, 0, 0, 0, 0, 0, null, 1, + null, null, null, true, null, 1, null, null, null, null, null, 0, + null, 0, 0, 0, 0, 0, null, 1, null, null, null, true, null, 1, 0, + null, null, 0, 0, null, 1, 0, null, null, 0, 0, null, 1, null, null, + null, 0, 0, 0, 0, 0, 0], + "clj_activitypub/internal/crypto.clj": + [null, 1, null, null, null, null, 1, 1, null, 1, 0, 0, null, null, 1, + 0, 0, null, 1, 0, 0, null, null, 1, 0, null, 1, 0, 0, null, 1, 0, 0, + 0, 0, 0, null], + "dog_and_duck/scratch/core.clj":[null, 1, null, 1, null, null, 0], + "clj_activitypub/webfinger.clj": + [null, 1, null, null, null, null, 1, null, 1, 1, null, 1, null, null, + 1, 1, 1, null, 1, 1, null, 1, null, null, null, 3, 3, 3, true, 1, + true, 2, null], + "dog_and_duck/scratch/scratch.clj": + [null, 1, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, 1, null, 1, 1, 1, null, null, null, + null, 1, null, 1, 1, 1, 1, null, null, 1, null, null, 1, 1, null, + null, null, null, 1, 1, 1, 1, 1, 1, null]}} diff --git a/docs/cloverage/coverage.css b/docs/cloverage/coverage.css new file mode 100644 index 0000000..2be4e57 --- /dev/null +++ b/docs/cloverage/coverage.css @@ -0,0 +1,40 @@ +.covered { + font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace; + background-color: #558B55; +} + +.not-covered { + font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace; + background-color: red; +} + +.partial { + font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace; + background-color: orange; +} + +.not-tracked { + font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace; +} + +.blank { + font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace; +} + +td { + padding-right: 10px; +} + +td.with-bar { + width: 250px; + text-align: center; +} + +td.with-number { + text-align: right; +} + +td.ns-name { + min-width: 150px; + padding-right: 25px; +} diff --git a/docs/cloverage/coverage.xml b/docs/cloverage/coverage.xml new file mode 100644 index 0000000..f5390a2 --- /dev/null +++ b/docs/cloverage/coverage.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/cloverage/dog_and_duck/quack/quack.clj.html b/docs/cloverage/dog_and_duck/quack/quack.clj.html new file mode 100644 index 0000000..30f6484 --- /dev/null +++ b/docs/cloverage/dog_and_duck/quack/quack.clj.html @@ -0,0 +1,569 @@ + + + + dog_and_duck/quack/quack.clj + + + + 001  (ns dog-and-duck.quack.quack +
+ + 002    "Validator for ActivityPub objects: if it walks like a duck, and it quacks like a duck..." +
+ + 003    ;;(:require [clojure.spec.alpha as s]) +
+ + 004    (:import [java.net URI URISyntaxException])) +
+ + 005   +
+ + 006  ;;;     Copyright (C) Simon Brooke, 2022 +
+ + 007   +
+ + 008  ;;;     This program is free software; you can redistribute it and/or +
+ + 009  ;;;     modify it under the terms of the GNU General Public License +
+ + 010  ;;;     as published by the Free Software Foundation; either version 2 +
+ + 011  ;;;     of the License, or (at your option) any later version. +
+ + 012   +
+ + 013  ;;;     This program is distributed in the hope that it will be useful, +
+ + 014  ;;;     but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 015  ;;;     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 016  ;;;     GNU General Public License for more details. +
+ + 017   +
+ + 018  ;;;     You should have received a copy of the GNU General Public License +
+ + 019  ;;;     along with this program; if not, write to the Free Software +
+ + 020  ;;;     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. +
+ + 021   +
+ + 022  (defn object? +
+ + 023    "Returns `true` iff `x` is recognisably an ActivityStreams object. +
+ + 024      +
+ + 025     **NOTE THAT** The ActivityStreams spec  +
+ + 026     [says](https://www.w3.org/TR/activitystreams-core/#object): +
+ + 027      +
+ + 028     > All properties are optional (including the id and type) +
+ + 029      +
+ + 030     But we are *just not having that*, because otherwise we're flying blind. +
+ + 031     We *shall* reject objects lacking at least `:type`. Missing `:id` keys are +
+ + 032     tolerable because they represent transient objects, which we expect to  +
+ + 033     handle." +
+ + 034    [x] +
+ + 035    (and (map? x) (:type x) true)) +
+ + 036   +
+ + 037  (defn persistent-object? +
+ + 038    "`true` iff `x` is a persistent object. +
+ + 039   +
+ + 040     Transient objects in ActivityPub are not required to have an `id` key, but persistent +
+ + 041     ones must have a key, and it must be an IRI (but normally a URI)." +
+ + 042    [x] +
+ + 043    (try +
+ + 044      (and (object? x) (uri? (URI. (:id x)))) +
+ + 045      (catch URISyntaxException _ false))) +
+ + 046   +
+ + 047  (persistent-object? {:type "test" :id "https://mastodon.scot/@barfilfarm"}) +
+ + 048   +
+ + 049  (def ^:const actor-types +
+ + 050    "The set of types we will accept as actors. +
+ + 051      +
+ + 052     There's an [explicit set of allowed actor types] +
+ + 053     (https://www.w3.org/TR/activitystreams-vocabulary/#actor-types)." +
+ + 054    #{"Application" +
+ + 055      "Group" +
+ + 056      "Organization" +
+ + 057      "Person" +
+ + 058      "Service"}) +
+ + 059   +
+ + 060  (defn actor-type? +
+ + 061    ;; TODO: better as a macro +
+ + 062    [x] +
+ + 063    (if (actor-types x) true false)) +
+ + 064   +
+ + 065  (def ^:const verb-types +
+ + 066    "The set of types we will accept as verbs. +
+ + 067      +
+ + 068     There's an [explicit set of allowed verb types] +
+ + 069     (https://www.w3.org/TR/activitystreams-vocabulary/#activity-types)." +
+ + 070    #{"Accept" "Add" "Announce" "Arrive" "Block" "Create" "Delete" "Dislike" +
+ + 071      "Flag" "Follow" "Ignore" "Invite" "Join" "Leave" "Like" "Listen" "Move" +
+ + 072      "Offer" "Question" "Reject" "Read" "Remove" "TentativeAccept" +
+ + 073      "TentativeReject" "Travel" "Undo" "Update" "View"}) +
+ + 074   +
+ + 075  (defn verb-type? +
+ + 076    ;; TODO: better as a macro +
+ + 077    [x] +
+ + 078    (if (verb-types x) true false)) +
+ + 079   +
+ + 080  (def ^:const activitystreams-context-uri +
+ + 081    "The URI of the context of an ActivityStreams object is expected to be this +
+ + 082     literal string." +
+ + 083    "https://www.w3.org/ns/activitystreams") +
+ + 084   +
+ + 085  (defn context? +
+ + 086    "Returns `true` iff `x` quacks like an ActivityStreams context, else false. +
+ + 087      +
+ + 088     A context is either +
+ + 089     1. the URI (actually an IRI) `activitystreams-context-uri`, or +
+ + 090     2. a collection comprising that URI and a map." +
+ + 091    [x] +
+ + 092    (cond +
+ + 093      (nil? x) false +
+ + 094      (string? x) (and (= x activitystreams-context-uri) true) +
+ + 095      (coll? x) (and (context? (first (remove map? x)))  +
+ + 096                     (= (count x) 2) +
+ + 097                     true) +
+ + 098      :else false)) +
+ + 099   +
+ + 100  (defmacro has-context? [x] +
+ + 101    `(context? ((keyword "@context") ~x))) +
+ + 102   +
+ + 103  (defn actor? +
+ + 104    "Returns `true` if `x` quacks like an actor, else false." +
+ + 105    [x] +
+ + 106    (and +
+ + 107     (object? x) +
+ + 108     (has-context? x) +
+ + 109     (uri? (URI. (:inbox x))) +
+ + 110     (uri? (URI. (:outbox x))) +
+ + 111     (actor-type? (:type x)) +
+ + 112     true)) +
+ + 113   +
+ + 114  (defn activity? +
+ + 115    "`true` iff `x` quacks like an activity, else false." +
+ + 116    [x] +
+ + 117    (try +
+ + 118      (and (object? x) +
+ + 119           (has-context? x) +
+ + 120           (string? (:summary x)) +
+ + 121           (actor? (:actor x)) +
+ + 122           (verb-type? (:type x)) +
+ + 123           (or (object? (:object x)) (uri? (URI. (:object x)))) +
+ + 124           true) +
+ + 125      (catch URISyntaxException _ false))) +
+ + 126   +
+ + 127  (defn link? +
+ + 128    "`true` iff `x` quacks like a link, else false." +
+ + 129    [x] +
+ + 130    (and (object? x) +
+ + 131         (= (:type x) "Link") +
+ + 132         (uri? (URI. (:href x))) +
+ + 133         true)) +
+ + 134   +
+ + 135  (defn link-or-uri? +
+ + 136    "`true` iff `x` is either a URI or a link, else false. +
+ + 137      +
+ + 138     There are several points in the specification where e.g. the `:image` +
+ + 139     property (if present) may be either a link or a URI." +
+ + 140    [x] +
+ + 141    (and +
+ + 142     (cond (string? x) (uri? (URI. x)) +
+ + 143           :else (link? x)) +
+ + 144     true)) +
+ + 145   +
+ + 146  (defn collection? +
+ + 147    "`true` iff `x` quacks like a collection of type `type`, else `false`. +
+ + 148      +
+ + 149     With one argument, will recognise plain collections and ordered collections, +
+ + 150     but (currently) not collection pages." +
+ + 151    ([x type] +
+ + 152     (let [items (or (:items x) (:orderedItems x))] +
+ + 153       (and +
+ + 154        (cond +
+ + 155          (:items x) (nil? (:orderedItems x)) +
+ + 156          (:orderedItems x) (nil? (:items x))) ;; can't have both properties +
+ + 157        (object? x) +
+ + 158        (= (:type x) type) +
+ + 159        (coll? items) +
+ + 160        (every? object? items) +
+ + 161        (integer? (:totalItems x)) +
+ + 162        true))) +
+ + 163    ([x] +
+ + 164     (or (collection? x "Collection") +
+ + 165         (collection? x "OrderedCollection")))) +
+ + 166   +
+ + 167  (defn unordered-collection? +
+ + 168    "`true` iff `x` quacks like an unordered collection, else `false`." +
+ + 169    [x] +
+ + 170    (collection? x "Collection")) +
+ + 171   +
+ + 172  (defn ordered-collection? +
+ + 173    "`true` iff `x` quacks like an ordered collection, else `false`." +
+ + 174    [x] +
+ + 175    (collection? x "OrderedCollection")) +
+ + 176   +
+ + 177  (defn collection-page? +
+ + 178    "`true` iff `x` quacks like a page in a paged collection, else `false`." +
+ + 179    [x] +
+ + 180    (collection? x "CollectionPage")) +
+ + 181   +
+ + 182  (defn ordered-collection-page? +
+ + 183    "`true` iff `x` quacks like a page in an ordered paged collection, else `false`." +
+ + 184    [x] +
+ + 185    (collection? x "OrderedCollectionPage")) +
+ + 186   +
+ + 187   +
+ + diff --git a/docs/cloverage/dog_and_duck/scratch/core.clj.html b/docs/cloverage/dog_and_duck/scratch/core.clj.html new file mode 100644 index 0000000..eb11848 --- /dev/null +++ b/docs/cloverage/dog_and_duck/scratch/core.clj.html @@ -0,0 +1,26 @@ + + + + dog_and_duck/scratch/core.clj + + + + 001  (ns dog-and-duck.scratch.core) +
+ + 002   +
+ + 003  (defn foo +
+ + 004    "I don't do a whole lot." +
+ + 005    [x] +
+ + 006    (println x "Hello, World!")) +
+ + diff --git a/docs/cloverage/dog_and_duck/scratch/parser.clj.html b/docs/cloverage/dog_and_duck/scratch/parser.clj.html new file mode 100644 index 0000000..7f217ac --- /dev/null +++ b/docs/cloverage/dog_and_duck/scratch/parser.clj.html @@ -0,0 +1,143 @@ + + + + dog_and_duck/scratch/parser.clj + + + + 001  (ns dog-and-duck.scratch.parser +
+ + 002    (:require [clojure.java.io :refer [file]] +
+ + 003              [clojure.string :refer [ends-with?]] +
+ + 004              [clojure.walk :refer [keywordize-keys]] +
+ + 005              [clojure.data.json :as json] +
+ + 006              [dog-and-duck.quack.quack :as q])) +
+ + 007   +
+ + 008  ;;;     Copyright (C) Simon Brooke, 2022 +
+ + 009   +
+ + 010  ;;;     This program is free software; you can redistribute it and/or +
+ + 011  ;;;     modify it under the terms of the GNU General Public License +
+ + 012  ;;;     as published by the Free Software Foundation; either version 2 +
+ + 013  ;;;     of the License, or (at your option) any later version. +
+ + 014   +
+ + 015  ;;;     This program is distributed in the hope that it will be useful, +
+ + 016  ;;;     but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 017  ;;;     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 018  ;;;     GNU General Public License for more details. +
+ + 019   +
+ + 020  ;;;     You should have received a copy of the GNU General Public License +
+ + 021  ;;;     along with this program; if not, write to the Free Software +
+ + 022  ;;;     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. +
+ + 023   +
+ + 024  (defn clean +
+ + 025    "Take this `json` input, and return a sequence of ActivityPub objects  +
+ + 026     represented by it." +
+ + 027    [json] +
+ + 028    (let [feed (json/read-str json)] +
+ + 029      (map +
+ + 030       keywordize-keys +
+ + 031       (filter +
+ + 032        q/object? +
+ + 033        (cond (map? feed) (list (keywordize-keys feed)) +
+ + 034              (coll? feed) (map keywordize-keys feed)))))) +
+ + 035   +
+ + 036  (clean (slurp "resources/activitystreams-test-documents/core-ex1-jsonld.json")) +
+ + 037   +
+ + 038  (map +
+ + 039   #(when  +
+ + 040     (ends-with? (str %) ".json")  +
+ + 041      (let [objects (clean (slurp %))] +
+ + 042        (list (str %)  +
+ + 043              (count objects)  +
+ + 044              (map :type objects)))) +
+ + 045   (file-seq (file "resources/activitystreams-test-documents"))) +
+ + diff --git a/docs/cloverage/dog_and_duck/scratch/scratch.clj.html b/docs/cloverage/dog_and_duck/scratch/scratch.clj.html new file mode 100644 index 0000000..2991e30 --- /dev/null +++ b/docs/cloverage/dog_and_duck/scratch/scratch.clj.html @@ -0,0 +1,188 @@ + + + + dog_and_duck/scratch/scratch.clj + + + + 001  (ns dog-and-duck.scratch.scratch +
+ + 002    "Scratchpad where I try to understand how to do this stuff." +
+ + 003    (:require [clj-activitypub.core :as activitypub] +
+ + 004              [clj-activitypub.webfinger :as webfinger] +
+ + 005              [clj-pgp.core :as pgp] +
+ + 006              [clj-pgp.keyring :as keyring] +
+ + 007              [clj-pgp.generate :as pgp-gen] +
+ + 008              [clojure.walk :refer [keywordize-keys]] +
+ + 009              [clojure.pprint :refer [pprint]])) +
+ + 010   +
+ + 011  ;;;     Copyright (C) Simon Brooke, 2022 +
+ + 012   +
+ + 013  ;;;     This program is free software; you can redistribute it and/or +
+ + 014  ;;;     modify it under the terms of the GNU General Public License +
+ + 015  ;;;     as published by the Free Software Foundation; either version 2 +
+ + 016  ;;;     of the License, or (at your option) any later version. +
+ + 017       +
+ + 018  ;;;     This program is distributed in the hope that it will be useful, +
+ + 019  ;;;     but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 020  ;;;     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 021  ;;;     GNU General Public License for more details. +
+ + 022       +
+ + 023  ;;;     You should have received a copy of the GNU General Public License +
+ + 024  ;;;     along with this program; if not, write to the Free Software +
+ + 025  ;;;     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. +
+ + 026   +
+ + 027  ;;; Use any ActivityPub account handle you like - for example, your own +
+ + 028  (def account-handle "@simon_brooke@mastodon.scot") +
+ + 029   +
+ + 030  (def handle (activitypub/parse-account account-handle)) +
+ + 031  (webfinger/fetch-user-id "mastodon.scot" "simon_brooke") +
+ + 032  (apply webfinger/fetch-user-id (map handle [:domain :username])) +
+ + 033   +
+ + 034  ;;; Retrieve the account details from its home server +
+ + 035  ;;; (`keywordize-keys` is not necessary here but produces a more idiomatic clojure +
+ + 036  ;;; data structure) +
+ + 037  (def account +
+ + 038    "Fetch my account to mess with" +
+ + 039    (let [handle (activitypub/parse-account account-handle)] +
+ + 040      (keywordize-keys +
+ + 041       (activitypub/fetch-user +
+ + 042        (apply webfinger/fetch-user-id (map handle [:domain :username])))))) +
+ + 043   +
+ + 044  ;;; examine what you got back! +
+ + 045  (:outbox account) +
+ + 046   +
+ + 047   +
+ + 048  (def rsa (pgp-gen/rsa-keypair-generator 2048)) +
+ + 049  (def kp (pgp-gen/generate-keypair rsa :rsa-general)) +
+ + 050   +
+ + 051  ;; how we make a public/private key pair. But this key pair is not the one  +
+ + 052  ;; known to mastodon.scot as my key pair, so that doesn't get us very far... +
+ + 053  ;; I think. +
+ + 054  (let [rsa (pgp-gen/rsa-keypair-generator 2048) +
+ + 055        kp (pgp-gen/generate-keypair rsa :rsa-general) +
+ + 056        public (-> kp .getPublicKey .getEncoded) +
+ + 057        private (-> kp .getPrivateKey .getPrivateKeyDataPacket .getEncoded)] +
+ + 058    (println (str "Public key:  " public)) +
+ + 059    (println (str "Private key: " private)) +
+ + 060    ) +
+ + diff --git a/docs/cloverage/index.html b/docs/cloverage/index.html new file mode 100644 index 0000000..a11f17a --- /dev/null +++ b/docs/cloverage/index.html @@ -0,0 +1,164 @@ + + + + + Coverage Summary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Namespace Forms Forms % Lines Lines %TotalBlankInstrumented
clj-activitypub.core
71
230
23.59 %
24
2
60
30.23 %1471486
clj-activitypub.internal.crypto
9
39
18.75 %
9
14
39.13 %36823
clj-activitypub.internal.http-util
29
10
74.36 %
12
3
80.00 %25315
clj-activitypub.internal.thread-cache
105
21
83.33 %
30
1
3
91.18 %44334
clj-activitypub.webfinger
107
5
95.54 %
16
2
100.00 %32518
dog-and-duck.quack.quack
199
249
44.42 %
31
5
32
52.94 %1872668
dog-and-duck.scratch.core
2
4
33.33 %
2
1
66.67 %613
dog-and-duck.scratch.parser
34
34
50.00 %
10
1
7
61.11 %45718
dog-and-duck.scratch.scratch
75
100.00 %
19
100.00 %60919
Totals:51.59 %57.75 %
+ + diff --git a/docs/codox/Using_ActivityPub.html b/docs/codox/Using_ActivityPub.html new file mode 100644 index 0000000..208f2cb --- /dev/null +++ b/docs/codox/Using_ActivityPub.html @@ -0,0 +1,112 @@ + +Using ActivityPub

Using ActivityPub

+
user=> (require '[clj-activitypub.core :as activitypub])
+nil
+user=> (require '[clj-activitypub.webfinger :as webfinger])
+nil
+user=> (require '[clojure.walk :refer [keywordize-keys]])
+nil
+user=> (require '[clojure.pprint :refer [pprint]])
+nil
+user=> (def base-domain "mastodon.scot")
+#'user/base-domain
+user=> (def account-handle "@simon_brooke@mastodon.scot")
+#'user/account-handle
+user=> (in-ns 'user)
+#object[clojure.lang.Namespace 0x525575 "user"]
+user=> (activitypub/parse-account account-handle )
+{:domain "mastodon.scot", :username "simon_brooke"}
+user=> (map *1 [:domain :username])
+("mastodon.scot" "simon_brooke")
+user=> (apply webfinger/fetch-user-id *1)
+"https://mastodon.scot/users/simon_brooke"
+user=> (activitypub/fetch-user *1)
+{"followers" "https://mastodon.scot/users/simon_brooke/followers", "inbox" "https://mastodon.scot/users/simon_brooke/inbox", "url" "https://mastodon.scot/@simon_brooke", "@context" ["https://www.w3.org/ns/activitystreams" "https://w3id.org/security/v1" {"identityKey" {"@type" "@id", "@id" "toot:identityKey"}, "EncryptedMessage" "toot:EncryptedMessage", "Ed25519Key" "toot:Ed25519Key", "devices" {"@type" "@id", "@id" "toot:devices"}, "manuallyApprovesFollowers" "as:manuallyApprovesFollowers", "schema" "http://schema.org#", "PropertyValue" "schema:PropertyValue", "Curve25519Key" "toot:Curve25519Key", "claim" {"@type" "@id", "@id" "toot:claim"}, "value" "schema:value", "Hashtag" "as:Hashtag", "movedTo" {"@id" "as:movedTo", "@type" "@id"}, "discoverable" "toot:discoverable", "messageType" "toot:messageType", "messageFranking" "toot:messageFranking", "cipherText" "toot:cipherText", "toot" "http://joinmastodon.org/ns#", "alsoKnownAs" {"@id" "as:alsoKnownAs", "@type" "@id"}, "featured" {"@id" "toot:featured", "@type" "@id"}, "featuredTags" {"@id" "toot:featuredTags", "@type" "@id"}, "Ed25519Signature" "toot:Ed25519Signature", "focalPoint" {"@container" "@list", "@id" "toot:focalPoint"}, "fingerprintKey" {"@type" "@id", "@id" "toot:fingerprintKey"}, "Device" "toot:Device", "publicKeyBase64" "toot:publicKeyBase64", "deviceId" "toot:deviceId", "suspended" "toot:suspended"}], "devices" "https://mastodon.scot/users/simon_brooke/collections/devices", "manuallyApprovesFollowers" false, "image" {"type" "Image", "mediaType" "image/jpeg", "url" "https://media.mastodon.scot/mastodon-scot-public/accounts/headers/109/252/274/874/045/781/original/e1f1823c4361fa27.jpg"}, "endpoints" {"sharedInbox" "https://mastodon.scot/inbox"}, "id" "https://mastodon.scot/users/simon_brooke", "publicKey" {"id" "https://mastodon.scot/users/simon_brooke#main-key", "owner" "https://mastodon.scot/users/simon_brooke", "publicKeyPem" "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/6GgLJgJlPhhqFm1tUQ\noSLnWxhDwq4HlZIHrBsVjkSvUAnHKqq42Q/hta+fkWB8rmTFpmjLXDj/Fi0uejvT\nBc+KrLwfX/yR8+G87afGCRS3CaumoLJ7zkBIlsFzIKMoIke1D3QuHX95yGGXs+hp\nmyxt/+CXRyZjK7u9NG7SMRUlpwvOlpD12Aei35Nb8NSr03JvY8/WVMIbWrecyI0b\nAlwj6axxHx7J15Yo+aEtKzZ2OFKXf+sh0QF9BEnYcmVKYlR6kiOglLFHKdCBUSYi\ni9Flv00TydqlGvR5fpShBqORiy0M/FVtNXlz2sNBEsGB2meipkjh+cRLzTbYo4KL\nJwIDAQAB\n-----END PUBLIC KEY-----\n"}, "summary" "<p>Anarcho-syndicalist, autistic, crofter, cyclist, depressive, entrepreneur, geek, Zapatista. Politics &amp; environment, especially <a href=\"https://mastodon.scot/tags/LandReform\" class=\"mention hashtag\" rel=\"tag\">#<span>LandReform</span></a>. he/him.</p><p>Twitter: <span class=\"h-card\"><a href=\"https://mastodon.scot/@simon_brooke\" class=\"u-url mention\">@<span>simon_brooke</span></a></span><br />GitHub: simon-brooke<br />FetLife: Simon_Brooke</p><p>Credo: Life is harsh. What we can do - and what we should do - is strive to make it less harsh for the people around us.</p>", "attachment" [{"type" "PropertyValue", "name" "Home Page", "value" "<a href=\"https://www.journeyman.cc/~simon/\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://www.</span><span class=\"\">journeyman.cc/~simon/</span><span class=\"invisible\"></span></a>"}], "name" "Simon Brooke", "tag" [{"type" "Hashtag", "href" "https://mastodon.scot/tags/landreform", "name" "#landreform"}], "published" "2022-10-29T00:00:00Z", "preferredUsername" "simon_brooke", "discoverable" true, "alsoKnownAs" ["https://mastodon.social/users/simon_brooke"], "featured" "https://mastodon.scot/users/simon_brooke/collections/featured", "featuredTags" "https://mastodon.scot/users/simon_brooke/collections/tags", "type" "Person", "outbox" "https://mastodon.scot/users/simon_brooke/outbox", "following" "https://mastodon.scot/users/simon_brooke/following", "icon" {"type" "Image", "mediaType" "image/png", "url" "https://media.mastodon.scot/mastodon-scot-public/accounts/avatars/109/252/274/874/045/781/original/172e8f7530627e87.png"}}
+user=> (def sb (keywordize-keys *1))
+#'user/sb
+user=> (:outbox sb)
+"https://mastodon.scot/users/simon_brooke/outbox"
+user=> (require '[clojure.data.json :as json])
+nil
+user=> (slurp (:outbox sb))
+Execution error (IOException) at sun.net.www.protocol.http.HttpURLConnection/getInputStream0 (HttpURLConnection.java:1894).
+Server returned HTTP response code: 403 for URL: https://mastodon.scot/users/simon_brooke/outbox
+user=> (pprint sb)
+{:inbox "https://mastodon.scot/users/simon_brooke/inbox",
+ :name "Simon Brooke",
+ :@context
+ ["https://www.w3.org/ns/activitystreams"
+  "https://w3id.org/security/v1"
+  {:schema "http://schema.org#",
+   :messageType "toot:messageType",
+   :messageFranking "toot:messageFranking",
+   :identityKey {:@type "@id", :@id "toot:identityKey"},
+   :Hashtag "as:Hashtag",
+   :deviceId "toot:deviceId",
+   :publicKeyBase64 "toot:publicKeyBase64",
+   :value "schema:value",
+   :Ed25519Key "toot:Ed25519Key",
+   :featured {:@id "toot:featured", :@type "@id"},
+   :Curve25519Key "toot:Curve25519Key",
+   :discoverable "toot:discoverable",
+   :focalPoint {:@container "@list", :@id "toot:focalPoint"},
+   :suspended "toot:suspended",
+   :fingerprintKey {:@type "@id", :@id "toot:fingerprintKey"},
+   :Ed25519Signature "toot:Ed25519Signature",
+   :cipherText "toot:cipherText",
+   :EncryptedMessage "toot:EncryptedMessage",
+   :alsoKnownAs {:@id "as:alsoKnownAs", :@type "@id"},
+   :featuredTags {:@id "toot:featuredTags", :@type "@id"},
+   :devices {:@type "@id", :@id "toot:devices"},
+   :toot "http://joinmastodon.org/ns#",
+   :movedTo {:@id "as:movedTo", :@type "@id"},
+   :Device "toot:Device",
+   :PropertyValue "schema:PropertyValue",
+   :manuallyApprovesFollowers "as:manuallyApprovesFollowers",
+   :claim {:@type "@id", :@id "toot:claim"}}],
+ :featured
+ "https://mastodon.scot/users/simon_brooke/collections/featured",
+ :type "Person",
+ :discoverable true,
+ :icon
+ {:type "Image",
+  :mediaType "image/png",
+  :url
+  "https://media.mastodon.scot/mastodon-scot-public/accounts/avatars/109/252/274/874/045/781/original/172e8f7530627e87.png"},
+ :following "https://mastodon.scot/users/simon_brooke/following",
+ :summary
+ "<p>Anarcho-syndicalist, autistic, crofter, cyclist, depressive, entrepreneur, geek, Zapatista. Politics &amp; environment, especially <a href=\"https://mastodon.scot/tags/LandReform\" class=\"mention hashtag\" rel=\"tag\">#<span>LandReform</span></a>. he/him.</p><p>Twitter: <span class=\"h-card\"><a href=\"https://mastodon.scot/@simon_brooke\" class=\"u-url mention\">@<span>simon_brooke</span></a></span><br />GitHub: simon-brooke<br />FetLife: Simon_Brooke</p><p>Credo: Life is harsh. What we can do - and what we should do - is strive to make it less harsh for the people around us.</p>",
+ :publicKey
+ {:id "https://mastodon.scot/users/simon_brooke#main-key",
+  :owner "https://mastodon.scot/users/simon_brooke",
+  :publicKeyPem
+  "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/6GgLJgJlPhhqFm1tUQ\noSLnWxhDwq4HlZIHrBsVjkSvUAnHKqq42Q/hta+fkWB8rmTFpmjLXDj/Fi0uejvT\nBc+KrLwfX/yR8+G87afGCRS3CaumoLJ7zkBIlsFzIKMoIke1D3QuHX95yGGXs+hp\nmyxt/+CXRyZjK7u9NG7SMRUlpwvOlpD12Aei35Nb8NSr03JvY8/WVMIbWrecyI0b\nAlwj6axxHx7J15Yo+aEtKzZ2OFKXf+sh0QF9BEnYcmVKYlR6kiOglLFHKdCBUSYi\ni9Flv00TydqlGvR5fpShBqORiy0M/FVtNXlz2sNBEsGB2meipkjh+cRLzTbYo4KL\nJwIDAQAB\n-----END PUBLIC KEY-----\n"},
+ :endpoints {:sharedInbox "https://mastodon.scot/inbox"},
+ :preferredUsername "simon_brooke",
+ :id "https://mastodon.scot/users/simon_brooke",
+ :alsoKnownAs ["https://mastodon.social/users/simon_brooke"],
+ :outbox "https://mastodon.scot/users/simon_brooke/outbox",
+ :url "https://mastodon.scot/@simon_brooke",
+ :featuredTags
+ "https://mastodon.scot/users/simon_brooke/collections/tags",
+ :devices
+ "https://mastodon.scot/users/simon_brooke/collections/devices",
+ :image
+ {:type "Image",
+  :mediaType "image/jpeg",
+  :url
+  "https://media.mastodon.scot/mastodon-scot-public/accounts/headers/109/252/274/874/045/781/original/e1f1823c4361fa27.jpg"},
+ :tag
+ [{:type "Hashtag",
+   :href "https://mastodon.scot/tags/landreform",
+   :name "#landreform"}],
+ :followers "https://mastodon.scot/users/simon_brooke/followers",
+ :published "2022-10-29T00:00:00Z",
+ :manuallyApprovesFollowers false,
+ :attachment
+ [{:type "PropertyValue",
+   :name "Home Page",
+   :value
+   "<a href=\"https://www.journeyman.cc/~simon/\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://www.</span><span class=\"\">journeyman.cc/~simon/</span><span class=\"invisible\"></span></a>"}]}
+
\ No newline at end of file diff --git a/docs/codox/clj-activitypub.core.html b/docs/codox/clj-activitypub.core.html new file mode 100644 index 0000000..9e763ef --- /dev/null +++ b/docs/codox/clj-activitypub.core.html @@ -0,0 +1,3 @@ + +clj-activitypub.core documentation

clj-activitypub.core

TODO: write docs

activity

multimethod

Produces a map representing an ActivityPub activity which can be serialized directly to JSON in the form expected by the ActivityStreams 2.0 spec. See https://www.w3.org/TR/activitystreams-vocabulary/ for reference.

actor

(actor {:keys [user-id username public-key]})

Accepts a config, and returns a map in the form expected by the ActivityPub spec. See https://www.w3.org/TR/activitypub/#actor-objects for reference.

auth-headers

(auth-headers config {:keys [body headers]})

Given a config and request map of {:body … :headers …}, returns the original set of headers with Signature and Digest attributes appended.

config

(config {:keys [domain username username-route public-key private-key], :or {username-route "/users/", public-key nil, private-key nil}})

Creates hash of computed data relevant for most ActivityPub utilities.

fetch-user

(fetch-user user-id)

Fetches the customer account details located at user-id from a remote server. Will return cached results if they exist in memory.

gen-signature-header

(gen-signature-header config headers)

Generates a HTTP Signature string based on the provided map of headers.

obj

multimethod

Produces a map representing an ActivityPub object which can be serialized directly to JSON in the form expected by the ActivityStreams 2.0 spec. See https://www.w3.org/TR/activitystreams-vocabulary/ for reference.

parse-account

(parse-account handle)

Given an ActivityPub handle (e.g. @jahfer@mastodon.social), produces a map containing {:domain … :username …}.

signature-headers

TODO: write docs

with-config

(with-config config)

Returns curried forms of the #activity and #obj multimethods in the form {:activity … :obj …}, with the initial parameter set to config.

\ No newline at end of file diff --git a/docs/codox/clj-activitypub.internal.crypto.html b/docs/codox/clj-activitypub.internal.crypto.html new file mode 100644 index 0000000..89605eb --- /dev/null +++ b/docs/codox/clj-activitypub.internal.crypto.html @@ -0,0 +1,3 @@ + +clj-activitypub.internal.crypto documentation

clj-activitypub.internal.crypto

TODO: write docs

base64-encode

(base64-encode bytes)

TODO: write docs

private-key

(private-key private-pem-str)

TODO: write docs

sha256-base64

(sha256-base64 data)

TODO: write docs

sign

(sign data private-key)

TODO: write docs

\ No newline at end of file diff --git a/docs/codox/clj-activitypub.internal.http-util.html b/docs/codox/clj-activitypub.internal.http-util.html new file mode 100644 index 0000000..2726e1a --- /dev/null +++ b/docs/codox/clj-activitypub.internal.http-util.html @@ -0,0 +1,3 @@ + +clj-activitypub.internal.http-util documentation

clj-activitypub.internal.http-util

TODO: write docs

date

(date)

TODO: write docs

digest

(digest body)

Accepts body from HTTP request and generates string for use in HTTP Digest request header.

encode-url-params

(encode-url-params params)

TODO: write docs

\ No newline at end of file diff --git a/docs/codox/clj-activitypub.internal.thread-cache.html b/docs/codox/clj-activitypub.internal.thread-cache.html new file mode 100644 index 0000000..627ef04 --- /dev/null +++ b/docs/codox/clj-activitypub.internal.thread-cache.html @@ -0,0 +1,3 @@ + +clj-activitypub.internal.thread-cache documentation

clj-activitypub.internal.thread-cache

TODO: write docs

make

(make)(make cache-if-nil)

Creates a thread-local cache.

\ No newline at end of file diff --git a/docs/codox/clj-activitypub.webfinger.html b/docs/codox/clj-activitypub.webfinger.html new file mode 100644 index 0000000..bebfcf9 --- /dev/null +++ b/docs/codox/clj-activitypub.webfinger.html @@ -0,0 +1,3 @@ + +clj-activitypub.webfinger documentation

clj-activitypub.webfinger

TODO: write docs

fetch-user-id

(fetch-user-id domain username)

Follows the webfinger request to a remote domain, retrieving the ID of the requested account. Typically returns a string in the form of a URL.

remote-uri-path

TODO: write docs

resource-url

(resource-url domain username & [params])

Builds a URL pointing to the user’s account on the remote server.

\ No newline at end of file diff --git a/docs/codox/css/default.css b/docs/codox/css/default.css new file mode 100644 index 0000000..33f78fe --- /dev/null +++ b/docs/codox/css/default.css @@ -0,0 +1,551 @@ +body { + font-family: Helvetica, Arial, sans-serif; + font-size: 15px; +} + +pre, code { + font-family: Monaco, DejaVu Sans Mono, Consolas, monospace; + font-size: 9pt; + margin: 15px 0; +} + +h1 { + font-weight: normal; + font-size: 29px; + margin: 10px 0 2px 0; + padding: 0; +} + +h2 { + font-weight: normal; + font-size: 25px; +} + +h5.license { + margin: 9px 0 22px 0; + color: #555; + font-weight: normal; + font-size: 12px; + font-style: italic; +} + +.document h1, .namespace-index h1 { + font-size: 32px; + margin-top: 12px; +} + +#header, #content, .sidebar { + position: fixed; +} + +#header { + top: 0; + left: 0; + right: 0; + height: 22px; + color: #f5f5f5; + padding: 5px 7px; +} + +#content { + top: 32px; + right: 0; + bottom: 0; + overflow: auto; + background: #fff; + color: #333; + padding: 0 18px; +} + +.sidebar { + position: fixed; + top: 32px; + bottom: 0; + overflow: auto; +} + +.sidebar.primary { + background: #e2e2e2; + border-right: solid 1px #cccccc; + left: 0; + width: 250px; +} + +.sidebar.secondary { + background: #f2f2f2; + border-right: solid 1px #d7d7d7; + left: 251px; + width: 200px; +} + +#content.namespace-index, #content.document { + left: 251px; +} + +#content.namespace-docs { + left: 452px; +} + +#content.document { + padding-bottom: 10%; +} + +#header { + background: #3f3f3f; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.4); + z-index: 100; +} + +#header h1 { + margin: 0; + padding: 0; + font-size: 18px; + font-weight: lighter; + text-shadow: -1px -1px 0px #333; +} + +#header h1 .project-version { + font-weight: normal; +} + +.project-version { + padding-left: 0.15em; +} + +#header a, .sidebar a { + display: block; + text-decoration: none; +} + +#header a { + color: #f5f5f5; +} + +.sidebar a { + color: #333; +} + +#header h2 { + float: right; + font-size: 9pt; + font-weight: normal; + margin: 4px 3px; + padding: 0; + color: #bbb; +} + +#header h2 a { + display: inline; +} + +.sidebar h3 { + margin: 0; + padding: 10px 13px 0 13px; + font-size: 19px; + font-weight: lighter; +} + +.sidebar h3 a { + color: #444; +} + +.sidebar h3.no-link { + color: #636363; +} + +.sidebar ul { + padding: 7px 0 6px 0; + margin: 0; +} + +.sidebar ul.index-link { + padding-bottom: 4px; +} + +.sidebar li { + display: block; + vertical-align: middle; +} + +.sidebar li a, .sidebar li .no-link { + border-left: 3px solid transparent; + padding: 0 10px; + white-space: nowrap; +} + +.sidebar li .no-link { + display: block; + color: #777; + font-style: italic; +} + +.sidebar li .inner { + display: inline-block; + padding-top: 7px; + height: 24px; +} + +.sidebar li a, .sidebar li .tree { + height: 31px; +} + +.depth-1 .inner { padding-left: 2px; } +.depth-2 .inner { padding-left: 6px; } +.depth-3 .inner { padding-left: 20px; } +.depth-4 .inner { padding-left: 34px; } +.depth-5 .inner { padding-left: 48px; } +.depth-6 .inner { padding-left: 62px; } + +.sidebar li .tree { + display: block; + float: left; + position: relative; + top: -10px; + margin: 0 4px 0 0; + padding: 0; +} + +.sidebar li.depth-1 .tree { + display: none; +} + +.sidebar li .tree .top, .sidebar li .tree .bottom { + display: block; + margin: 0; + padding: 0; + width: 7px; +} + +.sidebar li .tree .top { + border-left: 1px solid #aaa; + border-bottom: 1px solid #aaa; + height: 19px; +} + +.sidebar li .tree .bottom { + height: 22px; +} + +.sidebar li.branch .tree .bottom { + border-left: 1px solid #aaa; +} + +.sidebar.primary li.current a { + border-left: 3px solid #a33; + color: #a33; +} + +.sidebar.secondary li.current a { + border-left: 3px solid #33a; + color: #33a; +} + +.namespace-index h2 { + margin: 30px 0 0 0; +} + +.namespace-index h3 { + font-size: 16px; + font-weight: bold; + margin-bottom: 0; +} + +.namespace-index .topics { + padding-left: 30px; + margin: 11px 0 0 0; +} + +.namespace-index .topics li { + padding: 5px 0; +} + +.namespace-docs h3 { + font-size: 18px; + font-weight: bold; +} + +.public h3 { + margin: 0; + float: left; +} + +.usage { + clear: both; +} + +.public { + margin: 0; + border-top: 1px solid #e0e0e0; + padding-top: 14px; + padding-bottom: 6px; +} + +.public:last-child { + margin-bottom: 20%; +} + +.members .public:last-child { + margin-bottom: 0; +} + +.members { + margin: 15px 0; +} + +.members h4 { + color: #555; + font-weight: normal; + font-variant: small-caps; + margin: 0 0 5px 0; +} + +.members .inner { + padding-top: 5px; + padding-left: 12px; + margin-top: 2px; + margin-left: 7px; + border-left: 1px solid #bbb; +} + +#content .members .inner h3 { + font-size: 12pt; +} + +.members .public { + border-top: none; + margin-top: 0; + padding-top: 6px; + padding-bottom: 0; +} + +.members .public:first-child { + padding-top: 0; +} + +h4.type, +h4.dynamic, +h4.added, +h4.deprecated { + float: left; + margin: 3px 10px 15px 0; + font-size: 15px; + font-weight: bold; + font-variant: small-caps; +} + +.public h4.type, +.public h4.dynamic, +.public h4.added, +.public h4.deprecated { + font-size: 13px; + font-weight: bold; + margin: 3px 0 0 10px; +} + +.members h4.type, +.members h4.added, +.members h4.deprecated { + margin-top: 1px; +} + +h4.type { + color: #717171; +} + +h4.dynamic { + color: #9933aa; +} + +h4.added { + color: #508820; +} + +h4.deprecated { + color: #880000; +} + +.namespace { + margin-bottom: 30px; +} + +.namespace:last-child { + margin-bottom: 10%; +} + +.index { + padding: 0; + font-size: 80%; + margin: 15px 0; + line-height: 16px; +} + +.index * { + display: inline; +} + +.index p { + padding-right: 3px; +} + +.index li { + padding-right: 5px; +} + +.index ul { + padding-left: 0; +} + +.type-sig { + clear: both; + color: #088; +} + +.type-sig pre { + padding-top: 10px; + margin: 0; +} + +.usage code { + display: block; + color: #008; + margin: 2px 0; +} + +.usage code:first-child { + padding-top: 10px; +} + +p { + margin: 15px 0; +} + +.public p:first-child, .public pre.plaintext { + margin-top: 12px; +} + +.doc { + margin: 0 0 26px 0; + clear: both; +} + +.public .doc { + margin: 0; +} + +.namespace-index .doc { + margin-bottom: 20px; +} + +.namespace-index .namespace .doc { + margin-bottom: 10px; +} + +.markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td { + line-height: 22px; +} + +.markdown li { + padding: 2px 0; +} + +.markdown h2 { + font-weight: normal; + font-size: 25px; + margin: 30px 0 10px 0; +} + +.markdown h3 { + font-weight: normal; + font-size: 20px; + margin: 30px 0 0 0; +} + +.markdown h4 { + font-size: 15px; + margin: 22px 0 -4px 0; +} + +.doc, .public, .namespace .index { + max-width: 680px; + overflow-x: visible; +} + +.markdown pre > code { + display: block; + padding: 10px; +} + +.markdown pre > code, .src-link a { + border: 1px solid #e4e4e4; + border-radius: 2px; +} + +.markdown code:not(.hljs), .src-link a { + background: #f6f6f6; +} + +pre.deps { + display: inline-block; + margin: 0 10px; + border: 1px solid #e4e4e4; + border-radius: 2px; + padding: 10px; + background-color: #f6f6f6; +} + +.markdown hr { + border-style: solid; + border-top: none; + color: #ccc; +} + +.doc ul, .doc ol { + padding-left: 30px; +} + +.doc table { + border-collapse: collapse; + margin: 0 10px; +} + +.doc table td, .doc table th { + border: 1px solid #dddddd; + padding: 4px 6px; +} + +.doc table th { + background: #f2f2f2; +} + +.doc dl { + margin: 0 10px 20px 10px; +} + +.doc dl dt { + font-weight: bold; + margin: 0; + padding: 3px 0; + border-bottom: 1px solid #ddd; +} + +.doc dl dd { + padding: 5px 0; + margin: 0 0 5px 10px; +} + +.doc abbr { + border-bottom: 1px dotted #333; + font-variant: none; + cursor: help; +} + +.src-link { + margin-bottom: 15px; +} + +.src-link a { + font-size: 70%; + padding: 1px 4px; + text-decoration: none; + color: #5555bb; +} diff --git a/docs/codox/css/highlight.css b/docs/codox/css/highlight.css new file mode 100644 index 0000000..d0cdaa3 --- /dev/null +++ b/docs/codox/css/highlight.css @@ -0,0 +1,97 @@ +/* +github.com style (c) Vasily Polovnyov +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #333; + background: #f8f8f8; +} + +.hljs-comment, +.hljs-quote { + color: #998; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-subst { + color: #333; + font-weight: bold; +} + +.hljs-number, +.hljs-literal, +.hljs-variable, +.hljs-template-variable, +.hljs-tag .hljs-attr { + color: #008080; +} + +.hljs-string, +.hljs-doctag { + color: #d14; +} + +.hljs-title, +.hljs-section, +.hljs-selector-id { + color: #900; + font-weight: bold; +} + +.hljs-subst { + font-weight: normal; +} + +.hljs-type, +.hljs-class .hljs-title { + color: #458; + font-weight: bold; +} + +.hljs-tag, +.hljs-name, +.hljs-attribute { + color: #000080; + font-weight: normal; +} + +.hljs-regexp, +.hljs-link { + color: #009926; +} + +.hljs-symbol, +.hljs-bullet { + color: #990073; +} + +.hljs-built_in, +.hljs-builtin-name { + color: #0086b3; +} + +.hljs-meta { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + background: #fdd; +} + +.hljs-addition { + background: #dfd; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/docs/codox/dog-and-duck.quack.quack.html b/docs/codox/dog-and-duck.quack.quack.html new file mode 100644 index 0000000..3382dad --- /dev/null +++ b/docs/codox/dog-and-duck.quack.quack.html @@ -0,0 +1,14 @@ + +dog-and-duck.quack.quack documentation

dog-and-duck.quack.quack

Validator for ActivityPub objects: if it walks like a duck, and it quacks like a duck…

activity?

(activity? x)

true iff x quacks like an activity, else false.

activitystreams-context-uri

The URI of the context of an ActivityStreams object is expected to be this literal string.

actor-type?

(actor-type? x)

TODO: write docs

actor-types

The set of types we will accept as actors.

+

There’s an explicit set of allowed actor types.

actor?

(actor? x)

Returns true if x quacks like an actor, else false.

collection-page?

(collection-page? x)

true iff x quacks like a page in a paged collection, else false.

collection?

(collection? x type)(collection? x)

true iff x quacks like a collection of type type, else false.

+

With one argument, will recognise plain collections and ordered collections, but (currently) not collection pages.

context?

(context? x)

Returns true iff x quacks like an ActivityStreams context, else false.

+

A context is either 1. the URI (actually an IRI) activitystreams-context-uri, or 2. a collection comprising that URI and a map.

has-context?

macro

(has-context? x)

TODO: write docs

link?

(link? x)

true iff x quacks like a link, else false.

object?

(object? x)

Returns true iff x is recognisably an ActivityStreams object.

+

NOTE THAT The ActivityStreams spec says:

+
+

All properties are optional (including the id and type)

+
+

But we are just not having that, because otherwise we’re flying blind. We shall reject objects lacking at least :type. Missing :id keys are tolerable because they represent transient objects, which we expect to handle.

ordered-collection-page?

(ordered-collection-page? x)

true iff x quacks like a page in an ordered paged collection, else false.

ordered-collection?

(ordered-collection? x)

true iff x quacks like an ordered collection, else false.

persistent-object?

(persistent-object? x)

true iff x is a persistent object.

+

Transient objects in ActivityPub are not required to have an id key, but persistent ones must have a key, and it must be an IRI (but normally a URI).

unordered-collection?

(unordered-collection? x)

true iff x quacks like an unordered collection, else false.

verb-type?

(verb-type? x)

TODO: write docs

verb-types

The set of types we will accept as verbs.

+

There’s an explicit set of allowed verb types.

\ No newline at end of file diff --git a/docs/codox/dog-and-duck.scratch.core.html b/docs/codox/dog-and-duck.scratch.core.html new file mode 100644 index 0000000..30b1865 --- /dev/null +++ b/docs/codox/dog-and-duck.scratch.core.html @@ -0,0 +1,3 @@ + +dog-and-duck.scratch.core documentation

dog-and-duck.scratch.core

TODO: write docs

foo

(foo x)

I don’t do a whole lot.

\ No newline at end of file diff --git a/docs/codox/dog-and-duck.scratch.parser.html b/docs/codox/dog-and-duck.scratch.parser.html new file mode 100644 index 0000000..8f8968c --- /dev/null +++ b/docs/codox/dog-and-duck.scratch.parser.html @@ -0,0 +1,3 @@ + +dog-and-duck.scratch.parser documentation

dog-and-duck.scratch.parser

TODO: write docs

clean

(clean json)

Take this json input, and return a sequence of ActivityPub objects represented by it.

\ No newline at end of file diff --git a/docs/codox/dog-and-duck.scratch.scratch.html b/docs/codox/dog-and-duck.scratch.scratch.html new file mode 100644 index 0000000..be30ecf --- /dev/null +++ b/docs/codox/dog-and-duck.scratch.scratch.html @@ -0,0 +1,3 @@ + +dog-and-duck.scratch.scratch documentation

dog-and-duck.scratch.scratch

Scratchpad where I try to understand how to do this stuff.

account

Fetch my account to mess with

account-handle

TODO: write docs

handle

TODO: write docs

kp

TODO: write docs

rsa

TODO: write docs

\ No newline at end of file diff --git a/docs/codox/index.html b/docs/codox/index.html new file mode 100644 index 0000000..f194bc9 --- /dev/null +++ b/docs/codox/index.html @@ -0,0 +1,3 @@ + +Dog-and-duck 0.1.0-SNAPSHOT

Dog-and-duck 0.1.0-SNAPSHOT

Released under the GPL-2.0-or-later

A Clojure library designed to implement the ActivityPub protocol.

Installation

To install, add the following dependency to your project or build file:

[dog-and-duck "0.1.0-SNAPSHOT"]

Topics

Namespaces

clj-activitypub.internal.crypto

TODO: write docs

Public variables and functions:

clj-activitypub.internal.http-util

TODO: write docs

Public variables and functions:

clj-activitypub.internal.thread-cache

TODO: write docs

Public variables and functions:

clj-activitypub.webfinger

TODO: write docs

Public variables and functions:

dog-and-duck.scratch.core

TODO: write docs

Public variables and functions:

dog-and-duck.scratch.parser

TODO: write docs

Public variables and functions:

dog-and-duck.scratch.scratch

Scratchpad where I try to understand how to do this stuff.

Public variables and functions:

\ No newline at end of file diff --git a/docs/codox/intro.html b/docs/codox/intro.html new file mode 100644 index 0000000..6a5fb84 --- /dev/null +++ b/docs/codox/intro.html @@ -0,0 +1,46 @@ + +The Old Dog and Duck

The Old Dog and Duck

+

A Clojure library designed to implement the ActivityPub protocol, obviously.

+

Introduction

+

The Old Dog and Duck is clearly a pub, and it’s a pub related to an activity; to whit, hunting ducks with dogs. Yes, of course one could also hunt dogs with ducks, but in practice that doesn’t work so well. The point isn’t whether or not I approve of hunting ducks with dogs (or vice versa); to be clear, I don’t. The point is that it’s a pub related to an activity, and is therefore an ActivityPub.

+

Are we clear?

+

Good.

+

Let us proceed.

+

The Old Dog and Duck is intended to be a set of libraries to enable people to build stuff which interacts with ActivityPub. It isn’t intended to be a replacement for, or clone of, Mastodon. I do think I might implement my own ActivityPub server on top of The Old Dog and Duck, that specifically might allow for user-pluggable feed-sorting algorithms and with my own user interface/user experience take, but that project is not (yet, at any rate) this project.

+

Status

+

This is a long way pre-alpha. Everything will change. Feel free to play, but do so at your own risk. Contributions welcome.

+

Architecture

+

There are a number of separate concerns required to implement ActivityPub. They include

+
    +
  1. Parsing ActivityStreams messages received from peers and from clients;
  2. +
  3. Persisting ActivityStreams objects;
  4. +
  5. Delivering ActivityStreams objects to peers;
  6. +
  7. Delivering ActivityStreams objects to clients.
  8. +
+

NOTE THAT what Mastodon delivers to clients is not actually in ActivityStreams format; this seems to be an ad-hoc hack that’s just never been fixed and has therefore become a de-facto standard for communication between ActivityPub hosts and their clients.

+

My proposal would be to deliver exactly the same ActivityStreams format to my client as to other servers. There may be a valid reason for not doing this, but if there is I will discover it in due course.

+

Proposed dog-and-duck libraries

+

NOTE THAT at the present stage all the proposed libraries are in one package, namely this package, but that it is proposed that in future they will form separate libraries in separate packages.

+

Bar

+

Where conversations happen. Handle interactions with clients.

+

Cellar

+

Where things are stored. Persistance for ActivityStreams objects; I may at least initially simply copy the Mastodon postgres schema, but equally I may not.

+

Pantry

+

Where deliveries are ordered and arrive; and from where deliveries onwards are despatched. Handle interactions with peers.

+

Quack

+

Duck-typing for ActivityStreams objects.

+

As of version 0.1.0, this is substantially the only part that is yet at all useful, and it is still a long way from finished or robust.

+

Scratch

+

What the dog does when bored. Essentially, a place where I can learn how to make this stuff work, but perhaps eventually an ActivityPub server in its own right.

+

Usage

+

At present, only the duck-typing functions work. To play with them, use

+
(require '[dog-and-duck.quack.quack :as q])
+
+

Testing

+

Prior to testing, you should clone activitystreams-test-documents into the resources directory. You can then test with

+
lein test
+
+

License

+

Copyright © Simon Brooke, 2022.

+

This program and the accompanying materials are made available under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.

\ No newline at end of file diff --git a/docs/codox/js/highlight.min.js b/docs/codox/js/highlight.min.js new file mode 100644 index 0000000..6486ffd --- /dev/null +++ b/docs/codox/js/highlight.min.js @@ -0,0 +1,2 @@ +/*! highlight.js v9.6.0 | BSD3 License | git.io/hljslicense */ +!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/[&<>]/gm,function(e){return I[e]})}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return R(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||R(i))return i}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function u(e){l+=""}function c(e){("start"===e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):E(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"===e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function l(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function h(e,n,t,r){var a=r?"":y.classPrefix,i='',i+n+o}function p(){var e,t,r,a;if(!E.k)return n(B);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(B);r;)a+=n(B.substr(t,r.index-t)),e=g(E,r),e?(M+=e[1],a+=h(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(B);return a+n(B.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!x[E.sL])return n(B);var t=e?l(E.sL,B,!0,L[E.sL]):f(B,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(L[E.sL]=t.top),h(t.language,t.value,!1,!0)}function b(){k+=null!=E.sL?d():p(),B=""}function v(e){k+=e.cN?h(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(B+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?B+=n:(t.eB&&(B+=n),b(),t.rB||t.eB||(B=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?B+=n:(a.rE||a.eE||(B+=n),b(),a.eE&&(B=n));do E.cN&&(k+=C),E.skip||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return B+=n,n.length||1}var N=R(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var w,E=i||N,L={},k="";for(w=E;w!==N;w=w.parent)w.cN&&(k=h(w.cN,"",!0)+k);var B="",M=0;try{for(var I,j,O=0;;){if(E.t.lastIndex=O,I=E.t.exec(t),!I)break;j=m(t.substr(O,I.index-O),I[0]),O=I.index+j}for(m(t.substr(O)),w=E;w.parent;w=w.parent)w.cN&&(k+=C);return{r:M,value:k,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function f(e,t){t=t||y.languages||E(x);var r={r:0,value:n(e)},a=r;return t.filter(R).forEach(function(n){var t=l(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function g(e){return y.tabReplace||y.useBR?e.replace(M,function(e,n){return y.useBR&&"\n"===e?"
":y.tabReplace?n.replace(/\t/g,y.tabReplace):void 0}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n,t,r,o,s,p=i(e);a(p)||(y.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,s=n.textContent,r=p?l(p,s,!0):f(s),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),s)),r.value=g(r.value),e.innerHTML=r.value,e.className=h(e.className,p,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function d(e){y=o(y,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");w.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function N(){return E(x)}function R(e){return e=(e||"").toLowerCase(),x[e]||x[L[e]]}var w=[],E=Object.keys,x={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="
",y={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},I={"&":"&","<":"<",">":">"};return e.highlight=l,e.highlightAuto=f,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=R,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("clojure",function(e){var t={"builtin-name":"def defonce cond apply if-not if-let if not not= = < > <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"},r="a-zA-Z_\\-!.?+*=<>&#'",n="["+r+"]["+r+"0-9/;:]*",a="[-+]?\\d+(\\.\\d+)?",o={b:n,r:0},s={cN:"number",b:a,r:0},i=e.inherit(e.QSM,{i:null}),c=e.C(";","$",{r:0}),d={cN:"literal",b:/\b(true|false|nil)\b/},l={b:"[\\[\\{]",e:"[\\]\\}]"},m={cN:"comment",b:"\\^"+n},p=e.C("\\^\\{","\\}"),u={cN:"symbol",b:"[:]{1,2}"+n},f={b:"\\(",e:"\\)"},h={eW:!0,r:0},y={k:t,l:n,cN:"name",b:n,starts:h},b=[f,i,m,p,c,u,l,s,d,o];return f.c=[e.C("comment",""),y,h],h.c=b,l.c=b,{aliases:["clj"],i:/\S/,c:[f,i,m,p,c,u,l,s,d]}});hljs.registerLanguage("clojure-repl",function(e){return{c:[{cN:"meta",b:/^([\w.-]+|\s*#_)=>/,starts:{e:/$/,sL:"clojure"}}]}}); \ No newline at end of file diff --git a/docs/codox/js/jquery.min.js b/docs/codox/js/jquery.min.js new file mode 100644 index 0000000..73f33fb --- /dev/null +++ b/docs/codox/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f +}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML="
a",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/\s*$/g,sb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:l.htmlSerialize?[0,"",""]:[1,"X
","
"]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?""!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("