diff --git a/README.md b/README.md
index 21064bf..309c761 100644
--- a/README.md
+++ b/README.md
@@ -6,28 +6,92 @@ A Clojure library designed to provide simple interationalisation of user-facing
To use this library in your project, add the following leiningen dependency:
- [org.clojars.simon_brooke/internationalisation "1.0.0"]
+ [org.clojars.simon_brooke/internationalisation "1.0.4"]
To use it in your namespace, require:
- [scot.weft.i18n.core :refer [get-messages]]
+ [scot.weft.i18n.core :refer [get-message get-messages]]
-There is only one function you should need to use:
+There is only two functions you may need to use:
### get-messages
- (get-messages accept-language-header resource-path default-locale)
+```clojure
+(get-messages accept-language-header resource-path default-locale)
+```
+Return the most acceptable messages collection we have given this `accept-language-header`.
-Return the most acceptable messages collection we have given this accept-language-header. Use this function instrad of the unmemoized variant raw-get-messages, as performance will be very much better.
+* `accept-language-header` should be a string representing the value of an RFC 2616 Accept-Language header;
+* `resource-path` should be a string representing the fully-qualified path name of the directory in which message files are stored;
+* `default-locale` should be a string representing a locale specifier to use if no acceptable locale can be identified.
-* `accept-language-header` should be the value of an RFC 2616 Accept-Language header;
-* `resource-path` should be the fully-qualified path name of the directory in which message files are stored;
-* `default-locale` should be a locale specifier to use if no acceptable locale can be identified.
+For example:
+```clojure
+(get-messages "en-GB;q=0.9, fr-FR" "i18n" "en-GB")
+```
Returns a map of message keys to strings.
See [RFC 2616](https://www.ietf.org/rfc/rfc2616.txt).
+**NOTE THAT** `get-messages` is [memoized](https://clojuredocs.org/clojure.core/memoize) resulting in faster response when called repeatedly with similar arguments.
+
+### get-message
+
+A wrapper around `get-messages` to resolve a single, particular message.
+```clojure
+(get-message token)
+
+(get-message token accept-language-header)
+
+(get-message token accept-language-header resource-path default-locale)
+```
+
+where
+
+* `token` is the Clojure [keyword](https://clojuredocs.org/clojure.core/keyword) which identifies the particular message you want to retrieve;
+
+and all the other arguments are as defined above.
+
+For example:
+```clojure
+(get-message :pipe)
+
+(get-message :pipe "en-GB;q=0.9, fr-FR")
+
+(get-message :pipe "de-DE" "i18n" "ru")
+```
+
+So how does this work? When one calls `(get-message token accept-language-header)`, how does it know where to find resources? The answer is that there are two dynamic variables:
+
+* `*resource-path*`, the default path within the resources space on which
+ translation files will be sought. Initialised to `i18n`.
+* `*default-language*`, the language tag for the language to use when no
+ otherwise suitable language can be identified. Initialised to the default
+ language of the runtime session, so this may well be different on your
+ machine from someone elses running identical software.
+
+Thus
+```clojure
+(binding [*resource-path* "language-files"
+ *default-language* "en-CA"]
+ (get-message :pipe "en-GB;q=0.9, fr-FR")
+)
+```
+and
+```clojure
+(get-message :pipe "en-GB;q=0.9, fr-FR" "language-files" "en-CA")
+```
+are effectively the same.
+
+The intelligent reader will note that if one calls
+```clojure
+(get-message :pipe)
+```
+there's no mechanism to set the `accept-header`. This is true. The expected use case for this arity of the function is in desktop applications where the locale of the local machine will always be the correct locale to use. The two-argument arity of the function is intended for web applications, where different clients may have different linguistic needs.
+
+**NOTE THAT** `get-message` is also memoized, and for the same reason.
+
## The translation files
Obviously, this only works if you provide files with translations of your interesting strings. These files should contain Clojure maps, and the file names should be the locale string for which the file is relevent followed by the extension ".edn". All the translation files should be in the same directory.
diff --git a/doc/intro.md b/doc/intro.md
index f961eda..309c761 100644
--- a/doc/intro.md
+++ b/doc/intro.md
@@ -1,31 +1,97 @@
-# Introduction to internationalisation
+# internationalisation
+
+A Clojure library designed to provide simple interationalisation of user-facing messages.
## Usage
To use this library in your project, add the following leiningen dependency:
- [org.clojars.simon_brooke/internationalisation "1.0.0"]
+ [org.clojars.simon_brooke/internationalisation "1.0.4"]
To use it in your namespace, require:
- [scot.weft.i18n.core :refer [get-messages]]
+ [scot.weft.i18n.core :refer [get-message get-messages]]
-There is only one function you should need to use:
+There is only two functions you may need to use:
### get-messages
- (get-messages accept-language-header resource-path default-locale)
+```clojure
+(get-messages accept-language-header resource-path default-locale)
+```
+Return the most acceptable messages collection we have given this `accept-language-header`.
-Return the most acceptable messages collection we have given this accept-language-header. Use this function instrad of the unmemoized variant raw-get-messages, as performance will be very much better.
+* `accept-language-header` should be a string representing the value of an RFC 2616 Accept-Language header;
+* `resource-path` should be a string representing the fully-qualified path name of the directory in which message files are stored;
+* `default-locale` should be a string representing a locale specifier to use if no acceptable locale can be identified.
-* `accept-language-header` should be the value of an RFC 2616 Accept-Language header;
-* `resource-path` should be the fully-qualified path name of the directory in which message files are stored;
-* `default-locale` should be a locale specifier to use if no acceptable locale can be identified.
+For example:
+```clojure
+(get-messages "en-GB;q=0.9, fr-FR" "i18n" "en-GB")
+```
Returns a map of message keys to strings.
See [RFC 2616](https://www.ietf.org/rfc/rfc2616.txt).
+**NOTE THAT** `get-messages` is [memoized](https://clojuredocs.org/clojure.core/memoize) resulting in faster response when called repeatedly with similar arguments.
+
+### get-message
+
+A wrapper around `get-messages` to resolve a single, particular message.
+```clojure
+(get-message token)
+
+(get-message token accept-language-header)
+
+(get-message token accept-language-header resource-path default-locale)
+```
+
+where
+
+* `token` is the Clojure [keyword](https://clojuredocs.org/clojure.core/keyword) which identifies the particular message you want to retrieve;
+
+and all the other arguments are as defined above.
+
+For example:
+```clojure
+(get-message :pipe)
+
+(get-message :pipe "en-GB;q=0.9, fr-FR")
+
+(get-message :pipe "de-DE" "i18n" "ru")
+```
+
+So how does this work? When one calls `(get-message token accept-language-header)`, how does it know where to find resources? The answer is that there are two dynamic variables:
+
+* `*resource-path*`, the default path within the resources space on which
+ translation files will be sought. Initialised to `i18n`.
+* `*default-language*`, the language tag for the language to use when no
+ otherwise suitable language can be identified. Initialised to the default
+ language of the runtime session, so this may well be different on your
+ machine from someone elses running identical software.
+
+Thus
+```clojure
+(binding [*resource-path* "language-files"
+ *default-language* "en-CA"]
+ (get-message :pipe "en-GB;q=0.9, fr-FR")
+)
+```
+and
+```clojure
+(get-message :pipe "en-GB;q=0.9, fr-FR" "language-files" "en-CA")
+```
+are effectively the same.
+
+The intelligent reader will note that if one calls
+```clojure
+(get-message :pipe)
+```
+there's no mechanism to set the `accept-header`. This is true. The expected use case for this arity of the function is in desktop applications where the locale of the local machine will always be the correct locale to use. The two-argument arity of the function is intended for web applications, where different clients may have different linguistic needs.
+
+**NOTE THAT** `get-message` is also memoized, and for the same reason.
+
## The translation files
Obviously, this only works if you provide files with translations of your interesting strings. These files should contain Clojure maps, and the file names should be the locale string for which the file is relevent followed by the extension ".edn". All the translation files should be in the same directory.
diff --git a/docs/MagrittePipe.jpeg b/docs/MagrittePipe.jpeg
new file mode 100644
index 0000000..71bb3ab
Binary files /dev/null and b/docs/MagrittePipe.jpeg differ
diff --git a/docs/cloverage/codecov.json b/docs/cloverage/codecov.json
new file mode 100644
index 0000000..08624a5
--- /dev/null
+++ b/docs/cloverage/codecov.json
@@ -0,0 +1,18 @@
+{"coverage":
+ {"scot/weft/i18n/core.clj":
+ [null, 1, 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, null, 1, null, 1, null, 1, null, null, null, null,
+ null, null, null, null, null, null, null, null, 1, null, 1, null, 1,
+ null, null, null, null, null, true, 119, null, true, 119, 6, 16, 16,
+ 16, 8, null, 18, 18, null, 18, 18, 9, null, 19, 19, 15, 15, null,
+ 15, 4, 20, 15, 15, 0, 0, null, 0, 15, 15, null, 10, null, 0, 0,
+ null, null, 1, null, null, null, null, null, null, null, null, 6, 6,
+ 5, 5, null, 5, 5, 1, null, null, 1, null, null, null, 13, 13, null,
+ 7, null, null, null, 1, null, null, null, null, null, null, null,
+ null, null, null, 13, 13, 8, 8, 8, 13, 13, 13, 2, 11, 5, 5, 5, 5, 3,
+ 3, 3, null, null, 1, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3,
+ 3, 3, null, 1, null, null, 1, null, null, null, null, null, null,
+ null, null, null, 1, null, 1, null, null, null, null, null, null,
+ null, null, null, 1, 3, null, 1, null, 1]}}
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..51eff4d
--- /dev/null
+++ b/docs/cloverage/coverage.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/cloverage/index.html b/docs/cloverage/index.html
new file mode 100644
index 0000000..7592895
--- /dev/null
+++ b/docs/cloverage/index.html
@@ -0,0 +1,42 @@
+
+
+
+
+ Coverage Summary
+
+
+
+
+ Namespace
+ Forms
+Forms %
+ Lines
+Lines %
+Total Blank Instrumented
+
+
+ scot.weft.i18n.core 333
34
+90.74 %
+ 86
2
5
+94.62 %
+216 23 93
+
+Totals:
+
+90.74 %
+
+94.62 %
+
+
+
+
diff --git a/docs/cloverage/scot/weft/i18n/core.clj.html b/docs/cloverage/scot/weft/i18n/core.clj.html
new file mode 100644
index 0000000..01c1586
--- /dev/null
+++ b/docs/cloverage/scot/weft/i18n/core.clj.html
@@ -0,0 +1,656 @@
+
+
+
+ scot/weft/i18n/core.clj
+
+
+
+ 001 (ns ^{:doc "Internationalisation."
+
+
+ 002 :author "Simon Brooke"}
+
+
+ 003 scot.weft.i18n.core
+
+
+ 004 (:require [clojure.java.io :as io]
+
+
+ 005 [clojure.pprint :refer [pprint]]
+
+
+ 006 [clojure.string :refer [join]]
+
+
+ 007 [instaparse.core :as insta]
+
+
+ 008 [taoensso.timbre :as timbre]
+
+
+ 009 [trptr.java-wrapper.locale :as locale])
+
+
+ 010 (:import [clojure.lang Keyword]))
+
+
+ 011
+
+
+ 012 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+ 013 ;;;;
+
+
+ 014 ;;;; scot.weft.i18n: a simple internationalisation library for Clojure.
+
+
+ 015 ;;;;
+
+
+ 016 ;;;; This library is distributed under the Eclipse Licence in the hope
+
+
+ 017 ;;;; that it may be useful, but without guarantee.
+
+
+ 018 ;;;;
+
+
+ 019 ;;;; Copyright (C) 2017 Simon Brooke
+
+
+ 020 ;;;;
+
+
+ 021 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+ 022
+
+
+ 023 (def ^:dynamic *resource-path*
+
+
+ 024 "The default path within the resources space on which translation files
+
+
+ 025 will be sought."
+
+
+ 026 "i18n")
+
+
+ 027
+
+
+ 028 (def ^:dynamic *default-language*
+
+
+ 029 "The default language to seek."
+
+
+ 030 (-> (locale/get-default) locale/to-language-tag))
+
+
+ 031
+
+
+ 032 (def accept-language-grammar
+
+
+ 033 "Grammar for `Accept-Language` headers"
+
+
+ 034 "HEADER := SPECIFIER | SPECIFIERS;
+
+
+ 035 SPECIFIERS:= SPECIFIER | SPECIFIER SPEC-SEP SPECIFIERS;
+
+
+ 036 SPEC-SEP := #',\\s*';
+
+
+ 037 SPECIFIER := LANGUAGE-TAG | LANGUAGE-TAG Q-SEP Q-VALUE;
+
+
+ 038 LANGUAGE-TAG := PRIMARY-TAG | PRIMARY-TAG '-' SUB-TAGS;
+
+
+ 039 PRIMARY-TAG := #'[a-zA-Z]+';
+
+
+ 040 SUB-TAGS := SUB-TAG | SUB-TAG '-' SUB-TAGS;
+
+
+ 041 SUB-TAG := #'[a-zA-Z0-9]+';
+
+
+ 042 Q-SEP := #';\\s*q='
+
+
+ 043 Q-VALUE := '1' | #'0.[0-9]+';")
+
+
+ 044
+
+
+ 045 (def parse-accept-language-header
+
+
+ 046 "Parse an `Accept-Language` header"
+
+
+ 047 (insta/parser accept-language-grammar))
+
+
+ 048
+
+
+ 049 (defn generate-accept-languages
+
+
+ 050 "From a `parse-tree` generated by the `language-specifier-grammar`, generate
+
+
+ 051 a list of maps each having a `:language` key, a `:preference` key and a
+
+
+ 052 `:qualifier` key."
+
+
+ 053 {:doc/format :markdown}
+
+
+ 054 [parse-tree]
+
+
+ 055 (if
+
+
+ 056 (nil? parse-tree)
+
+
+ 057 nil
+
+
+ 058 (case
+
+
+ 059 (first parse-tree)
+
+
+ 060 :HEADER (generate-accept-languages (second parse-tree))
+
+
+ 061 :SPECIFIERS (cons
+
+
+ 062 (generate-accept-languages (second parse-tree))
+
+
+ 063 (when (>= (count parse-tree) 3)
+
+
+ 064 (generate-accept-languages (nth parse-tree 3))))
+
+
+ 065 :SPEC-SEP nil
+
+
+ 066 :SPECIFIER (assoc
+
+
+ 067 (generate-accept-languages (second parse-tree))
+
+
+ 068 :preference
+
+
+ 069 (if
+
+
+ 070 (>= (count parse-tree) 3)
+
+
+ 071 (generate-accept-languages (nth parse-tree 3))
+
+
+ 072 1))
+
+
+ 073 :LANGUAGE-TAG (if
+
+
+ 074 (>= (count parse-tree) 3)
+
+
+ 075 (assoc
+
+
+ 076 (generate-accept-languages (second parse-tree))
+
+
+ 077 :qualifier
+
+
+ 078 (generate-accept-languages (nth parse-tree 3)))
+
+
+ 079 (generate-accept-languages (second parse-tree)))
+
+
+ 080 :PRIMARY-TAG {:language (second parse-tree) :qualifier "*"}
+
+
+ 081 :SUB-TAGS (if
+
+
+ 082 (>= (count parse-tree) 3)
+
+
+ 083 (str
+
+
+ 084 (generate-accept-languages (second parse-tree))
+
+
+ 085 "-"
+
+
+ 086 (generate-accept-languages (nth parse-tree 3)))
+
+
+ 087 (generate-accept-languages (second parse-tree)))
+
+
+ 088 :SUB-TAG (second parse-tree)
+
+
+ 089 :Q-SEP nil
+
+
+ 090 :Q-VALUE (read-string (second parse-tree))
+
+
+ 091 ;; default
+
+
+ 092 (do
+
+
+ 093 (timbre/error "Unable to parse header.")
+
+
+ 094 nil))))
+
+
+ 095
+
+
+ 096 (defn acceptable-languages
+
+
+ 097 "Generate an ordered list of acceptable languages, most-preferred first.
+
+
+ 098
+
+
+ 099 * `accept-language-header` should be the value of an RFC2616 `Accept-Language` header.
+
+
+ 100
+
+
+ 101 Returns a list of maps as generated by `generate-accept-languages`, in descending order
+
+
+ 102 of preference."
+
+
+ 103 {:doc/format :markdown}
+
+
+ 104 [accept-language-header]
+
+
+ 105 (let [parse-tree (parse-accept-language-header accept-language-header)]
+
+
+ 106 (if (vector? parse-tree)
+
+
+ 107 (reverse
+
+
+ 108 (sort-by
+
+
+ 109 :preference
+
+
+ 110 (generate-accept-languages
+
+
+ 111 parse-tree)))
+
+
+ 112 (timbre/error "Failed to parse Accept-Language header '" accept-language-header "':\n" (str parse-tree)))))
+
+
+ 113
+
+
+ 114
+
+
+ 115 (defn slurp-resource
+
+
+ 116 "Slurp the resource of this name and return its contents as a string; but if it doesn't
+
+
+ 117 exist log the fact and return nil, rather than throwing an exception."
+
+
+ 118 [name]
+
+
+ 119 (try
+
+
+ 120 (slurp (io/resource name))
+
+
+ 121 (catch Exception _
+
+
+ 122 (timbre/error (str "Resource at " name " does not exist."))
+
+
+ 123 nil)))
+
+
+ 124
+
+
+ 125
+
+
+ 126 (defn find-language-file-name
+
+
+ 127 "Find the name of a messages file on this resource path which matches this `language-spec`.
+
+
+ 128
+
+
+ 129 * `language-spec` should be either a map as generated by `generate-accept-languages`, or
+
+
+ 130 else a string;
+
+
+ 131 * `resource-path` should be the path name of the directory in which message files are stored,
+
+
+ 132 within the resources on the classpath.
+
+
+ 133
+
+
+ 134 Returns the name of an appropriate file if any is found, else nil."
+
+
+ 135 {:doc/format :markdown}
+
+
+ 136 [language-spec resource-path]
+
+
+ 137 (let [file-path (when
+
+
+ 138 (string? language-spec)
+
+
+ 139 (join
+
+
+ 140 java.io.File/separator
+
+
+ 141 [resource-path (str language-spec ".edn")]))
+
+
+ 142 contents (when file-path (slurp-resource file-path))]
+
+
+ 143 (cond
+
+
+ 144 contents
+
+
+ 145 file-path
+
+
+ 146 (map? language-spec)
+
+
+ 147 (or
+
+
+ 148 (find-language-file-name
+
+
+ 149 (str (:language language-spec) "-" (:qualifier language-spec))
+
+
+ 150 resource-path)
+
+
+ 151 (find-language-file-name
+
+
+ 152 (:language language-spec)
+
+
+ 153 resource-path)))))
+
+
+ 154
+
+
+ 155
+
+
+ 156 (defn raw-get-messages
+
+
+ 157 "Return the most acceptable messages collection we have given this `accept-language-header`.
+
+
+ 158 Do not use this function directly, use the memoized variant `get-messages`, as performance
+
+
+ 159 will be very much better.
+
+
+ 160
+
+
+ 161 * `accept-language-header` should be the value of an RFC2616 `Accept-Language` header;
+
+
+ 162 * `resource-path` should be the fully-qualified path name of the directory in which
+
+
+ 163 message files are stored;
+
+
+ 164 * `default-locale` should be a locale specifier to use if no acceptable locale can be
+
+
+ 165 identified.
+
+
+ 166
+
+
+ 167 Returns a map of message keys to strings; if no useable file is found, returns nil."
+
+
+ 168 {:doc/format :markdown}
+
+
+ 169 [^String accept-language-header ^String resource-path ^String default-locale]
+
+
+ 170 (let [file-path (first
+
+
+ 171 (remove
+
+
+ 172 nil?
+
+
+ 173 (map
+
+
+ 174 #(find-language-file-name % resource-path)
+
+
+ 175 (acceptable-languages accept-language-header))))]
+
+
+ 176 (timbre/debug (str "Found i18n file at '" file-path "'"))
+
+
+ 177 (try
+
+
+ 178 (read-string
+
+
+ 179 (slurp-resource
+
+
+ 180 (or
+
+
+ 181 file-path
+
+
+ 182 (join java.io.File/separator
+
+
+ 183 [resource-path
+
+
+ 184 (str default-locale ".edn")]))))
+
+
+ 185 (catch Exception any
+
+
+ 186 (timbre/error (str "Failed to load internationalisation because " (.getMessage any)))
+
+
+ 187 nil))))
+
+
+ 188
+
+
+ 189 (def get-messages
+
+
+ 190 "Return the most acceptable messages collection we have given this `accept-language-header`
+
+
+ 191
+
+
+ 192 * `accept-language-header` should be the value of an RFC2616 `Accept-Language` header;
+
+
+ 193 * `resource-path` should be the fully-qualified path name of the directory in which
+
+
+ 194 message files are stored;
+
+
+ 195 * `default-locale` should be a locale specifier to use if no acceptable locale can be
+
+
+ 196 identified.
+
+
+ 197
+
+
+ 198 Returns a map of message keys to strings.; if no useable file is found, returns nil."
+
+
+ 199 (memoize raw-get-messages))
+
+
+ 200
+
+
+ 201 (def get-message
+
+
+ 202 "Return the message keyed by this `token` from the most acceptable messages collection
+
+
+ 203 we have given this `accept-language-header`.
+
+
+ 204
+
+
+ 205 * `token` should be a clojure keyword identifying the message to be retrieved;
+
+
+ 206 * `accept-language-header` should be the value of an RFC2616 `Accept-Language` header;
+
+
+ 207 * `resource-path` should be the fully-qualified path name of the directory in which
+
+
+ 208 message files are stored;
+
+
+ 209 * `default-locale` should be a locale specifier to use if no acceptable locale can be
+
+
+ 210 identified."
+
+
+ 211 (fn ([^Keyword token ^String accept-language-header ^String resource-path ^String default-locale]
+
+
+ 212 ((get-messages accept-language-header resource-path default-locale) token))
+
+
+ 213 ([^Keyword token ^String accept-language-header]
+
+
+ 214 (get-message token accept-language-header *resource-path* *default-language*))
+
+
+ 215 ([^Keyword token]
+
+
+ 216 (get-message token nil *resource-path* *default-language*))))
+
+
+
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/index.html b/docs/codox/index.html
new file mode 100644
index 0000000..9250ac2
--- /dev/null
+++ b/docs/codox/index.html
@@ -0,0 +1,3 @@
+
+Internationalisation 1.0.3-SNAPSHOT Internationalisation 1.0.3-SNAPSHOT Internationalisation library for Clojure.
Installation To install, add the following dependency to your project or build file:
[org.clojars.simon_brooke/internationalisation "1.0.3-SNAPSHOT"] Topics Namespaces 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..a580553
--- /dev/null
+++ b/docs/codox/intro.html
@@ -0,0 +1,87 @@
+
+internationalisation internationalisation
+
A Clojure library designed to provide simple interationalisation of user-facing messages.
+
Usage
+
To use this library in your project, add the following leiningen dependency:
+
[org.clojars.simon_brooke/internationalisation "1.0.4"]
+
+
To use it in your namespace, require:
+
[scot.weft.i18n.core :refer [get-message get-messages]]
+
+
There is only two functions you may need to use:
+
get-messages
+
(get-messages accept-language-header resource-path default-locale)
+
+
Return the most acceptable messages collection we have given this accept-language-header
.
+
+ accept-language-header
should be a string representing the value of an RFC 2616 Accept-Language header;
+ resource-path
should be a string representing the fully-qualified path name of the directory in which message files are stored;
+ default-locale
should be a string representing a locale specifier to use if no acceptable locale can be identified.
+
+
For example:
+
(get-messages "en-GB;q=0.9, fr-FR" "i18n" "en-GB")
+
+
Returns a map of message keys to strings.
+
See RFC 2616 .
+
NOTE THAT get-messages
is memoized resulting in faster response when called repeatedly with similar arguments.
+
get-message
+
A wrapper around get-messages
to resolve a single, particular message.
+
(get-message token)
+
+(get-message token accept-language-header)
+
+(get-message token accept-language-header resource-path default-locale)
+
+
where
+
+ token
is the Clojure keyword which identifies the particular message you want to retrieve;
+
+
and all the other arguments are as defined above.
+
For example:
+
(get-message :pipe)
+
+(get-message :pipe "en-GB;q=0.9, fr-FR")
+
+(get-message :pipe "de-DE" "i18n" "ru")
+
+
So how does this work? When one calls (get-message token accept-language-header)
, how does it know where to find resources? The answer is that there are two dynamic variables:
+
+ *resource-path*
, the default path within the resources space on which translation files will be sought. Initialised to i18n
.
+ *default-language*
, the language tag for the language to use when no otherwise suitable language can be identified. Initialised to the default language of the runtime session, so this may well be different on your machine from someone elses running identical software.
+
+
Thus
+
(binding [*resource-path* "language-files"
+ *default-language* "en-CA"]
+ (get-message :pipe "en-GB;q=0.9, fr-FR")
+)
+
+
and
+
(get-message :pipe "en-GB;q=0.9, fr-FR" "language-files" "en-CA")
+
+
are effectively the same.
+
The intelligent reader will note that if one calls
+
(get-message :pipe)
+
+
there’s no mechanism to set the accept-header
. This is true. The expected use case for this arity of the function is in desktop applications where the locale of the local machine will always be the correct locale to use. The two-argument arity of the function is intended for web applications, where different clients may have different linguistic needs.
+
NOTE THAT get-message
is also memoized, and for the same reason.
+
The translation files
+
Obviously, this only works if you provide files with translations of your interesting strings. These files should contain Clojure maps, and the file names should be the locale string for which the file is relevent followed by the extension “.edn”. All the translation files should be in the same directory.
+
In this project you will find two very simple example files, which should give you the idea:
+
en-GB.edn
+
;;;; This is a British English translation file.
+
+{:pipe "This is not a pipe"}
+
+
fr-FR.edn
+
;;;; This is a French translation file.
+
+{:pipe "Ceci n'est pas une pipe."}
+
+
Documentation
+
Documentation may be generated by running
+
lein codox
+
+
License
+
Copyright © 2017 Simon Brooke
+
Distributed under the Eclipse Public License either version 1.0 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+=""+t(e)+">"}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>$2>")+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>$2>");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("")).appendTo(b.documentElement),b=(Db[0].contentWindow||Db[0].contentDocument).document,b.write(),b.close(),c=Fb(a,b),Db.detach()),Eb[a]=c),c}!function(){var a,b,c=z.createElement("div"),d="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";c.innerHTML=" a ",a=c.getElementsByTagName("a")[0],a.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(a.style.opacity),l.cssFloat=!!a.style.cssFloat,c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===c.style.backgroundClip,a=c=null,l.shrinkWrapBlocks=function(){var a,c,e,f;if(null==b){if(a=z.getElementsByTagName("body")[0],!a)return;f="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",c=z.createElement("div"),e=z.createElement("div"),a.appendChild(c).appendChild(e),b=!1,typeof e.style.zoom!==L&&(e.style.cssText=d+";width:1px;padding:1px;zoom:1",e.innerHTML="
",e.firstChild.style.width="5px",b=3!==e.offsetWidth),a.removeChild(c),a=c=e=null}return b}}();var Hb=/^margin/,Ib=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Jb,Kb,Lb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Jb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),Ib.test(g)&&Hb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):z.documentElement.currentStyle&&(Jb=function(a){return a.currentStyle},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ib.test(g)&&!Lb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Mb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h=z.createElement("div"),i="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",j="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";h.innerHTML=" a ",b=h.getElementsByTagName("a")[0],b.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(b.style.opacity),l.cssFloat=!!b.style.cssFloat,h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,b=h=null,n.extend(l,{reliableHiddenOffsets:function(){if(null!=c)return c;var a,b,d,e=z.createElement("div"),f=z.getElementsByTagName("body")[0];if(f)return e.setAttribute("className","t"),e.innerHTML=" a ",a=z.createElement("div"),a.style.cssText=i,f.appendChild(a).appendChild(e),e.innerHTML="",b=e.getElementsByTagName("td"),b[0].style.cssText="padding:0;margin:0;border:0;display:none",d=0===b[0].offsetHeight,b[0].style.display="",b[1].style.display="none",c=d&&0===b[0].offsetHeight,f.removeChild(a),e=f=null,c},boxSizing:function(){return null==d&&k(),d},boxSizingReliable:function(){return null==e&&k(),e},pixelPosition:function(){return null==f&&k(),f},reliableMarginRight:function(){var b,c,d,e;if(null==g&&a.getComputedStyle){if(b=z.getElementsByTagName("body")[0],!b)return;c=z.createElement("div"),d=z.createElement("div"),c.style.cssText=i,b.appendChild(c).appendChild(d),e=d.appendChild(z.createElement("div")),e.style.cssText=d.style.cssText=j,e.style.marginRight=e.style.width="0",d.style.width="1px",g=!parseFloat((a.getComputedStyle(e,null)||{}).marginRight),b.removeChild(c)}return g}});function k(){var b,c,h=z.getElementsByTagName("body")[0];h&&(b=z.createElement("div"),c=z.createElement("div"),b.style.cssText=i,h.appendChild(b).appendChild(c),c.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;display:block;padding:1px;border:1px;width:4px;margin-top:1%;top:1%",n.swap(h,null!=h.style.zoom?{zoom:1}:{},function(){d=4===c.offsetWidth}),e=!0,f=!1,g=!0,a.getComputedStyle&&(f="1%"!==(a.getComputedStyle(c,null)||{}).top,e="4px"===(a.getComputedStyle(c,null)||{width:"4px"}).width),h.removeChild(b),c=h=null)}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Nb=/alpha\([^)]*\)/i,Ob=/opacity\s*=\s*([^)]*)/,Pb=/^(none|table(?!-c[ea]).+)/,Qb=new RegExp("^("+T+")(.*)$","i"),Rb=new RegExp("^([+-])=("+T+")","i"),Sb={position:"absolute",visibility:"hidden",display:"block"},Tb={letterSpacing:0,fontWeight:400},Ub=["Webkit","O","Moz","ms"];function Vb(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ub.length;while(e--)if(b=Ub[e]+c,b in a)return b;return d}function Wb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=n._data(d,"olddisplay",Gb(d.nodeName)))):f[g]||(e=V(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Xb(a,b,c){var d=Qb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Yb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Zb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Jb(a),g=l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Kb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ib.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Yb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Kb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=Vb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Rb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]="",i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Vb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Kb(a,b,d)),"normal"===f&&b in Tb&&(f=Tb[b]),""===c||c?(e=parseFloat(f),c===!0||n.isNumeric(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&Pb.test(n.css(a,"display"))?n.swap(a,Sb,function(){return Zb(a,b,d)}):Zb(a,b,d):void 0},set:function(a,c,d){var e=d&&Jb(a);return Xb(a,c,d?Yb(a,b,d,l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Ob.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Nb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Nb.test(f)?f.replace(Nb,e):f+" "+e)}}),n.cssHooks.marginRight=Mb(l.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},Kb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Hb.test(a)||(n.cssHooks[a+b].set=Xb)}),n.fn.extend({css:function(a,b){return W(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Jb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)
+},a,b,arguments.length>1)},show:function(){return Wb(this,!0)},hide:function(){return Wb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function $b(a,b,c,d,e){return new $b.prototype.init(a,b,c,d,e)}n.Tween=$b,$b.prototype={constructor:$b,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=$b.propHooks[this.prop];return a&&a.get?a.get(this):$b.propHooks._default.get(this)},run:function(a){var b,c=$b.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):$b.propHooks._default.set(this),this}},$b.prototype.init.prototype=$b.prototype,$b.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},$b.propHooks.scrollTop=$b.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=$b.prototype.init,n.fx.step={};var _b,ac,bc=/^(?:toggle|show|hide)$/,cc=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),dc=/queueHooks$/,ec=[jc],fc={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=cc.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&cc.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function gc(){return setTimeout(function(){_b=void 0}),_b=n.now()}function hc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=U[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function ic(a,b,c){for(var d,e=(fc[b]||[]).concat(fc["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function jc(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&V(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k=Gb(a.nodeName),"none"===j&&(j=k),"inline"===j&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==k?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],bc.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}if(!n.isEmptyObject(o)){r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=ic(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function kc(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function lc(a,b,c){var d,e,f=0,g=ec.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=_b||gc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:_b||gc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(kc(k,j.opts.specialEasing);g>f;f++)if(d=ec[f].call(j,a,k,j.opts))return d;return n.map(k,ic,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(lc,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],fc[c]=fc[c]||[],fc[c].unshift(b)},prefilter:function(a,b){b?ec.unshift(a):ec.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=lc(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&dc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(hc(b,!0),a,d,e)}}),n.each({slideDown:hc("show"),slideUp:hc("hide"),slideToggle:hc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(_b=n.now();ca ",a=e.getElementsByTagName("a")[0],c=z.createElement("select"),d=c.appendChild(z.createElement("option")),b=e.getElementsByTagName("input")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==e.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=d.selected,l.enctype=!!z.createElement("form").enctype,c.disabled=!0,l.optDisabled=!d.disabled,b=z.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value,a=b=c=d=e=null}();var mc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(mc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.text(a)}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var nc,oc,pc=n.expr.attrHandle,qc=/^(?:checked|selected)$/i,rc=l.getSetAttribute,sc=l.input;n.fn.extend({attr:function(a,b){return W(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===L?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?oc:nc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(F);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?sc&&rc||!qc.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(rc?c:d)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),oc={set:function(a,b,c){return b===!1?n.removeAttr(a,c):sc&&rc||!qc.test(c)?a.setAttribute(!rc&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=pc[b]||n.find.attr;pc[b]=sc&&rc||!qc.test(b)?function(a,b,d){var e,f;return d||(f=pc[b],pc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,pc[b]=f),e}:function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),sc&&rc||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):nc&&nc.set(a,b,c)}}),rc||(nc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},pc.id=pc.name=pc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:nc.set},n.attrHooks.contenteditable={set:function(a,b,c){nc.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var tc=/^(?:input|select|textarea|button|object)$/i,uc=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return W(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):tc.test(a.nodeName)||uc.test(a.nodeName)&&a.href?0:-1}}}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var vc=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(F)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===L||"boolean"===c)&&(this.className&&n._data(this,"__className__",this.className),this.className=this.className||a===!1?"":n._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(vc," ").indexOf(b)>=0)return!0;return!1}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var wc=n.now(),xc=/\?/,yc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(yc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var zc,Ac,Bc=/#.*$/,Cc=/([?&])_=[^&]*/,Dc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Ec=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Fc=/^(?:GET|HEAD)$/,Gc=/^\/\//,Hc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ic={},Jc={},Kc="*/".concat("*");try{Ac=location.href}catch(Lc){Ac=z.createElement("a"),Ac.href="",Ac=Ac.href}zc=Hc.exec(Ac.toLowerCase())||[];function Mc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(F)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nc(a,b,c,d){var e={},f=a===Jc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Oc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Pc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Qc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ac,type:"GET",isLocal:Ec.test(zc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Oc(Oc(a,n.ajaxSettings),b):Oc(n.ajaxSettings,a)},ajaxPrefilter:Mc(Ic),ajaxTransport:Mc(Jc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Dc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||Ac)+"").replace(Bc,"").replace(Gc,zc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(F)||[""],null==k.crossDomain&&(c=Hc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===zc[1]&&c[2]===zc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(zc[3]||("http:"===zc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),Nc(Ic,k,b,v),2===t)return v;h=k.global,h&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Fc.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(xc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Cc.test(e)?e.replace(Cc,"$1_="+wc++):e+(xc.test(e)?"&":"?")+"_="+wc++)),k.ifModified&&(n.lastModified[e]&&v.setRequestHeader("If-Modified-Since",n.lastModified[e]),n.etag[e]&&v.setRequestHeader("If-None-Match",n.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Kc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Nc(Jc,k,b,v)){v.readyState=1,h&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Pc(k,v,c)),u=Qc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(n.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!l.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||n.css(a,"display"))},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var Rc=/%20/g,Sc=/\[\]$/,Tc=/\r?\n/g,Uc=/^(?:submit|button|image|reset|file)$/i,Vc=/^(?:input|select|textarea|keygen)/i;function Wc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Sc.test(a)?d(a,e):Wc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Wc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Wc(c,a[c],b,e);return d.join("&").replace(Rc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Vc.test(this.nodeName)&&!Uc.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Tc,"\r\n")}}):{name:b.name,value:c.replace(Tc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&$c()||_c()}:$c;var Xc=0,Yc={},Zc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Yc)Yc[a](void 0,!0)}),l.cors=!!Zc&&"withCredentials"in Zc,Zc=l.ajax=!!Zc,Zc&&n.ajaxTransport(function(a){if(!a.crossDomain||l.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Xc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Yc[g],b=void 0,f.onreadystatechange=n.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Yc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function $c(){try{return new a.XMLHttpRequest}catch(b){}}function _c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=z.head||n("head")[0]||z.documentElement;return{send:function(d,e){b=z.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var ad=[],bd=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=ad.pop()||n.expando+"_"+wc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(bd.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&bd.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(bd,"$1"+e):b.jsonp!==!1&&(b.url+=(xc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,ad.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||z;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var cd=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&cd)return cd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h,a.length),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&n.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?n("").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n});
diff --git a/docs/codox/js/page_effects.js b/docs/codox/js/page_effects.js
new file mode 100644
index 0000000..fdacbf8
--- /dev/null
+++ b/docs/codox/js/page_effects.js
@@ -0,0 +1,112 @@
+function visibleInParent(element) {
+ var position = $(element).position().top
+ return position > -50 && position < ($(element).offsetParent().height() - 50)
+}
+
+function hasFragment(link, fragment) {
+ return $(link).attr("href").indexOf("#" + fragment) != -1
+}
+
+function findLinkByFragment(elements, fragment) {
+ return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
+}
+
+function scrollToCurrentVarLink(elements) {
+ var elements = $(elements);
+ var parent = elements.offsetParent();
+
+ if (elements.length == 0) return;
+
+ var top = elements.first().position().top;
+ var bottom = elements.last().position().top + elements.last().height();
+
+ if (top >= 0 && bottom <= parent.height()) return;
+
+ if (top < 0) {
+ parent.scrollTop(parent.scrollTop() + top);
+ }
+ else if (bottom > parent.height()) {
+ parent.scrollTop(parent.scrollTop() + bottom - parent.height());
+ }
+}
+
+function setCurrentVarLink() {
+ $('.secondary a').parent().removeClass('current')
+ $('.anchor').
+ filter(function(index) { return visibleInParent(this) }).
+ each(function(index, element) {
+ findLinkByFragment(".secondary a", element.id).
+ parent().
+ addClass('current')
+ });
+ scrollToCurrentVarLink('.secondary .current');
+}
+
+var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
+
+function scrollPositionId(element) {
+ var directory = window.location.href.replace(/[^\/]+\.html$/, '')
+ return 'scroll::' + $(element).attr('id') + '::' + directory
+}
+
+function storeScrollPosition(element) {
+ if (!hasStorage) return;
+ localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
+ localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
+}
+
+function recallScrollPosition(element) {
+ if (!hasStorage) return;
+ $(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
+ $(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
+}
+
+function persistScrollPosition(element) {
+ recallScrollPosition(element)
+ $(element).scroll(function() { storeScrollPosition(element) })
+}
+
+function sidebarContentWidth(element) {
+ var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
+ return Math.max.apply(Math, widths)
+}
+
+function calculateSize(width, snap, margin, minimum) {
+ if (width == 0) {
+ return 0
+ }
+ else {
+ return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
+ }
+}
+
+function resizeSidebars() {
+ var primaryWidth = sidebarContentWidth('.primary')
+ var secondaryWidth = 0
+
+ if ($('.secondary').length != 0) {
+ secondaryWidth = sidebarContentWidth('.secondary')
+ }
+
+ // snap to grid
+ primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
+ secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
+
+ $('.primary').css('width', primaryWidth)
+ $('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
+
+ if (secondaryWidth > 0) {
+ $('#content').css('left', primaryWidth + secondaryWidth + 2)
+ }
+ else {
+ $('#content').css('left', primaryWidth + 1)
+ }
+}
+
+$(window).ready(resizeSidebars)
+$(window).ready(setCurrentVarLink)
+$(window).ready(function() { persistScrollPosition('.primary')})
+$(window).ready(function() {
+ $('#content').scroll(setCurrentVarLink)
+ $(window).resize(setCurrentVarLink)
+})
diff --git a/docs/codox/scot.weft.i18n.core.html b/docs/codox/scot.weft.i18n.core.html
new file mode 100644
index 0000000..085edec
--- /dev/null
+++ b/docs/codox/scot.weft.i18n.core.html
@@ -0,0 +1,30 @@
+
+
scot.weft.i18n.core documentation scot.weft.i18n.core *default-language* dynamic
The default language to seek.
*resource-path* dynamic
The default path within the resources space on which translation files will be sought.
accept-language-grammar
Grammar for Accept-Language
headers
acceptable-languages (acceptable-languages accept-language-header)
Generate an ordered list of acceptable languages, most-preferred first.
+
+ accept-language-header
should be the value of an RFC2616 Accept-Language
header.
+
+
Returns a list of maps as generated by generate-accept-languages
, in descending order of preference.
find-language-file-name (find-language-file-name language-spec resource-path)
Find the name of a messages file on this resource path which matches this language-spec
.
+
+ language-spec
should be either a map as generated by generate-accept-languages
, or else a string;
+ resource-path
should be the path name of the directory in which message files are stored, within the resources on the classpath.
+
+
Returns the name of an appropriate file if any is found, else nil.
generate-accept-languages (generate-accept-languages parse-tree)
From a parse-tree
generated by the language-specifier-grammar
, generate a list of maps each having a :language
key, a :preference
key and a :qualifier
key.
get-message
Return the message keyed by this token
from the most acceptable messages collection we have given this accept-language-header
.
+
+ token
should be a clojure keyword identifying the message to be retrieved;
+ accept-language-header
should be the value of an RFC2616 Accept-Language
header;
+ resource-path
should be the fully-qualified path name of the directory in which message files are stored;
+ default-locale
should be a locale specifier to use if no acceptable locale can be identified.
+ get-messages
Return the most acceptable messages collection we have given this accept-language-header
+
+ accept-language-header
should be the value of an RFC2616 Accept-Language
header;
+ resource-path
should be the fully-qualified path name of the directory in which message files are stored;
+ default-locale
should be a locale specifier to use if no acceptable locale can be identified.
+
+
Returns a map of message keys to strings.; if no useable file is found, returns nil.
raw-get-messages (raw-get-messages accept-language-header resource-path default-locale)
Return the most acceptable messages collection we have given this accept-language-header
. Do not use this function directly, use the memoized variant get-messages
, as performance will be very much better.
+
+ accept-language-header
should be the value of an RFC2616 Accept-Language
header;
+ resource-path
should be the fully-qualified path name of the directory in which message files are stored;
+ default-locale
should be a locale specifier to use if no acceptable locale can be identified.
+
+
Returns a map of message keys to strings; if no useable file is found, returns nil.
slurp-resource (slurp-resource name)
Slurp the resource of this name and return its contents as a string; but if it doesn’t exist log the fact and return nil, rather than throwing an exception.
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..143e182
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,17 @@
+
+
+
+
Internationalisation: Documentation
+
+
+
+
Internationalisation: Documentation
+
+
Illustration: La Trahison des Images by
+ René Magritte
+
+
+
diff --git a/project.clj b/project.clj
index 227868c..eaaf7a1 100644
--- a/project.clj
+++ b/project.clj
@@ -1,13 +1,21 @@
-(defproject org.clojars.simon_brooke/internationalisation "1.0.3"
+(defproject org.clojars.simon_brooke/internationalisation "1.0.3-SNAPSHOT"
+ :cloverage {:output "docs/cloverage"
+ :codecov? true
+ :emma-xml? true}
+ :codox {:metadata {:doc "**TODO**: write docs"
+ :doc/format :markdown}
+ :output-path "docs/codox"
+ :source-uri "https://github.com/simon-brooke/internationalisation/blob/master/{filepath}#L{line}"}
+ :dependencies [[org.clojure/clojure "1.11.1"]
+ [com.taoensso/timbre "6.0.4"]
+ [instaparse "1.4.12"]
+ [trptr/java-wrapper "0.2.3"]]
:description "Internationalisation library for Clojure"
- :url "https://github.com/simon-brooke/internationalisation"
+ :lein-release {:deploy-via :clojars}
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
- :dependencies [[org.clojure/clojure "1.7.0"]
- [com.taoensso/timbre "4.10.0"]
- [instaparse "1.4.7"]]
- :plugins [[lein-codox "0.10.3"]]
+ :plugins [[lein-cloverage "1.2.2"]
+ [lein-codox "0.10.7"]]
:profiles {:dev {:resource-paths ["resources"]}}
- :lein-release {:deploy-via :clojars}
:signing {:gpg-key "Simon Brooke (Stultus in monte)
"}
- )
+ :url "https://github.com/simon-brooke/internationalisation")
diff --git a/resources/i18n/ru.edn b/resources/i18n/ru.edn
new file mode 100644
index 0000000..7eca991
--- /dev/null
+++ b/resources/i18n/ru.edn
@@ -0,0 +1,3 @@
+;;;; This is a Russian translation file.
+
+{:pipe "это не труба."}
diff --git a/src/scot/weft/i18n/core.clj b/src/scot/weft/i18n/core.clj
index aa31157..0e2117c 100644
--- a/src/scot/weft/i18n/core.clj
+++ b/src/scot/weft/i18n/core.clj
@@ -1,11 +1,13 @@
(ns ^{:doc "Internationalisation."
:author "Simon Brooke"}
- scot.weft.i18n.core
+ scot.weft.i18n.core
(:require [clojure.java.io :as io]
[clojure.pprint :refer [pprint]]
[clojure.string :refer [join]]
[instaparse.core :as insta]
- [taoensso.timbre :as timbre]))
+ [taoensso.timbre :as timbre]
+ [trptr.java-wrapper.locale :as locale])
+ (:import [clojure.lang Keyword]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
@@ -18,6 +20,14 @@
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(def ^:dynamic *resource-path*
+ "The default path within the resources space on which translation files
+ will be sought."
+ "i18n")
+
+(def ^:dynamic *default-language*
+ "The default language to seek."
+ (-> (locale/get-default) locale/to-language-tag))
(def accept-language-grammar
"Grammar for `Accept-Language` headers"
@@ -32,12 +42,10 @@
Q-SEP := #';\\s*q='
Q-VALUE := '1' | #'0.[0-9]+';")
-
(def parse-accept-language-header
"Parse an `Accept-Language` header"
(insta/parser accept-language-grammar))
-
(defn generate-accept-languages
"From a `parse-tree` generated by the `language-specifier-grammar`, generate
a list of maps each having a `:language` key, a `:preference` key and a
@@ -45,47 +53,46 @@
{:doc/format :markdown}
[parse-tree]
(if
- (nil? parse-tree)
+ (nil? parse-tree)
nil
(case
- (first parse-tree)
+ (first parse-tree)
:HEADER (generate-accept-languages (second parse-tree))
:SPECIFIERS (cons
- (generate-accept-languages (second parse-tree))
- (if (>= (count parse-tree) 3)
- (generate-accept-languages (nth parse-tree 3))))
+ (generate-accept-languages (second parse-tree))
+ (when (>= (count parse-tree) 3)
+ (generate-accept-languages (nth parse-tree 3))))
:SPEC-SEP nil
:SPECIFIER (assoc
- (generate-accept-languages (second parse-tree))
- :preference
- (if
- (>= (count parse-tree) 3)
- (generate-accept-languages (nth parse-tree 3))
- 1))
+ (generate-accept-languages (second parse-tree))
+ :preference
+ (if
+ (>= (count parse-tree) 3)
+ (generate-accept-languages (nth parse-tree 3))
+ 1))
:LANGUAGE-TAG (if
- (>= (count parse-tree) 3)
+ (>= (count parse-tree) 3)
(assoc
- (generate-accept-languages (second parse-tree))
- :qualifier
- (generate-accept-languages (nth parse-tree 3)))
+ (generate-accept-languages (second parse-tree))
+ :qualifier
+ (generate-accept-languages (nth parse-tree 3)))
(generate-accept-languages (second parse-tree)))
:PRIMARY-TAG {:language (second parse-tree) :qualifier "*"}
:SUB-TAGS (if
- (>= (count parse-tree) 3)
+ (>= (count parse-tree) 3)
(str
- (generate-accept-languages (second parse-tree))
- "-"
- (generate-accept-languages (nth parse-tree 3)))
+ (generate-accept-languages (second parse-tree))
+ "-"
+ (generate-accept-languages (nth parse-tree 3)))
(generate-accept-languages (second parse-tree)))
:SUB-TAG (second parse-tree)
:Q-SEP nil
:Q-VALUE (read-string (second parse-tree))
;; default
- (let [formatted-tree (with-out-str (pprint parse-tree))]
+ (do
(timbre/error "Unable to parse header.")
nil))))
-
(defn acceptable-languages
"Generate an ordered list of acceptable languages, most-preferred first.
@@ -98,10 +105,10 @@
(let [parse-tree (parse-accept-language-header accept-language-header)]
(if (vector? parse-tree)
(reverse
- (sort-by
- :preference
- (generate-accept-languages
- parse-tree)))
+ (sort-by
+ :preference
+ (generate-accept-languages
+ parse-tree)))
(timbre/error "Failed to parse Accept-Language header '" accept-language-header "':\n" (str parse-tree)))))
@@ -111,7 +118,7 @@
[name]
(try
(slurp (io/resource name))
- (catch Exception any
+ (catch Exception _
(timbre/error (str "Resource at " name " does not exist."))
nil)))
@@ -127,23 +134,23 @@
Returns the name of an appropriate file if any is found, else nil."
{:doc/format :markdown}
[language-spec resource-path]
- (let [file-path (if
- (string? language-spec)
+ (let [file-path (when
+ (string? language-spec)
(join
- java.io.File/separator
- [resource-path (str language-spec ".edn")]))
- contents (if file-path (slurp-resource file-path))]
+ java.io.File/separator
+ [resource-path (str language-spec ".edn")]))
+ contents (when file-path (slurp-resource file-path))]
(cond
contents
file-path
(map? language-spec)
(or
- (find-language-file-name
- (str (:language language-spec) "-" (:qualifier language-spec))
- resource-path)
- (find-language-file-name
- (:language language-spec)
- resource-path)))))
+ (find-language-file-name
+ (str (:language language-spec) "-" (:qualifier language-spec))
+ resource-path)
+ (find-language-file-name
+ (:language language-spec)
+ resource-path)))))
(defn raw-get-messages
@@ -161,33 +168,49 @@
{:doc/format :markdown}
[^String accept-language-header ^String resource-path ^String default-locale]
(let [file-path (first
- (remove
- nil?
- (map
- #(find-language-file-name % resource-path)
- (acceptable-languages accept-language-header))))]
+ (remove
+ nil?
+ (map
+ #(find-language-file-name % resource-path)
+ (acceptable-languages accept-language-header))))]
(timbre/debug (str "Found i18n file at '" file-path "'"))
(try
(read-string
- (slurp-resource
- (or
- file-path
- (join java.io.File/separator
- [resource-path
- (str default-locale ".edn")]))))
+ (slurp-resource
+ (or
+ file-path
+ (join java.io.File/separator
+ [resource-path
+ (str default-locale ".edn")]))))
(catch Exception any
(timbre/error (str "Failed to load internationalisation because " (.getMessage any)))
nil))))
-
(def get-messages
"Return the most acceptable messages collection we have given this `accept-language-header`
- `accept-language-header` should be the value of an RFC2616 `Accept-Language` header;
- `resource-path` should be the fully-qualified path name of the directory in which
+ * `accept-language-header` should be the value of an RFC2616 `Accept-Language` header;
+ * `resource-path` should be the fully-qualified path name of the directory in which
message files are stored;
- `default-locale` should be a locale specifier to use if no acceptable locale can be
+ * `default-locale` should be a locale specifier to use if no acceptable locale can be
identified.
Returns a map of message keys to strings.; if no useable file is found, returns nil."
(memoize raw-get-messages))
+
+(def get-message
+ "Return the message keyed by this `token` from the most acceptable messages collection
+ we have given this `accept-language-header`.
+
+ * `token` should be a clojure keyword identifying the message to be retrieved;
+ * `accept-language-header` should be the value of an RFC2616 `Accept-Language` header;
+ * `resource-path` should be the fully-qualified path name of the directory in which
+ message files are stored;
+ * `default-locale` should be a locale specifier to use if no acceptable locale can be
+ identified."
+ (fn ([^Keyword token ^String accept-language-header ^String resource-path ^String default-locale]
+ ((get-messages accept-language-header resource-path default-locale) token))
+ ([^Keyword token ^String accept-language-header]
+ (get-message token accept-language-header *resource-path* *default-language*))
+ ([^Keyword token]
+ (get-message token nil *resource-path* *default-language*))))
\ No newline at end of file
diff --git a/test/scot/weft/i18n/test/core.clj b/test/scot/weft/i18n/test/core.clj
index e12a320..de3038d 100644
--- a/test/scot/weft/i18n/test/core.clj
+++ b/test/scot/weft/i18n/test/core.clj
@@ -1,7 +1,12 @@
(ns ^{:doc "Tests for Internationalisation."
:author "Simon Brooke"} scot.weft.i18n.test.core
- (:require [clojure.test :refer :all]
- [scot.weft.i18n.core :refer :all]))
+ (:require [clojure.test :refer [deftest is testing]]
+ [scot.weft.i18n.core :refer [*default-language*
+ acceptable-languages
+ generate-accept-languages
+ get-message
+ get-messages
+ parse-accept-language-header]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
@@ -14,174 +19,173 @@
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
(deftest test-generator
(testing "Generating normalised maps from parse trees"
(is
- (=
- 0.6
- (generate-accept-languages
- [:Q-VALUE "0.6"])))
+ (=
+ 0.6
+ (generate-accept-languages
+ [:Q-VALUE "0.6"])))
(is
- (=
- {:language "en", :qualifier "*"}
- (generate-accept-languages
- [:PRIMARY-TAG "en"])))
+ (=
+ {:language "en", :qualifier "*"}
+ (generate-accept-languages
+ [:PRIMARY-TAG "en"])))
(is
- (=
- {:language "en", :qualifier "*"}
- (generate-accept-languages
+ (=
+ {:language "en", :qualifier "*"}
+ (generate-accept-languages
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]])))
+ (is
+ (=
+ {:language "en", :qualifier "*", :preference 1}
+ (generate-accept-languages
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]]])))
+ (is
+ (=
+ {:language "en", :qualifier "GB", :preference 1}
+ (generate-accept-languages
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]
+ "-"
+ [:SUB-TAGS
+ [:SUB-TAG "GB"]]]])))
+ (is
+ (=
+ '({:language "en", :qualifier "GB", :preference 1})
+ (generate-accept-languages
+ [:SPECIFIERS
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]
+ "-"
+ [:SUB-TAGS
+ [:SUB-TAG "GB"]]]]])))
+ (is
+ (=
+ '({:language "en", :qualifier "US", :preference 0.8}
+ {:language "en", :qualifier "*", :preference 0.6})
+ (generate-accept-languages
+ [:SPECIFIERS
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]
+ "-"
+ [:SUB-TAGS
+ [:SUB-TAG "US"]]]
+ ";q="
+ [:Q-VALUE "0.8"]]
+ [:SPEC-SEP ","]
+ [:SPECIFIERS
+ [:SPECIFIER
[:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]])))
+ [:PRIMARY-TAG "en"]]
+ ";q="
+ [:Q-VALUE "0.6"]]]])))
(is
- (=
- {:language "en", :qualifier "*", :preference 1}
- (generate-accept-languages
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]]])))
- (is
- (=
- {:language "en", :qualifier "GB", :preference 1}
- (generate-accept-languages
+ (=
+ '({:language "en", :qualifier "GB", :preference 1}
+ {:language "en", :qualifier "US", :preference 0.8}
+ {:language "en", :qualifier "*", :preference 0.6})
+ (generate-accept-languages
+ [:HEADER
+ [:SPECIFIERS
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]
+ "-"
+ [:SUB-TAGS
+ [:SUB-TAG "GB"]]]]
+ [:SPEC-SEP ","]
+ [:SPECIFIERS
[:SPECIFIER
[:LANGUAGE-TAG
[:PRIMARY-TAG "en"]
"-"
[:SUB-TAGS
- [:SUB-TAG "GB"]]]])))
- (is
- (=
- '({:language "en", :qualifier "GB", :preference 1})
- (generate-accept-languages
+ [:SUB-TAG "US"]]]
+ ";q="
+ [:Q-VALUE "0.8"]]
+ [:SPEC-SEP ","]
[:SPECIFIERS
[:SPECIFIER
[:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]
- "-"
- [:SUB-TAGS
- [:SUB-TAG "GB"]]]]])))
- (is
- (=
- '({:language "en", :qualifier "US", :preference 0.8}
- {:language "en", :qualifier "*", :preference 0.6})
- (generate-accept-languages
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]
- "-"
- [:SUB-TAGS
- [:SUB-TAG "US"]]]
+ [:PRIMARY-TAG "en"]]
";q="
- [:Q-VALUE "0.8"]]
- [:SPEC-SEP ","]
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]]
- ";q="
- [:Q-VALUE "0.6"]]]])))
- (is
- (=
- '({:language "en", :qualifier "GB", :preference 1}
- {:language "en", :qualifier "US", :preference 0.8}
- {:language "en", :qualifier "*", :preference 0.6})
- (generate-accept-languages
- [:HEADER
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]
- "-"
- [:SUB-TAGS
- [:SUB-TAG "GB"]]]]
- [:SPEC-SEP ","]
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]
- "-"
- [:SUB-TAGS
- [:SUB-TAG "US"]]]
- ";q="
- [:Q-VALUE "0.8"]]
- [:SPEC-SEP ","]
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]]
- ";q="
- [:Q-VALUE "0.6"]]]]]])))))
+ [:Q-VALUE "0.6"]]]]]])))))
(deftest test-parser
(testing "Generating parse trees from `Accept-Language` headers"
(is
- (=
- [:HEADER
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "dk"]]]]]
- (parse-accept-language-header "dk"))
- "Should accept a basic language specifier.")
+ (=
+ [:HEADER
+ [:SPECIFIERS
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "dk"]]]]]
+ (parse-accept-language-header "dk"))
+ "Should accept a basic language specifier.")
(is
- (=
- [:HEADER
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]
- "-"
- [:SUB-TAGS [:SUB-TAG "GB"]]]]]]
- (parse-accept-language-header "en-GB"))
- "Should accept a basic locale.")
+ (=
+ [:HEADER
+ [:SPECIFIERS
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]
+ "-"
+ [:SUB-TAGS [:SUB-TAG "GB"]]]]]]
+ (parse-accept-language-header "en-GB"))
+ "Should accept a basic locale.")
(is
- (=
- [:HEADER
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]
- "-"
- [:SUB-TAGS [:SUB-TAG "GB"]]]
- [:Q-SEP ";q="]
- [:Q-VALUE "0.6"]]]]
- (parse-accept-language-header "en-GB;q=0.6"))
- "Should accept a q value.")
+ (=
+ [:HEADER
+ [:SPECIFIERS
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]
+ "-"
+ [:SUB-TAGS [:SUB-TAG "GB"]]]
+ [:Q-SEP ";q="]
+ [:Q-VALUE "0.6"]]]]
+ (parse-accept-language-header "en-GB;q=0.6"))
+ "Should accept a q value.")
(is
- (=
- [:HEADER
- [:SPECIFIERS
- [:SPECIFIER
- [:LANGUAGE-TAG
- [:PRIMARY-TAG "en"]
- "-"
- [:SUB-TAGS [:SUB-TAG "GB"]]]
- [:Q-SEP "; q="]
- [:Q-VALUE "0.6"]]]]
- (parse-accept-language-header "en-GB; q=0.6"))
- "Space after semi-colon should be tolerated.")
+ (=
+ [:HEADER
+ [:SPECIFIERS
+ [:SPECIFIER
+ [:LANGUAGE-TAG
+ [:PRIMARY-TAG "en"]
+ "-"
+ [:SUB-TAGS [:SUB-TAG "GB"]]]
+ [:Q-SEP "; q="]
+ [:Q-VALUE "0.6"]]]]
+ (parse-accept-language-header "en-GB; q=0.6"))
+ "Space after semi-colon should be tolerated.")
(is
- (=
- [:HEADER
- [:SPECIFIERS
- [:SPECIFIER [:LANGUAGE-TAG [:PRIMARY-TAG "en"]]]
- [:SPEC-SEP ","]
- [:SPECIFIERS
- [:SPECIFIER [:LANGUAGE-TAG [:PRIMARY-TAG "fr"]]]]]]
- (parse-accept-language-header "en,fr"))
- "Should accept multiple specifications.")
+ (=
+ [:HEADER
+ [:SPECIFIERS
+ [:SPECIFIER [:LANGUAGE-TAG [:PRIMARY-TAG "en"]]]
+ [:SPEC-SEP ","]
+ [:SPECIFIERS
+ [:SPECIFIER [:LANGUAGE-TAG [:PRIMARY-TAG "fr"]]]]]]
+ (parse-accept-language-header "en,fr"))
+ "Should accept multiple specifications.")
(is
- (=
- [:HEADER
- [:SPECIFIERS
- [:SPECIFIER [:LANGUAGE-TAG [:PRIMARY-TAG "en"]]]
- [:SPEC-SEP ", "]
- [:SPECIFIERS
- [:SPECIFIER [:LANGUAGE-TAG [:PRIMARY-TAG "fr"]]]]]]
- (parse-accept-language-header "en, fr"))
- "Space after comma should be tolerated.")
+ (=
+ [:HEADER
+ [:SPECIFIERS
+ [:SPECIFIER [:LANGUAGE-TAG [:PRIMARY-TAG "en"]]]
+ [:SPEC-SEP ", "]
+ [:SPECIFIERS
+ [:SPECIFIER [:LANGUAGE-TAG [:PRIMARY-TAG "fr"]]]]]]
+ (parse-accept-language-header "en, fr"))
+ "Space after comma should be tolerated.")
(is (vector? (parse-accept-language-header "en, fr"))
"If the header is valid, we should get a (parse tree) vector")
(is (not (vector? (parse-accept-language-header "")))
@@ -191,23 +195,29 @@
(deftest test-ordering
(testing "Languages specified are ordered correctly"
(is
- (=
- '({:language "en", :qualifier "GB", :preference 1}
- {:language "en", :qualifier "AU", :preference 0.8}
- {:language "en", :qualifier "US", :preference 0.6})
- (acceptable-languages "en-AU;q=0.8, en-GB, en-US;q=0.6")))))
+ (=
+ '({:language "en", :qualifier "GB", :preference 1}
+ {:language "en", :qualifier "AU", :preference 0.8}
+ {:language "en", :qualifier "US", :preference 0.6})
+ (acceptable-languages "en-AU;q=0.8, en-GB, en-US;q=0.6")))))
(deftest test-pipe
(testing "Top level functionality"
(is
- (=
- "This is not a pipe"
- (:pipe (get-messages "en-GB, fr-FR;q=0.9" "i18n" "en-GB"))))
+ (=
+ "This is not a pipe"
+ (:pipe (get-messages "en-GB, fr-FR;q=0.9" "i18n" "en-GB"))))
(is
- (=
- "Ceci n'est pas une pipe."
- (:pipe (get-messages "en-GB;q=0.9, fr-FR" "i18n" "en-GB"))))
+ (=
+ "Ceci n'est pas une pipe."
+ (:pipe (get-messages "en-GB;q=0.9, fr-FR" "i18n" "en-GB"))))
(is
- (= nil (get-messages "xx-XX;q=0.5, yy-YY" "i18n" "zz-ZZ"))
- "If no usable file is found, an exception should not be thrown.")))
+ (= nil (get-messages "xx-XX;q=0.5, yy-YY" "i18n" "zz-ZZ"))
+ "If no usable file is found, an exception should not be thrown.")
+ (binding [*default-language* "en-GB"]
+ (is (= "This is not a pipe" (get-message :pipe)))
+ (is
+ (=
+ "Ceci n'est pas une pipe." (get-message :pipe "en-GB;q=0.9, fr-FR")))
+ (is (= "это не труба." (get-message :pipe "de-DE" "i18n" "ru"))))))