diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..08cf6ba --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +.calva/ +target/ + +pom.xml + +.lein-repl-history + +.lein-failures + +eastwood.txt + +.clj-kondo/ +.lsp/ +.project +.settings/ +.nrepl-port +.classpath + +test.html \ No newline at end of file diff --git a/README.md b/README.md index 01786d2..d188729 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,13 @@ You can see MicroWorld in action [here](http://www.journeyman.cc/microworld/) - but please don't be mean to my poor little server. If you want to run big maps or complex rule-sets, please run it on your own machines. +### Version compatibility + +There are substantial changes in how rule functions are evaluated between 0.1.x +versions of MicroWorld libraries and 0.3.x versions. In particular, in 0.3.x +metadata is held on rule functions which is essential to the functioning of the +engine. Consequently, you cannot mix 0.1.x and 0.3.x libraries: it will not work. + ## Usage Primary entry points are make-world and run-world, both in mw-engine.core. See diff --git a/buildall.sh b/buildall.sh index 0eabd8e..6152aed 100755 --- a/buildall.sh +++ b/buildall.sh @@ -72,8 +72,9 @@ if [ $# -lt 1 ] then cat <<-EOF 1>&2 Usage: - -archive Create a tar archive of the current state of the source. - -build Build all components and commit to master. + -archive Create a tar archive of the current state of the source. + -build Build all components, commit and push to origin. + -docker Build and push a Docker image. -email [ADDRESS] Your email address, to be recorded in the build signature. -fullname [NAME] Your full name, to be recorded in the build signature. -pull Pull from remote git repository @@ -87,12 +88,14 @@ fi while (( "$#" )) do case $1 in - -a|-archive) - archive="TRUE";; + -a|-archive) + archive="TRUE";; -b|-build) # 'build' is the expected normal case. trial="FALSE"; ;; + -d|-docker) + docker="TRUE";; -e|-email) shift; email=$1;; @@ -126,7 +129,7 @@ do shift done -echo "Trial: ${trial}; email: ${email}; fullname ${fullname}; release: ${release}; webapps: $webappsdir" +echo "Trial: ${trial}; docker: ${docker}; email: ${email}; fullname ${fullname}; release: ${release}; webapps: $webappsdir" ls mw-* > /dev/null 2>&1 if [ $? -ne 0 ] @@ -137,132 +140,141 @@ fi for dir in mw-* do - pushd ${dir} + if [ "${dir}" != "mw-explore" ] + then + pushd ${dir} - # Make a temporary directory to keep the work-in-progress files. - if [ ! -d "${tmp}" ] - then - rm -f "${tmp}" - mkdir "${tmp}" - fi + # Make a temporary directory to keep the work-in-progress files. + if [ ! -d "${tmp}" ] + then + rm -f "${tmp}" + mkdir "${tmp}" + fi - cat project.clj > ${tmp}/project.bak.1 - old=`cat project.clj | grep 'defproject mw' | sed 's/.*defproject mw-[a-z]* "\([A-Za-z0-9_.-]*\)".*/\1/'` + cat project.clj > ${tmp}/project.bak.1 + old=`cat project.clj | grep 'defproject mw' | sed 's/.*defproject mw-[a-z]* "\([A-Za-z0-9_.-]*\)".*/\1/'` - if [ "${release}" != "" ] - then - message="Preparing ${old} for release" + if [ "${release}" != "" ] + then + message="Preparing ${old} for release" - # Does the 'old' version tag end with the token "-SNAPSHOT"? it probably does! - echo "${old}" | grep 'SNAPSHOT' - if [ $? -eq 0 ] - then - # It does... - interim=`echo ${old} | sed 's/\([A-Za-z0-9_.-]*\)-SNAPSHOT.*/\1/'` - if [ "${interim}" = "" ] - then - echo "Failed to compute interim version tag from '${old}'" 1>&2 - exit 1; - fi - setup-build-sig "${old}" "${interim}" "${fullname}" "${email}" - message="Upversioned from ${old} to ${interim} for release" - old=${interim} - else - setup-build-sig "unset" "${old}" "${fullname}" "${email}" - fi - else - setup-build-sig "unset" "${old}" "${fullname}" "${email}" - fi + # Does the 'old' version tag end with the token "-SNAPSHOT"? it probably does! + echo "${old}" | grep 'SNAPSHOT' + if [ $? -eq 0 ] + then + # It does... + interim=`echo ${old} | sed 's/\([A-Za-z0-9_.-]*\)-SNAPSHOT.*/\1/'` + if [ "${interim}" = "" ] + then + echo "Failed to compute interim version tag from '${old}'" 1>&2 + exit 1; + fi + setup-build-sig "${old}" "${interim}" "${fullname}" "${email}" + message="Upversioned from ${old} to ${interim} for release" + old=${interim} + else + setup-build-sig "unset" "${old}" "${fullname}" "${email}" + fi + else + setup-build-sig "unset" "${old}" "${fullname}" "${email}" + fi - sed -f ${tmp}/manifest.sed ${tmp}/project.bak.1 > project.clj + sed -f ${tmp}/manifest.sed ${tmp}/project.bak.1 > project.clj - echo $message + echo $message - lein clean - lein compile - if [ $? -ne 0 ] - then - echo "Sub-project ${dir} failed in compile" 1>&2 - exit 1 - fi + lein clean + lein compile + if [ $? -ne 0 ] + then + echo "Sub-project ${dir} failed in compile" 1>&2 + exit 1 + fi - lein test - if [ $? -ne 0 ] - then - echo "Sub-project ${dir} failed in test" 1>&2 - exit 1 - fi + lein test + if [ $? -ne 0 ] + then + echo "Sub-project ${dir} failed in test" 1>&2 + exit 1 + fi - lein marg - lein install + lein marg + lein install - # If we're in the UI project, build the uberwar - and should - # probably deploy it to local Tomcat for test - if [ "${dir}" = "mw-ui" -a "${webappsdir}" != "" ] - then - lein ring uberwar - sudo cp target/microworld.war "${webappsdir}" - echo "Deployed new WAR file to local Tomcat at ${webappsdir}" - fi + # If we're in the UI project, build the uberwar - and should + # probably deploy it to local Tomcat for test + if [ "${dir}" = "mw-ui" -a "${webappsdir}" != "" ] + then + lein ring uberwar + sudo cp target/microworld.war "${webappsdir}" + echo "Deployed new WAR file to local Tomcat at ${webappsdir}" + fi - # Then unset manifest properties prior to committing. - cat project.clj > ${tmp}/project.bak.2 - setup-build-sig - sed -f ${tmp}/manifest.sed ${tmp}/project.bak.2 > project.clj + if [ "${dir}" = "mw-ui" -a "${docker}" = "TRUE" ] + then + lein docker build + lein docker push + fi - if [ "${trial}" = "FALSE" ] - then - if [ "${message}" = "" ] - then - git commit -a - else - git commit -a -m "$message" - fi - git push origin master - fi + # Then unset manifest properties prior to committing. + cat project.clj > ${tmp}/project.bak.2 + setup-build-sig + sed -f ${tmp}/manifest.sed ${tmp}/project.bak.2 > project.clj - if [ "${release}" != "" ] - then - branch="${old}_MAINTENANCE" - if [ "${trial}" = "FALSE" ] - then - git branch "${branch}" - git push origin "${branch}" - fi + if [ "${trial}" = "FALSE" ] + then + if [ "${message}" = "" ] + then + git commit -a + else + git commit -a -m "$message" + fi + git push origin master + fi - cat project.clj > ${tmp}/project.bak.3 - setup-build-sig "${old}" "${release}-SNAPSHOT" "${fullname}" "${email}" - sed -f ${tmp}/manifest.sed ${tmp}/project.bak.3 > project.clj - message="Upversioned from ${interim} to ${release}-SNAPSHOT" + if [ "${release}" != "" ] + then + branch="${old}_MAINTENANCE" + if [ "${trial}" = "FALSE" ] + then + git branch "${branch}" + git push origin "${branch}" + fi - echo $message + cat project.clj > ${tmp}/project.bak.3 + setup-build-sig "${old}" "${release}-SNAPSHOT" "${fullname}" "${email}" + sed -f ${tmp}/manifest.sed ${tmp}/project.bak.3 > project.clj + message="Upversioned from ${interim} to ${release}-SNAPSHOT" - lein clean - lein compile - if [ $? -ne 0 ] - then - echo "Sub-project ${dir} failed in compile after branch to ${release}!" 1>&2 - exit 1 - fi - lein marg - lein install + echo $message - # Then unset manifest properties prior to committing. - cat project.clj > ${tmp}/project.bak.4 - setup-build-sig - sed -f ${tmp}/manifest.sed ${tmp}/project.bak.4 > project.clj + lein clean + lein compile + if [ $? -ne 0 ] + then + echo "Sub-project ${dir} failed in compile after branch to ${release}!" 1>&2 + exit 1 + fi + lein marg + lein install - if [ "${trial}" = "FALSE" ] - then - git commit -a -m "${message}" - echo ${message} - git push origin master - fi - fi + # Then unset manifest properties prior to committing. + cat project.clj > ${tmp}/project.bak.4 + setup-build-sig + sed -f ${tmp}/manifest.sed ${tmp}/project.bak.4 > project.clj - # if nothing broke so far, clean up... - rm -rf "${tmp}" - popd + if [ "${trial}" = "FALSE" ] + then + git commit -a -m "${message}" + echo ${message} + git push origin master + fi + fi + + # if nothing broke so far, clean up... + rm -rf "${tmp}" + popd + fi done 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/index.html b/docs/cloverage/index.html new file mode 100644 index 0000000..c18113a --- /dev/null +++ b/docs/cloverage/index.html @@ -0,0 +1,172 @@ + + + + + Coverage Summary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Namespace Forms Forms % Lines Lines %TotalBlankInstrumented
mw-engine.core
74
125
37.19 %
26
1
25
51.92 %1451352
mw-engine.display
9
79
10.23 %
8
11
42.11 %65819
mw-engine.drainage
88
301
22.62 %
31
59
34.44 %2173090
mw-engine.flow
511
147
77.66 %
54
8
18
77.50 %1791880
mw-engine.heightmap
140
11
92.72 %
42
2
2
95.65 %1331246
mw-engine.natural-rules
51
605
7.77 %
35
5
66
37.74 %18414106
mw-engine.render
11
149
6.88 %
10
26
27.78 %981136
mw-engine.utils
554
287
65.87 %
100
1
53
65.58 %37941154
mw-engine.world
65
123
34.57 %
13
1
25
35.90 %1111439
Totals:45.14 %54.18 %
+ + diff --git a/docs/cloverage/mw_engine/core.clj.html b/docs/cloverage/mw_engine/core.clj.html new file mode 100644 index 0000000..133d478 --- /dev/null +++ b/docs/cloverage/mw_engine/core.clj.html @@ -0,0 +1,443 @@ + + + + mw_engine/core.clj + + + + 001  (ns ^{:doc "Functions to transform a world and run rules. +
+ + 002               +
+ + 003              Every rule is a function of two arguments, a cell and a world. If the rule +
+ + 004              fires, it returns a new cell, which should have the same values for `:x` and +
+ + 005              `:y` as the old cell. Anything else can be modified. +
+ + 006   +
+ + 007              While any function of two arguments can be used as a rule, a special high +
+ + 008              level rule language is provided by the `mw-parser` package, which compiles +
+ + 009              rules expressed in a subset of English rules into suitable functions. +
+ + 010   +
+ + 011              A cell is a map containing at least values for the keys :x, :y, and :state; +
+ + 012              a transformation should not alter the values of :x or :y, and should not +
+ + 013              return a cell without a keyword as the value of :state. Anything else is +
+ + 014              legal. +
+ + 015   +
+ + 016              A world is a two dimensional matrix (sequence of sequences) of cells, such +
+ + 017              that every cell's `:x` and `:y` properties reflect its place in the matrix. +
+ + 018              See `world.clj`. +
+ + 019   +
+ + 020              Each time the world is transformed (see `transform-world`), for each cell, +
+ + 021              rules are applied in turn until one matches. Once one rule has matched no +
+ + 022              further rules can be applied to that cell." +
+ + 023        :author "Simon Brooke"} +
+ + 024   mw-engine.core +
+ + 025    (:require [mw-engine.flow :refer [flow-world]] +
+ + 026              [mw-engine.utils :refer [add-history-event get-int-or-zero map-world rule-type]] +
+ + 027              [taoensso.timbre :as l])) +
+ + 028   +
+ + 029  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 030  ;;;; +
+ + 031  ;;;; mw-engine: the state/transition engine of MicroWorld. +
+ + 032  ;;;; +
+ + 033  ;;;; This program is free software; you can redistribute it and/or +
+ + 034  ;;;; modify it under the terms of the GNU General Public License +
+ + 035  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 036  ;;;; of the License, or (at your option) any later version. +
+ + 037  ;;;; +
+ + 038  ;;;; This program is distributed in the hope that it will be useful, +
+ + 039  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 040  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 041  ;;;; GNU General Public License for more details. +
+ + 042  ;;;; +
+ + 043  ;;;; You should have received a copy of the GNU General Public License +
+ + 044  ;;;; along with this program; if not, write to the Free Software +
+ + 045  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 046  ;;;; USA. +
+ + 047  ;;;; +
+ + 048  ;;;; Copyright (C) 2014 Simon Brooke +
+ + 049  ;;;; +
+ + 050  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 051   +
+ + 052  (def ^:dynamic *with-history* +
+ + 053    "I suspect that caching history on the cells is greatly worsening the +
+ + 054     memory problems. Make it optional, but by default false." +
+ + 055    false) +
+ + 056   +
+ + 057  (defn apply-rule +
+ + 058    "Apply a single `rule` to a `cell`. What this is about is that I want to be able, +
+ + 059     for debugging purposes, to tag a cell with the rule text of the rule which +
+ + 060     fired (and especially so when an exception is thrown). " +
+ + 061    ;; as of version 0-3-0, metadata for rules is now passed around on the metadata +
+ + 062    ;; of the rule function itself. Yes, I know, this is obvious; but I'll confess +
+ + 063    ;; I didn't think of it before. +
+ + 064    [world cell rule] +
+ + 065    (let [result (try +
+ + 066                   (apply rule (list cell world)) +
+ + 067                   (catch Exception e +
+ + 068                     (l/warn e +
+ + 069                             (format +
+ + 070                              "Error in `apply-rule`: `%s` (%s) while executing rule `%s` on cell `%s`" +
+ + 071                              e +
+ + 072                              (.getMessage e) +
+ + 073                              (-> rule meta :lisp) +
+ + 074                              cell))))] +
+ + 075      (if *with-history* +
+ + 076        (add-history-event result rule) +
+ + 077        result))) +
+ + 078   +
+ + 079  (defn- apply-rules +
+ + 080    "Derive a cell from this `cell` of this `world` by applying these `rules`." +
+ + 081    [world cell rules] +
+ + 082    (or +
+ + 083     (first +
+ + 084      (remove +
+ + 085       nil? +
+ + 086       (try +
+ + 087         (map #(apply-rule world cell %) rules) +
+ + 088         (catch Exception e +
+ + 089           (l/warn e +
+ + 090                   (format +
+ + 091                    "Error in `apply-rules`: `%s` (%s) while executing rules on cell `%s`" +
+ + 092                    (-> e .getClass .getName) +
+ + 093                    (.getMessage e) +
+ + 094                    cell)))))) +
+ + 095     cell)) +
+ + 096   +
+ + 097  (defn- transform-cell +
+ + 098    "Derive a cell from this `cell` of this `world` by applying these `rules`. If an +
+ + 099     exception is thrown, cache its message on the cell and set it's state to error" +
+ + 100    [world cell rules] +
+ + 101    (try +
+ + 102      (merge +
+ + 103       (apply-rules world cell rules) +
+ + 104       {:generation (+ (get-int-or-zero cell :generation) 1)}) +
+ + 105      (catch Exception e +
+ + 106        (let [narrative (format "Error in `transform-cell`: `%s` (%s) at generation %d when in state %s;" +
+ + 107                                (-> e .getClass .getName) +
+ + 108                                (.getMessage e) +
+ + 109                                (:generation cell) +
+ + 110                                (:state cell))] +
+ + 111          (l/warn e narrative) +
+ + 112          cell)))) +
+ + 113   +
+ + 114  (defn transform-world +
+ + 115    "Return a world derived from this `world` by applying the production rules  +
+ + 116    found among these `rules` to each cell." +
+ + 117    [world rules] +
+ + 118    (map-world world transform-cell +
+ + 119               ;; Yes, that `list` is there for a reason!  +
+ + 120               (list +
+ + 121                (filter +
+ + 122                 #(= :production (rule-type %)) +
+ + 123                 rules)))) +
+ + 124   +
+ + 125  (defn run-world +
+ + 126    "Run this world with these rules for this number of generations. +
+ + 127   +
+ + 128     * `world` a world as discussed above; +
+ + 129     * `init-rules` a sequence of rules as defined above, to be run once to initialise the world; +
+ + 130     * `rules` a sequence of rules as defined above, to be run iteratively for each generation; +
+ + 131     * `generations` an (integer) number of generations. +
+ + 132      +
+ + 133     **NOTE THAT** all rules **must** be tagged with `rule-type` metadata, or thet **will not** +
+ + 134     be executed. +
+ + 135   +
+ + 136     Return the final generation of the world." +
+ + 137    ([world rules generations] +
+ + 138     (run-world world rules rules (dec generations))) +
+ + 139    ([world init-rules rules generations] +
+ + 140     (reduce (fn [world iteration] +
+ + 141               (l/info "Running iteration " iteration) +
+ + 142               (let [w' (transform-world world rules)] +
+ + 143                 (flow-world w' rules))) +
+ + 144             (transform-world world init-rules) +
+ + 145             (range generations)))) +
+ + diff --git a/docs/cloverage/mw_engine/display.clj.html b/docs/cloverage/mw_engine/display.clj.html new file mode 100644 index 0000000..a370627 --- /dev/null +++ b/docs/cloverage/mw_engine/display.clj.html @@ -0,0 +1,203 @@ + + + + mw_engine/display.clj + + + + 001  (ns ^{:doc "Simple functions to allow a world to be visualised." +
+ + 002        :author "Simon Brooke"} +
+ + 003    mw-engine.display) +
+ + 004   +
+ + 005  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 006  ;;;; +
+ + 007  ;;;; mw-engine: the state/transition engine of MicroWorld. +
+ + 008  ;;;; +
+ + 009  ;;;; This program is free software; you can redistribute it and/or +
+ + 010  ;;;; modify it under the terms of the GNU General Public License +
+ + 011  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 012  ;;;; of the License, or (at your option) any later version. +
+ + 013  ;;;; +
+ + 014  ;;;; This program is distributed in the hope that it will be useful, +
+ + 015  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 016  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 017  ;;;; GNU General Public License for more details. +
+ + 018  ;;;; +
+ + 019  ;;;; You should have received a copy of the GNU General Public License +
+ + 020  ;;;; along with this program; if not, write to the Free Software +
+ + 021  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 022  ;;;; USA. +
+ + 023  ;;;; +
+ + 024  ;;;; Copyright (C) 2014 Simon Brooke +
+ + 025  ;;;; +
+ + 026  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 027   +
+ + 028  (def ^:dynamic *image-base* +
+ + 029    "Base url (i.e., url of directory) from which to load tile images." +
+ + 030    "img/tiles") +
+ + 031   +
+ + 032  (defn format-css-class +
+ + 033    "Format this `state`, assumed to be a keyword indicating a state in the +
+ + 034     world, into a CSS class" +
+ + 035    [state] +
+ + 036    (subs (str state) 1)) +
+ + 037   +
+ + 038  (defn format-image-path +
+ + 039    "Render this `state`, assumed to be a keyword indicating a state in the +
+ + 040     world, into a path which should recover the corresponding image file." +
+ + 041    [state] +
+ + 042    (format "%s/%s.png" *image-base* (format-css-class state))) +
+ + 043   +
+ + 044  (defn format-mouseover [cell] +
+ + 045    (str cell)) +
+ + 046   +
+ + 047  (defn render-cell +
+ + 048    "Render this world cell as a Hiccup table cell." +
+ + 049    [cell] +
+ + 050    (let [state (:state cell)] +
+ + 051      [:td {:class (format-css-class state) :title (format-mouseover cell)} +
+ + 052       [:a {:href (format "inspect?x=%d&y=%d" (:x cell) (:y cell))} +
+ + 053        [:img {:alt (:state cell) :width 32 :height 32 :src (format-image-path state)}]]])) +
+ + 054   +
+ + 055  (defn render-world-row +
+ + 056    "Render this world `row` as a Hiccup table row." +
+ + 057    [row] +
+ + 058    (apply vector (cons :tr (map render-cell row)))) +
+ + 059   +
+ + 060  (defn render-world-table +
+ + 061    "Render this `world` as a Hiccup table." +
+ + 062    [world] +
+ + 063    (apply vector +
+ + 064      (cons :table +
+ + 065        (map render-world-row world)))) +
+ + diff --git a/docs/cloverage/mw_engine/drainage.clj.html b/docs/cloverage/mw_engine/drainage.clj.html new file mode 100644 index 0000000..5b8d0b9 --- /dev/null +++ b/docs/cloverage/mw_engine/drainage.clj.html @@ -0,0 +1,659 @@ + + + + mw_engine/drainage.clj + + + + 001  (ns ^{:doc "Experimental, probably of no interest to anyone else; attempt to +
+ + 002        compute drainage on a world, assumed to have altitudes already set +
+ + 003        from a heightmap." +
+ + 004        :author "Simon Brooke"} +
+ + 005    mw-engine.drainage +
+ + 006    (:require [mw-engine.core :refer [run-world]] +
+ + 007              [mw-engine.heightmap :as heightmap] +
+ + 008              [mw-engine.utils :refer [get-int-or-zero get-least-cell get-neighbours +
+ + 009                                       get-neighbours-with-property-value +
+ + 010                                       map-world]])) +
+ + 011   +
+ + 012  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 013  ;;;; +
+ + 014  ;;;; mw-engine: the state/transition engine of MicroWorld. +
+ + 015  ;;;; +
+ + 016  ;;;; This program is free software; you can redistribute it and/or +
+ + 017  ;;;; modify it under the terms of the GNU General Public License +
+ + 018  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 019  ;;;; of the License, or (at your option) any later version. +
+ + 020  ;;;; +
+ + 021  ;;;; This program is distributed in the hope that it will be useful, +
+ + 022  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 023  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 024  ;;;; GNU General Public License for more details. +
+ + 025  ;;;; +
+ + 026  ;;;; You should have received a copy of the GNU General Public License +
+ + 027  ;;;; along with this program; if not, write to the Free Software +
+ + 028  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 029  ;;;; USA. +
+ + 030  ;;;; +
+ + 031  ;;;; Copyright (C) 2014 Simon Brooke +
+ + 032  ;;;; +
+ + 033  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 034   +
+ + 035   +
+ + 036  (def ^:dynamic *sealevel* 10) +
+ + 037   +
+ + 038  ;; forward declaration of flow, to allow for a wee bit of mutual recursion. +
+ + 039  (declare flow) +
+ + 040   +
+ + 041  (defn rainfall +
+ + 042    "Compute rainfall for a cell with this `gradient` west-east, given +
+ + 043    `remaining` drops to distribute, and this overall map width." +
+ + 044    [gradient remaining map-width] +
+ + 045      (cond +
+ + 046        ;; if there's no rain left in the cloud, it can't fall; +
+ + 047        (zero? remaining) +
+ + 048        0 +
+ + 049        (pos? gradient) +
+ + 050        ;; rain, on prevailing westerly wind, falls preferentially on rising ground; +
+ + 051        (int (rand gradient)) +
+ + 052        ;; rain falls randomly across the width of the map... +
+ + 053        (zero? (int (rand map-width))) 1 +
+ + 054        :else +
+ + 055        0)) +
+ + 056   +
+ + 057  (defn rain-row +
+ + 058    "Return a row like this `row`, across which rainfall has been distributed; +
+ + 059    if `rain-probability` is specified, it is the probable rainfall on a cell +
+ + 060    with no gradient." +
+ + 061    ([row] +
+ + 062     (rain-row row 1)) +
+ + 063    ([row rain-probability] +
+ + 064     (rain-row row (count row) 0 (int (* (count row) rain-probability)))) +
+ + 065    ([row map-width previous-altitude drops-in-cloud] +
+ + 066     (cond +
+ + 067       (empty? row) nil +
+ + 068       (pos? drops-in-cloud) +
+ + 069       (let [cell (first row) +
+ + 070             alt (or (:altitude cell) 0) +
+ + 071             rising (- alt previous-altitude) +
+ + 072             fall (rainfall rising drops-in-cloud map-width)] +
+ + 073         (cons +
+ + 074           (assoc cell :rainfall fall) +
+ + 075           (rain-row (rest row) map-width alt (- drops-in-cloud fall)))) +
+ + 076       :else +
+ + 077       (map +
+ + 078         #(assoc % :rainfall 0) +
+ + 079         row)))) +
+ + 080   +
+ + 081   +
+ + 082  (defn rain-world +
+ + 083    "Simulate rainfall on this `world`. TODO: Doesn't really work just now - should +
+ + 084     rain more on west-facing slopes, and less to the east of high ground" +
+ + 085    [world] +
+ + 086    (map +
+ + 087      rain-row +
+ + 088      world)) +
+ + 089   +
+ + 090   +
+ + 091  (defn flow-contributors +
+ + 092    "Return a list of the cells in this `world` which are higher than this +
+ + 093    `cell` and for which this cell is the lowest neighbour, or which are at the +
+ + 094     same altitude and have greater flow" +
+ + 095    [cell world] +
+ + 096    (filter #(map? %) +
+ + 097            (map +
+ + 098              (fn [n] +
+ + 099                (cond +
+ + 100                  (= cell (get-least-cell (get-neighbours world n) :altitude)) n +
+ + 101                  (and (= (:altitude cell) (:altitude n)) +
+ + 102                       (> (or (:flow n) 0) (or (:flow cell) 0))) n)) +
+ + 103              (get-neighbours-with-property-value +
+ + 104                world (:x cell) (:y cell) 1 :altitude +
+ + 105                (or (:altitude cell) 0) >=)))) +
+ + 106   +
+ + 107   +
+ + 108  (defn is-hollow +
+ + 109    "Detects point hollows - that is, individual cells all of whose neighbours +
+ + 110     are higher. Return true if this `cell` has an altitude lower than any of +
+ + 111     its neighbours in this `world`" +
+ + 112    [world cell] +
+ + 113    ;; quicker to count the elements of the list and compare equality of numbers +
+ + 114    ;; than recursive equality check on members, I think. But worth benchmarking. +
+ + 115    (let [neighbours (get-neighbours world cell) +
+ + 116          altitude (get-int-or-zero cell :altitude)] +
+ + 117      (= (count neighbours) +
+ + 118         (count (get-neighbours-with-property-value +
+ + 119                  world (:x cell) (:y cell) 1 :altitude altitude >))))) +
+ + 120   +
+ + 121   +
+ + 122  (defn flood-hollow +
+ + 123    "Raise the altitude of a copy of this `cell` of this `world` to the altitude +
+ + 124     of the lowest of its `neighbours`." +
+ + 125    ([_world cell neighbours] +
+ + 126      (let [lowest (get-least-cell neighbours :altitude)] +
+ + 127        (merge cell {:state :water :altitude (:altitude lowest)}))) +
+ + 128    ([world cell] +
+ + 129      (flood-hollow world cell (get-neighbours world cell)))) +
+ + 130   +
+ + 131   +
+ + 132  (defn flood-hollows +
+ + 133    "Flood all local hollows in this `world`. At this stage only floods single +
+ + 134     cell hollows." +
+ + 135    [world] +
+ + 136    (map-world world +
+ + 137               #(if (is-hollow %1 %2) (flood-hollow %1 %2) %2))) +
+ + 138   +
+ + 139   +
+ + 140  (def max-altitude 255) +
+ + 141   +
+ + 142  (defn flow-nr +
+ + 143    "Experimental non recursive flow algorithm, needs to be run on a world as +
+ + 144     many times as there are distinct altitude values. This algorithm works only +
+ + 145     if applied sequentially from the highest altitude to the lowest, see +
+ + 146     `flow-world-nr`." +
+ + 147    [cell world] +
+ + 148    (when (= (- max-altitude (get-int-or-zero cell :generation)) +
+ + 149           (get-int-or-zero cell :altitude)) +
+ + 150      (merge cell +
+ + 151             {:flow (reduce + +
+ + 152                            (map +
+ + 153                              #(+ (get-int-or-zero % :rainfall) +
+ + 154                                  (get-int-or-zero % :flow)) +
+ + 155                              (flow-contributors cell world)))}))) +
+ + 156   +
+ + 157   +
+ + 158  (def flow +
+ + 159    "Compute the total flow upstream of this `cell` in this `world`, and return a cell identical +
+ + 160    to this one but having a value of its flow property set from that computation. The function is +
+ + 161    memoised because the consequence of mapping a recursive function across an array is that many +
+ + 162    cells will be revisited - potentially many times. +
+ + 163   +
+ + 164    Flow comes from a higher cell to a lower only if the lower is the lowest neighbour of the higher." +
+ + 165    (memoize +
+ + 166     (fn [cell world] +
+ + 167       (cond +
+ + 168        (not (nil? (:flow cell))) cell +
+ + 169        (<= (or (:altitude cell) 0) *sealevel*) cell +
+ + 170        :else +
+ + 171        (merge cell +
+ + 172               {:flow (+ (:rainfall cell) +
+ + 173                         (apply + +
+ + 174                                (map (fn [neighbour] (:flow (flow neighbour world))) +
+ + 175                                     (flow-contributors cell world))))}))))) +
+ + 176   +
+ + 177   +
+ + 178  (defn flow-world-nr +
+ + 179    "Experimental non-recursive flow-world algorithm" +
+ + 180    [world] +
+ + 181    (run-world world nil (list flow-nr) max-altitude)) +
+ + 182   +
+ + 183  (defn flow-world +
+ + 184    "Return a world like this `world`, but with cells tagged with the amount of +
+ + 185     water flowing through them." +
+ + 186    [world] +
+ + 187    (map-world (rain-world world) flow)) +
+ + 188   +
+ + 189  (defn explore-lake +
+ + 190    "Return a sequence of cells starting with this `cell` in this `world` which +
+ + 191    form a contiguous lake" +
+ + 192    [_world _cell] +
+ + 193    ) +
+ + 194   +
+ + 195  (defn is-lake? +
+ + 196    "If this `cell` in this `world` is not part of a lake, return nil. If it is, +
+ + 197    return a cell like this `cell` tagged as part of a lake." +
+ + 198    [world cell] +
+ + 199    (if +
+ + 200      ;; if it's already tagged as a lake, it's a lake +
+ + 201      (:lake cell) cell +
+ + 202      (let +
+ + 203        [outflow (apply min (map :altitude (get-neighbours world cell)))] +
+ + 204        (when-not +
+ + 205          (> (:altitude cell) outflow) +
+ + 206          (assoc cell :lake true))))) +
+ + 207   +
+ + 208   +
+ + 209  (defn find-lakes +
+ + 210    [_world] +
+ + 211    ) +
+ + 212   +
+ + 213  (defn run-drainage +
+ + 214    "Create a world from the heightmap `hmap`, rain on it, and then compute river +
+ + 215     flows." +
+ + 216    [hmap] +
+ + 217    (flow-world (rain-world (flood-hollows (heightmap/apply-heightmap hmap))))) +
+ + diff --git a/docs/cloverage/mw_engine/flow.clj.html b/docs/cloverage/mw_engine/flow.clj.html new file mode 100644 index 0000000..40d0fe1 --- /dev/null +++ b/docs/cloverage/mw_engine/flow.clj.html @@ -0,0 +1,545 @@ + + + + mw_engine/flow.clj + + + + 001  (ns mw-engine.flow +
+ + 002    "Allow flows of values between cells in the world. +
+ + 003      +
+ + 004     The design here is: a flow object is a map with the following properties: +
+ + 005   +
+ + 006     1. `:source`, whose value is a location; +
+ + 007     2. `:destination`, whose value is a location; +
+ + 008     3. `:property`, whose value is a keyword; +
+ + 009     4. `:quantity`, whose value is a positive real number. +
+ + 010   +
+ + 011     A location object is a map with the following properties: +
+ + 012   +
+ + 013     1. `:x`, whose value is a natural number not greater than the extent of the world; +
+ + 014     2. `:y`, whose value is a natural number not greater than the extent of the world. +
+ + 015   +
+ + 016     To execute a flow is transfer the quantity specified of the property specified +
+ + 017     from the cell at the source specified to the cell at the destination specified; +
+ + 018     if the source doesn't have sufficient of the property, then all it has should +
+ + 019     be transferred, but no more: properties to be flowed cannot be pulled negative. +
+ + 020      +
+ + 021     Flowing values through the world is consequently a two stage process: firstly +
+ + 022     there's a planning stage, in which all the flows to be executed are computed +
+ + 023     without changing the world, and then an execution stage, where they're all  +
+ + 024     executed. This namespace deals with mainly with execution." +
+ + 025    (:require [mw-engine.utils :refer [add-history-event get-cell get-num +
+ + 026                                       in-bounds? map-world merge-cell rule-type]] +
+ + 027              [taoensso.timbre :refer [info warn]])) +
+ + 028   +
+ + 029  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 030  ;;;; +
+ + 031  ;;;; mw-engine: the state/transition engine of MicroWorld. +
+ + 032  ;;;; +
+ + 033  ;;;; This program is free software; you can redistribute it and/or +
+ + 034  ;;;; modify it under the terms of the GNU General Public License +
+ + 035  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 036  ;;;; of the License, or (at your option) any later version. +
+ + 037  ;;;; +
+ + 038  ;;;; This program is distributed in the hope that it will be useful, +
+ + 039  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 040  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 041  ;;;; GNU General Public License for more details. +
+ + 042  ;;;; +
+ + 043  ;;;; You should have received a copy of the GNU General Public License +
+ + 044  ;;;; along with this program; if not, write to the Free Software +
+ + 045  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 046  ;;;; USA. +
+ + 047  ;;;; +
+ + 048  ;;;; Copyright (C) 2014 Simon Brooke +
+ + 049  ;;;; +
+ + 050  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 051   +
+ + 052  (defn coordinate? +
+ + 053    "Return `true` if this object `o` is a valid coordinate with respect to +
+ + 054       this `world`, else `false`. Assumes square worlds." +
+ + 055    [o world] +
+ + 056    (try +
+ + 057      (and (or (zero? o) (pos-int? o)) +
+ + 058           (< o (count world))) +
+ + 059      (catch Exception e +
+ + 060        (warn (format "Not a valid coordinate: %s; %s" o (.getMessage e))) +
+ + 061        false))) +
+ + 062   +
+ + 063  (defn location? +
+ + 064    "Return `true` if this object `o` is a location as defined above with respect to +
+ + 065     this `world`, else `false`." +
+ + 066    [o world] +
+ + 067    (try +
+ + 068      (and (map? o) +
+ + 069           (integer? (:x o)) +
+ + 070           (integer? (:y o)) +
+ + 071           (in-bounds? world (:x o) (:y o))) +
+ + 072      (catch Exception e +
+ + 073        (warn (format "Not a valid location: %s; %s" o (.getMessage e))) +
+ + 074        false))) +
+ + 075   +
+ + 076  (defn flow? +
+ + 077    "Return `true` if this object `o` is a flow as defined above with respect to +
+ + 078     this `world`, else `false`. Assumes square worlds." +
+ + 079    [o world] +
+ + 080    (try +
+ + 081      (and (map? o) +
+ + 082           (location? (:source o) world) +
+ + 083           (location? (:destination o) world) +
+ + 084           (keyword? (:property o)) +
+ + 085           (pos? (:quantity o))) +
+ + 086      (catch Exception e +
+ + 087        (warn (format "Not a valid flow: %s; %s" o (.getMessage e))) +
+ + 088        false))) +
+ + 089   +
+ + 090  (defn execute +
+ + 091    "Return a world like this `world`, except with the quantity of the property +
+ + 092     described in this `flow` object transferred from the source of that flow +
+ + 093     to its destination." +
+ + 094    [world flow] +
+ + 095    (try +
+ + 096      (let [sx (-> flow :source :x) +
+ + 097            sy (-> flow :source :y) +
+ + 098            source (get-cell world sx sy) +
+ + 099            dx (-> flow :destination :x) +
+ + 100            dy (-> flow :destination :y) +
+ + 101            dest (get-cell world dx dy) +
+ + 102            p (:property flow) +
+ + 103            q (min (:quantity flow) (get-num source p)) +
+ + 104            s' (add-history-event  +
+ + 105                (assoc source p (- (source p) q))  +
+ + 106                (:rule flow)  +
+ + 107                {:direction :sent :other {:x dx :y dy} :property p :quantity q}) +
+ + 108            d' (add-history-event +
+ + 109                (assoc dest p (+ (get-num dest p) q)) +
+ + 110                (:rule flow) +
+ + 111                {:direction :received :other {:x sx :y sy} :property p :quantity q})] +
+ + 112        (if (= q (:quantity flow)) +
+ + 113          (info (format "Moving %f units of %s from %d,%d to %d,%d" +
+ + 114                        (float q) (name p) sx sy dx dy)) +
+ + 115          (warn (format "Moving %s from %d,%d to %d,%d; %f units ordered but only %f available" +
+ + 116                        (name p) sx sy dx dy (float (:quantity flow)) (float q)))) +
+ + 117        (merge-cell (merge-cell world s') d')) +
+ + 118      (catch Exception e +
+ + 119        (warn (format "Failed to execute flow %s: %s" flow (.getMessage e))) +
+ + 120        ;; return the world unmodified. +
+ + 121        world))) +
+ + 122   +
+ + 123  (defn execute-flows +
+ + 124    "Return a world like this `world`, but with each of these flows executed." +
+ + 125    [world flows] +
+ + 126    (reduce execute world (filter #(flow? % world) flows))) +
+ + 127   +
+ + 128  (defn- plan-cell-flows  +
+ + 129    [world cell rules] +
+ + 130    (map ;; across all the rules +
+ + 131     (fn [rule] (let [r (try  +
+ + 132                          (apply rule (list cell world)) +
+ + 133                             (catch Exception any +
+ + 134                               (throw (ex-info "Planning of flows failed" +
+ + 135                                               (merge (meta rule) {:cell cell}) +
+ + 136                                               any))))]  +
+ + 137                  (when r (map #(assoc % :rule rule) r)))) +
+ + 138     rules)) +
+ + 139   +
+ + 140  (defn plan-flows +
+ + 141    "Plan, but do not execute, all the flows in this `world` implied by those of  +
+ + 142     these `rules` (which are expected to be pre-compiled) which are +
+ + 143     flow rules. Return the list of plans, as flow objects." +
+ + 144    [world rules] +
+ + 145    (remove nil? +
+ + 146            (flatten +
+ + 147             (map-world +
+ + 148              world +
+ + 149              plan-cell-flows +
+ + 150              (list (filter #(= :flow (rule-type %)) rules)))))) +
+ + 151   +
+ + 152  (defn flow-world +
+ + 153        "Return a world derived from this `world` by applying the flow rules  +
+ + 154        found among these `rules` to each cell, and executing all the flows +
+ + 155         planned." +
+ + 156    [world rules] +
+ + 157    (execute-flows world (plan-flows world rules))) +
+ + 158   +
+ + 159  ;; building blocks for compiled flow rules +
+ + 160   +
+ + 161  (defmacro create-location +
+ + 162    [cell] +
+ + 163    `(select-keys ~cell [:x :y])) +
+ + 164   +
+ + 165  (defmacro create-flow-quantity +
+ + 166    [source dest prop quantity] +
+ + 167    `{:source (create-location ~source) +
+ + 168      :destination (create-location ~dest) +
+ + 169      :prop ~prop +
+ + 170      :quantity ~quantity}) +
+ + 171   +
+ + 172  (defmacro create-flow-fraction +
+ + 173    [source dest prop fraction] +
+ + 174    `(create-flow-quantity ~source ~dest ~prop +
+ + 175                           (* ~fraction (get-num ~source ~prop)))) +
+ + 176   +
+ + 177  (defmacro create-flow-percent +
+ + 178    [source dest prop percent] +
+ + 179    `(create-flow-fraction ~source ~dest ~prop (/ ~percent 100))) +
+ + diff --git a/docs/cloverage/mw_engine/heightmap.clj.html b/docs/cloverage/mw_engine/heightmap.clj.html new file mode 100644 index 0000000..4d2b5d6 --- /dev/null +++ b/docs/cloverage/mw_engine/heightmap.clj.html @@ -0,0 +1,407 @@ + + + + mw_engine/heightmap.clj + + + + 001  (ns ^{:doc "Functions to apply a heightmap to a world. +
+ + 002               +
+ + 003              Heightmaps are considered only as greyscale images, so colour is redundent +
+ + 004              (will be ignored). Darker shades are higher." +
+ + 005        :author "Simon Brooke"} +
+ + 006    mw-engine.heightmap +
+ + 007    (:require [mikera.image.core :refer [load-image filter-image]] +
+ + 008              [mikera.image.filters :as filters] +
+ + 009              [mw-engine.utils :refer [get-int get-neighbours map-world]] +
+ + 010              [mw-engine.world :refer [make-world]])) +
+ + 011   +
+ + 012  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 013  ;;;; +
+ + 014  ;;;; mw-engine: the state/transition engine of MicroWorld. +
+ + 015  ;;;; +
+ + 016  ;;;; This program is free software; you can redistribute it and/or +
+ + 017  ;;;; modify it under the terms of the GNU General Public License +
+ + 018  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 019  ;;;; of the License, or (at your option) any later version. +
+ + 020  ;;;; +
+ + 021  ;;;; This program is distributed in the hope that it will be useful, +
+ + 022  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 023  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 024  ;;;; GNU General Public License for more details. +
+ + 025  ;;;; +
+ + 026  ;;;; You should have received a copy of the GNU General Public License +
+ + 027  ;;;; along with this program; if not, write to the Free Software +
+ + 028  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 029  ;;;; USA. +
+ + 030  ;;;; +
+ + 031  ;;;; Copyright (C) 2014 Simon Brooke +
+ + 032  ;;;; +
+ + 033  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 034   +
+ + 035  (defn abs  +
+ + 036    "Prior to Clojure 1.11, there is no native `abs` function. Afterwards, there +
+ + 037     is." +
+ + 038    [n]  +
+ + 039    (Math/abs n)) +
+ + 040   +
+ + 041  (defn tag-property +
+ + 042    "Set the value of this `property` of this cell from the corresponding pixel of this `heightmap`. +
+ + 043     If the heightmap you supply is smaller than the world, this will break. +
+ + 044   +
+ + 045     * `world` not actually used, but present to enable this function to be +
+ + 046       passed as an argument to `mw-engine.utils/map-world`, q.v. +
+ + 047     * `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map; +
+ + 048     * `property` the property (normally a keyword) whose value will be set on the cell. +
+ + 049     * `heightmap` an (ideally) greyscale image, whose x and y dimensions should +
+ + 050       exceed those of the world of which the `cell` forms part." +
+ + 051    ([_ cell property heightmap] +
+ + 052      (tag-property cell property heightmap)) +
+ + 053    ([cell property heightmap] +
+ + 054      (merge cell +
+ + 055             {property +
+ + 056              (+ (get-int cell property) +
+ + 057                 (- 256 +
+ + 058                    (abs +
+ + 059                      (mod +
+ + 060                        (.getRGB heightmap +
+ + 061                          (get-int cell :x) +
+ + 062                          (get-int cell :y)) 256))))}))) +
+ + 063   +
+ + 064  (defn tag-gradient +
+ + 065    "Set the `gradient` property of this `cell` of this `world` to the difference in +
+ + 066     altitude between its highest and lowest neghbours." +
+ + 067    [world cell] +
+ + 068    (let [heights (remove nil? (map :altitude (get-neighbours world cell))) +
+ + 069          highest (cond (empty? heights) 0 ;; shouldn't happen +
+ + 070                    :else (apply max heights)) +
+ + 071          lowest (cond (empty? heights) 0 ;; shouldn't +
+ + 072                   :else (apply min heights)) +
+ + 073          gradient (- highest lowest)] +
+ + 074      (merge cell {:gradient gradient}))) +
+ + 075   +
+ + 076  (defn tag-gradients +
+ + 077    "Set the `gradient` property of each cell in this `world` to the difference in +
+ + 078     altitude between its highest and lowest neghbours." +
+ + 079    [world] +
+ + 080    (map-world world tag-gradient)) +
+ + 081   +
+ + 082  (defn tag-altitude +
+ + 083    "Set the altitude of this cell from the corresponding pixel of this heightmap. +
+ + 084     If the heightmap you supply is smaller than the world, this will break. +
+ + 085   +
+ + 086     * `world` not actually used, but present to enable this function to be +
+ + 087       passed as an argument to `mw-engine.utils/map-world`, q.v.; +
+ + 088     * `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map; +
+ + 089     * `heightmap` an (ideally) greyscale image, whose x and y dimensions should +
+ + 090       exceed those of the world of which the `cell` forms part." +
+ + 091    ([_ cell heightmap] +
+ + 092      (tag-property cell :altitude heightmap)) +
+ + 093    ([cell heightmap] +
+ + 094      (tag-property cell :altitude heightmap))) +
+ + 095   +
+ + 096  (defn apply-heightmap +
+ + 097    "Apply the image file loaded from this path to this world, and return a world whose +
+ + 098    altitudes are modified (added to) by the altitudes in the heightmap. It is assumed that +
+ + 099    the heightmap is at least as large in x and y dimensions as the world. Note that, in +
+ + 100    addition to setting the `:altitude` of each cell, this function also sets the `:gradient`. +
+ + 101   +
+ + 102    * `world` a world, as defined in `world.clj`, q.v.; if world is not supplied, +
+ + 103      a world the size of the heightmap will be created; +
+ + 104    * `imagepath` a file path or URL which indicates an (ideally greyscale) image file." +
+ + 105    ([world imagepath] +
+ + 106      (let [heightmap (filter-image +
+ + 107                       (load-image imagepath) +
+ + 108                        (filters/grayscale))] +
+ + 109        (map-world +
+ + 110          (map-world world tag-altitude (list heightmap)) +
+ + 111          tag-gradient))) +
+ + 112     ([imagepath] +
+ + 113      (let [heightmap (filter-image +
+ + 114                        (load-image imagepath) +
+ + 115                        (filters/grayscale)) +
+ + 116            world (make-world (.getWidth heightmap) (.getHeight heightmap))] +
+ + 117        (map-world +
+ + 118          (map-world world tag-altitude (list heightmap)) +
+ + 119          tag-gradient)))) +
+ + 120   +
+ + 121  (defn apply-valuemap +
+ + 122    "Generalised from apply-heightmap, set an arbitrary property on each cell +
+ + 123     of this `world` from the values in this (ideally greyscale) heightmap. +
+ + 124   +
+ + 125     * `world` a world, as defined in `world.clj`, q.v.; +
+ + 126     * `imagepath` a file path or URL which indicates an (ideally greyscale) image file; +
+ + 127     * `property` the property of each cell whose value should be added to from the +
+ + 128        intensity of the corresponding cell of the image." +
+ + 129    [world imagepath property] +
+ + 130      (let [heightmap (filter-image +
+ + 131                        (load-image imagepath) +
+ + 132                        (filters/grayscale))] +
+ + 133        (map-world world tag-property (list property heightmap)))) +
+ + diff --git a/docs/cloverage/mw_engine/natural_rules.clj.html b/docs/cloverage/mw_engine/natural_rules.clj.html new file mode 100644 index 0000000..d3b0094 --- /dev/null +++ b/docs/cloverage/mw_engine/natural_rules.clj.html @@ -0,0 +1,560 @@ + + + + mw_engine/natural_rules.clj + + + + 001  (ns ^{:doc "A set of MicroWorld rules describing a simplified natural ecosystem. +
+ + 002   +
+ + 003              Since the completion of the rule language this is more or less obsolete - +
+ + 004              there are still a few things that you can do with rules written in Clojure +
+ + 005              that you can't do in the rule language, but not many and I doubt they're +
+ + 006              important. " +
+ + 007         :author " Simon Brooke "} +
+ + 008    mw-engine.natural-rules +
+ + 009    (:require [mw-engine.utils :refer [get-int get-neighbours get-neighbours-with-state member?]])) +
+ + 010   +
+ + 011  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 012  ;;;; +
+ + 013  ;;;; mw-engine: the state/transition engine of MicroWorld. +
+ + 014  ;;;; +
+ + 015  ;;;; This program is free software; you can redistribute it and/or +
+ + 016  ;;;; modify it under the terms of the GNU General Public License +
+ + 017  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 018  ;;;; of the License, or (at your option) any later version. +
+ + 019  ;;;; +
+ + 020  ;;;; This program is distributed in the hope that it will be useful, +
+ + 021  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 022  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 023  ;;;; GNU General Public License for more details. +
+ + 024  ;;;; +
+ + 025  ;;;; You should have received a copy of the GNU General Public License +
+ + 026  ;;;; along with this program; if not, write to the Free Software +
+ + 027  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 028  ;;;; USA. +
+ + 029  ;;;; +
+ + 030  ;;;; Copyright (C) 2014 Simon Brooke +
+ + 031  ;;;; +
+ + 032  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 033   +
+ + 034  ;; treeline at arbitrary altitude. +
+ + 035  (def treeline 150) +
+ + 036   +
+ + 037  ;; waterline also at arbitrary altitude. +
+ + 038  (def waterline 10) +
+ + 039   +
+ + 040  ;; and finally snowline is also arbitrary. +
+ + 041  (def snowline 200) +
+ + 042   +
+ + 043  ;; Rare chance of lightning strikes +
+ + 044  (def lightning-probability 500) +
+ + 045   +
+ + 046  ;; rules describing vegetation +
+ + 047  (def vegetation-rules +
+ + 048    (list +
+ + 049      ;; Randomly, birds plant tree seeds into grassland. +
+ + 050      (fn [cell _] (cond (and (= (:state cell) :grassland)(< (rand 10) 1))(merge cell {:state :heath}))) +
+ + 051      ;; heath below the treeline grows gradually into forest, providing browsing pressure is not to high +
+ + 052      (fn [cell _] +
+ + 053        (cond (and +
+ + 054                (= (:state cell) :heath) +
+ + 055                ;; browsing limit really ought to vary with soil fertility, but... +
+ + 056                (< (+ (get-int cell :deer)(get-int cell :sheep)) 6) +
+ + 057                (< (get-int cell :altitude) treeline)) +
+ + 058          (merge cell {:state :scrub}))) +
+ + 059      (fn [cell _] (cond (= (:state cell) :scrub) (merge cell {:state :forest}))) +
+ + 060      ;; Forest on fertile land grows to climax +
+ + 061      (fn [cell _] +
+ + 062        (cond +
+ + 063          (and +
+ + 064            (= (:state cell) :forest) +
+ + 065            (> (get-int cell :fertility) 10)) +
+ + 066          (merge cell {:state :climax}))) +
+ + 067      ;; Climax forest occasionally catches fire (e.g. lightning strikes) +
+ + 068      (fn [cell _] (cond (and (= (:state cell) :climax)(< (rand lightning-probability) 1)) (merge cell {:state :fire}))) +
+ + 069      ;; Climax forest neighbouring fires is likely to catch fire +
+ + 070      (fn [cell world] +
+ + 071        (cond +
+ + 072          (and (= (:state cell) :climax) +
+ + 073               (< (rand 3) 1) +
+ + 074               (not (empty? (get-neighbours-with-state world (:x cell) (:y cell) 1 :fire)))) +
+ + 075          (merge cell {:state :fire}))) +
+ + 076      ;; After fire we get waste +
+ + 077      (fn [cell _] (cond (= (:state cell) :fire) (merge cell {:state :waste}))) +
+ + 078      ;; And after waste we get pioneer species; if there's a woodland seed +
+ + 079      ;; source, it's going to be heath, otherwise grassland. +
+ + 080      (fn [cell world] +
+ + 081        (cond +
+ + 082          (and (= (:state cell) :waste) +
+ + 083               (not +
+ + 084                 (empty? +
+ + 085                   (flatten +
+ + 086                     (list +
+ + 087                       (get-neighbours-with-state world (:x cell) (:y cell) 1 :scrub) +
+ + 088                       (get-neighbours-with-state world (:x cell) (:y cell) 1 :forest) +
+ + 089                       (get-neighbours-with-state world (:x cell) (:y cell) 1 :climax)))))) +
+ + 090          (merge cell {:state :heath}))) +
+ + 091      (fn [cell _] +
+ + 092        (cond (= (:state cell) :waste) +
+ + 093          (merge cell {:state :grassland}))) +
+ + 094      ;; Forest increases soil fertility +
+ + 095      (fn [cell _] +
+ + 096        (cond (member? (:state cell) '(:forest :climax)) +
+ + 097          (merge cell {:fertility (+ (get-int cell :fertility) 1)}))))) +
+ + 098   +
+ + 099   +
+ + 100  ;; rules describing herbivore behaviour +
+ + 101  (def herbivore-rules +
+ + 102    (list +
+ + 103      ;; if there are too many deer for the fertility of the area to sustain, +
+ + 104      ;; some die or move on. +
+ + 105      (fn [cell _] +
+ + 106        (cond (> (get-int cell :deer) (get-int cell :fertility)) +
+ + 107          (merge cell {:deer (get-int cell :fertility)}))) +
+ + 108      ;; deer arrive occasionally at the edge of the map. +
+ + 109      (fn [cell world] +
+ + 110        (cond (and (< (count (get-neighbours world cell)) 8) +
+ + 111                   (< (rand 50) 1) +
+ + 112                   (> (get-int cell :fertility) 0) +
+ + 113                   (= (get-int cell :deer) 0)) +
+ + 114          (merge cell {:deer 2}))) +
+ + 115      ;; deer gradually spread through the world by breeding or migrating. +
+ + 116      (fn [cell world] +
+ + 117        (let [n (apply + (map #(get-int % :deer) (get-neighbours world cell)))] +
+ + 118          (cond (and +
+ + 119                  (> (get-int cell :fertility) 0) +
+ + 120                  (= (get-int cell :deer) 0) +
+ + 121                  (>= n 2)) +
+ + 122            (merge cell {:deer (int (/ n 2))})))) +
+ + 123      ;; deer breed. +
+ + 124      (fn [cell _] +
+ + 125        (cond +
+ + 126          (>= (get-int cell :deer) 2) +
+ + 127          (merge cell {:deer (int (* (:deer cell) 2))}))))) +
+ + 128   +
+ + 129    ;; rules describing predator behaviour +
+ + 130    (def predator-rules +
+ + 131      (list +
+ + 132       ;; wolves eat deer +
+ + 133       (fn [cell _] +
+ + 134        (cond +
+ + 135         (>= (get-int cell :wolves) 1) +
+ + 136         (merge cell {:deer (max 0 (- (get-int cell :deer) (get-int cell :wolves)))}))) +
+ + 137  ;;      ;; not more than eight wolves in a pack, for now (hack because wolves are not dying) +
+ + 138  ;;      (fn [cell world] +
+ + 139  ;;        (cond (> (get-int cell :wolves) 8) (merge cell {:wolves 8}))) +
+ + 140      ;; if there are not enough deer to sustain the get-int of wolves, +
+ + 141      ;; some wolves die or move on. (doesn't seem to be working?) +
+ + 142      (fn [cell _] +
+ + 143         (cond (> (get-int cell :wolves) (get-int cell :deer)) +
+ + 144           (merge cell {:wolves 0}))) +
+ + 145      ;; wolves arrive occasionally at the edge of the map. +
+ + 146      (fn [cell world] +
+ + 147        (cond (and (< (count (get-neighbours world cell)) 8) +
+ + 148                   (< (rand 50) 1) +
+ + 149                   (not (= (:state cell) :water)) +
+ + 150                   (= (get-int cell :wolves) 0)) +
+ + 151          (merge cell {:wolves 2}))) +
+ + 152      ;; wolves gradually spread through the world by breeding or migrating. +
+ + 153      (fn [cell world] +
+ + 154        (let [n (apply + (map #(get-int % :wolves) (get-neighbours world cell)))] +
+ + 155          (cond (and +
+ + 156                  (not (= (:state cell) :water)) +
+ + 157                  (= (get-int cell :wolves) 0) +
+ + 158                  (>= n 2)) +
+ + 159            (merge cell {:wolves 2})))) +
+ + 160      ;; wolves breed. +
+ + 161      (fn [cell _] +
+ + 162        (cond +
+ + 163          (>= (get-int cell :wolves) 2) +
+ + 164          (merge cell {:wolves (int (* (:wolves cell) 2))}))))) +
+ + 165   +
+ + 166   +
+ + 167    ;; rules which initialise the world +
+ + 168    (def init-rules +
+ + 169      (list +
+ + 170       ;; below the waterline, we have water. +
+ + 171       (fn [cell _] +
+ + 172         (cond (and (= (:state cell) :new) (< (get-int cell :altitude) waterline)) (merge cell {:state :water}))) +
+ + 173       ;; above the snowline, we have snow. +
+ + 174       (fn [cell _] +
+ + 175         (cond (and (= (:state cell) :new) (> (get-int cell :altitude) snowline)) (merge cell {:state :snow}))) +
+ + 176       ;; in between, we have a wasteland. +
+ + 177       (fn [cell _] (cond (= (:state cell) :new) (merge cell {:state :grassland}))))) +
+ + 178   +
+ + 179   +
+ + 180  (def natural-rules (flatten +
+ + 181                      (list +
+ + 182                       vegetation-rules +
+ + 183                       herbivore-rules +
+ + 184                       predator-rules))) +
+ + diff --git a/docs/cloverage/mw_engine/render.clj.html b/docs/cloverage/mw_engine/render.clj.html new file mode 100644 index 0000000..4647116 --- /dev/null +++ b/docs/cloverage/mw_engine/render.clj.html @@ -0,0 +1,302 @@ + + + + mw_engine/render.clj + + + + 001  (ns mw-engine.render +
+ + 002    "Render a world as HTML. +
+ + 003      +
+ + 004     Adapted (simplified) from mw-ui.render-world; this is for visualisation, not +
+ + 005     interaction." +
+ + 006    ;; TODO: but possibly it would be better if there is to be a newer version of +
+ + 007    ;; mw-ui, to base it on this. +
+ + 008    (:require [hiccup2.core :refer [html]]) +
+ + 009    ) +
+ + 010   +
+ + 011  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 012  ;;;; +
+ + 013  ;;;; This program is free software; you can redistribute it and/or +
+ + 014  ;;;; modify it under the terms of the GNU General Public License +
+ + 015  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 016  ;;;; of the License, or (at your option) any later version. +
+ + 017  ;;;; +
+ + 018  ;;;; This program is distributed in the hope that it will be useful, +
+ + 019  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 020  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 021  ;;;; GNU General Public License for more details. +
+ + 022  ;;;; +
+ + 023  ;;;; You should have received a copy of the GNU General Public License +
+ + 024  ;;;; along with this program; if not, write to the Free Software +
+ + 025  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 026  ;;;; USA. +
+ + 027  ;;;; +
+ + 028  ;;;; Copyright (C) 2024 Simon Brooke +
+ + 029  ;;;; +
+ + 030  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 031   +
+ + 032  (def ^:dynamic *state-images-relative-path* "img/tiles/") +
+ + 033   +
+ + 034  (defn format-css-class +
+ + 035    "Format this statekey, assumed to be a keyword indicating a state in the +
+ + 036     world, into a CSS class" +
+ + 037    [statekey] +
+ + 038    (name statekey)) +
+ + 039   +
+ + 040  (defn format-image-path +
+ + 041    "Render this statekey, assumed to be a keyword indicating a state in the +
+ + 042     world, into a path which should recover the corresponding image file." +
+ + 043    [statekey] +
+ + 044    (format "%s%s.png" *state-images-relative-path* (format-css-class statekey))) +
+ + 045   +
+ + 046  (defn format-mouseover [cell] +
+ + 047    (str cell)) +
+ + 048   +
+ + 049  (defn render-cell +
+ + 050    "Render this world cell as a Hiccup table cell." +
+ + 051    [cell] +
+ + 052    (let [state (:state cell)] +
+ + 053      [:td {:class (format-css-class state) :title (format-mouseover cell)} +
+ + 054        +
+ + 055        [:img {:alt (:state cell) :src (format-image-path state)}]])) +
+ + 056   +
+ + 057   +
+ + 058  (defn render-world-row +
+ + 059    "Render this world row as a Hiccup table row." +
+ + 060    [row] +
+ + 061    (apply vector (cons :tr (map render-cell row)))) +
+ + 062   +
+ + 063  (defn render-world-table +
+ + 064    "Render this `world` as a complete HTML table in a DIV. If  +
+ + 065     `state-images-relative-path` is passed, use that to override the default path." +
+ + 066    ([world]  +
+ + 067      [:div {:class "world"} +
+ + 068       (apply vector +
+ + 069              (cons :table +
+ + 070                    (map render-world-row world))) +
+ + 071       [:p +
+ + 072        (str "Generation " (:generation (first (flatten world))))]]) +
+ + 073    ([world state-images-relative-path] +
+ + 074     (binding [*state-images-relative-path* state-images-relative-path] +
+ + 075       (render-world-table world)))) +
+ + 076   +
+ + 077  (defn render-world-page +
+ + 078    ([world] +
+ + 079     [:html +
+ + 080      [:head +
+ + 081       [:title "Rendered world"] +
+ + 082       [:style "div.world table, div.world table tr td { +
+ + 083   padding: 0; +
+ + 084   margin: 0; +
+ + 085   border-collapse: collapse; +
+ + 086   border: none;}"]] +
+ + 087      [:body +
+ + 088       (render-world-table world)]]) +
+ + 089    ([world state-images-relative-path] +
+ + 090     (binding [*state-images-relative-path* state-images-relative-path] +
+ + 091       (render-world-page world)))) +
+ + 092   +
+ + 093  (defn world->html-file +
+ + 094    ([world output-path] +
+ + 095    (spit output-path (str (html (render-world-page world))))) +
+ + 096    ([world output-path state-images-relative-path] +
+ + 097     (binding [*state-images-relative-path* state-images-relative-path] +
+ + 098       (world->html-file world output-path)))) +
+ + diff --git a/docs/cloverage/mw_engine/utils.clj.html b/docs/cloverage/mw_engine/utils.clj.html new file mode 100644 index 0000000..9a0bdf6 --- /dev/null +++ b/docs/cloverage/mw_engine/utils.clj.html @@ -0,0 +1,1145 @@ + + + + mw_engine/utils.clj + + + + 001  (ns ^{:doc " Utility functions needed by MicroWorld and, specifically, in the +
+ + 002        interpretation of MicroWorld rule." +
+ + 003        :author "Simon Brooke"} +
+ + 004   mw-engine.utils +
+ + 005    (:require [clojure.math.combinatorics :as combo] +
+ + 006              [clojure.string :refer [join]])) +
+ + 007   +
+ + 008  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 009  ;;;; +
+ + 010  ;;;; mw-engine: the state/transition engine of MicroWorld. +
+ + 011  ;;;; +
+ + 012  ;;;; This program is free software; you can redistribute it and/or +
+ + 013  ;;;; modify it under the terms of the GNU General Public License +
+ + 014  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 015  ;;;; of the License, or (at your option) any later version. +
+ + 016  ;;;; +
+ + 017  ;;;; This program is distributed in the hope that it will be useful, +
+ + 018  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 019  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 020  ;;;; GNU General Public License for more details. +
+ + 021  ;;;; +
+ + 022  ;;;; You should have received a copy of the GNU General Public License +
+ + 023  ;;;; along with this program; if not, write to the Free Software +
+ + 024  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 025  ;;;; USA. +
+ + 026  ;;;; +
+ + 027  ;;;; Copyright (C) 2014 Simon Brooke +
+ + 028  ;;;; +
+ + 029  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 030   +
+ + 031  (defn member? +
+ + 032    "Return 'true' if elt is a member of col, else 'false'." +
+ + 033    [elt col] +
+ + 034    (contains? (set col) elt)) +
+ + 035   +
+ + 036  (defn get-int-or-zero +
+ + 037    "Return the value of this `property` from this `map` if it is a integer; +
+ + 038     otherwise return zero." +
+ + 039    [map property] +
+ + 040    (let [value (map property)] +
+ + 041      (if (integer? value) value 0))) +
+ + 042   +
+ + 043  (defn init-generation +
+ + 044    "Return a cell like this `cell`, but having a value for :generation, zero if +
+ + 045     the cell passed had no integer value for generation, otherwise the value +
+ + 046     taken from the cell passed. The `world` argument is present only for +
+ + 047     consistency with the rule engine and is ignored." +
+ + 048    [_ cell] +
+ + 049    (merge cell {:generation (get-int-or-zero cell :generation)})) +
+ + 050   +
+ + 051  (defn in-bounds +
+ + 052    "True if x, y are in bounds for this world (i.e., there is a cell at x, y) +
+ + 053     else false. *DEPRECATED*: it's a predicate, prefer `in-bounds?`. +
+ + 054   +
+ + 055    * `world` a world as defined in [world.clj](mw-engine.world.html); +
+ + 056    * `x` a number which may or may not be a valid x coordinate within that world; +
+ + 057    * `y` a number which may or may not be a valid y coordinate within that world." +
+ + 058    {:deprecated "1.1.7"} +
+ + 059    [world x y] +
+ + 060    (and (>= x 0) (>= y 0) (< y (count world)) (< x (count (first world))))) +
+ + 061   +
+ + 062  (defn in-bounds? +
+ + 063    "True if x, y are in bounds for this world (i.e., there is a cell at x, y) +
+ + 064     else false. +
+ + 065   +
+ + 066    * `world` a world as defined in [world.clj](mw-engine.world.html); +
+ + 067    * `x` a number which may or may not be a valid x coordinate within that world; +
+ + 068    * `y` a number which may or may not be a valid y coordinate within that world." +
+ + 069    {:added "1.1.7"} +
+ + 070    [world x y] +
+ + 071    (and (>= x 0) (>= y 0) (< y (count world)) (< x (count (first world))))) +
+ + 072   +
+ + 073  (defn map-world-n-n +
+ + 074    "Wholly non-parallel map world implementation; see documentation for `map-world`." +
+ + 075    ([world function] +
+ + 076     (map-world-n-n world function nil)) +
+ + 077    ([world function additional-args] +
+ + 078     (into [] +
+ + 079           (map (fn [row] +
+ + 080                  (into [] (map +
+ + 081                            #(apply function +
+ + 082                                    (cons world (cons % additional-args))) +
+ + 083                            row))) +
+ + 084                world)))) +
+ + 085   +
+ + 086   +
+ + 087  (defn map-world-p-p +
+ + 088    "Wholly parallel map-world implementation; see documentation for `map-world`." +
+ + 089    ([world function] +
+ + 090     (map-world-p-p world function nil)) +
+ + 091    ([world function additional-args] +
+ + 092     (into [] +
+ + 093           (pmap (fn [row] +
+ + 094                   (into [] (pmap +
+ + 095                             #(apply function +
+ + 096                                     (cons world (cons % additional-args))) +
+ + 097                             row))) +
+ + 098                 world)))) +
+ + 099   +
+ + 100  (defn map-world +
+ + 101    "Apply this `function` to each cell in this `world` to produce a new world. +
+ + 102    the arguments to the function will be the world, the cell, and any +
+ + 103    `additional-args` supplied. Note that we parallel map over rows but +
+ + 104    just map over cells within a row. That's because it isn't worth starting +
+ + 105    a new thread for each cell, but there may be efficiency gains in +
+ + 106    running rows in parallel." +
+ + 107    ([world function] +
+ + 108     (map-world world function nil)) +
+ + 109    ([world function additional-args] +
+ + 110     (into [] +
+ + 111           (pmap (fn [row] +
+ + 112                   (into [] (map +
+ + 113                             #(apply function +
+ + 114                                     (cons world (cons % additional-args))) +
+ + 115                             row))) +
+ + 116                 world)))) +
+ + 117   +
+ + 118  (defn get-cell +
+ + 119    "Return the cell a x, y in this world, if any. +
+ + 120   +
+ + 121    * `world` a world as defined in [world.clj](mw-engine.world.html); +
+ + 122    * `x` a number which may or may not be a valid x coordinate within that world; +
+ + 123    * `y` a number which may or may not be a valid y coordinate within that world." +
+ + 124    [world x y] +
+ + 125    (when (in-bounds? world x y) +
+ + 126      (nth (nth world y) x))) +
+ + 127   +
+ + 128  (defn get-int +
+ + 129    "Get the value of a property expected to be an integer from a map; if not +
+ + 130     present (or not an integer) return 0. +
+ + 131   +
+ + 132    * `map` a map; +
+ + 133    * `key` a symbol or keyword, presumed to be a key into the `map`." +
+ + 134    [map key] +
+ + 135    (if (map? map) +
+ + 136      (let [v (map key)] +
+ + 137        (cond (and v (integer? v)) v +
+ + 138              :else 0)) +
+ + 139      (throw (Exception. "No map passed?")))) +
+ + 140   +
+ + 141  (defmacro get-num +
+ + 142    "Get the value of a property expected to be a number from a map; if not +
+ + 143     present (or not a number) return 0. +
+ + 144   +
+ + 145    * `map` a map; +
+ + 146    * `key` a symbol or keyword, presumed to be a key into the `map`." +
+ + 147    [map key] +
+ + 148    `(if (map? ~map) +
+ + 149       (let [~'v (~map ~key)] +
+ + 150         (cond (and ~'v (number? ~'v)) ~'v +
+ + 151               :else 0)) +
+ + 152       (throw (Exception. "No map passed?")))) +
+ + 153   +
+ + 154  (defn population +
+ + 155    "Return the population of this species in this cell. Currently a synonym for +
+ + 156     `get-int`, but may not always be (depending whether species are later +
+ + 157     implemented as actors) +
+ + 158   +
+ + 159    * `cell` a map; +
+ + 160    * `species` a keyword representing a species which may populate that cell." +
+ + 161    [cell species] +
+ + 162    (get-int cell species)) +
+ + 163   +
+ + 164  (def memo-get-neighbours +
+ + 165    "Memoised get neighbours is more efficient when running deeply recursive +
+ + 166     algorithms on the same world. But it's less efficient when running the +
+ + 167     engine in its normal iterative style, because then we will rarely call +
+ + 168     get naighbours on the same cell of the same world twice." +
+ + 169    (memoize +
+ + 170     (fn [world x y depth] +
+ + 171       (remove nil? +
+ + 172               (map #(get-cell world (first %) (first (rest %))) +
+ + 173                    (remove #(= % (list x y)) +
+ + 174                            (combo/cartesian-product +
+ + 175                             (range (- x depth) (+ x depth 1)) +
+ + 176                             (range (- y depth) (+ y depth 1))))))))) +
+ + 177   +
+ + 178  (defn get-neighbours +
+ + 179    "Get the neighbours to distance depth of a cell in this world. +
+ + 180   +
+ + 181      Several overloads: +
+ + 182      * `world` a world, as described in [world.clj](mw-engine.world.html); +
+ + 183      * `cell` a cell within that world +
+ + 184      Gets immediate neighbours of the specified cell. +
+ + 185   +
+ + 186      * `world` a world, as described in[world.clj](mw-engine.world.html); +
+ + 187      * `cell` a cell within that world +
+ + 188      * `depth` an integer representing the depth to search from the +
+ + 189        `cell` +
+ + 190      Gets neighbours within the specified distance of the cell. +
+ + 191   +
+ + 192      * `world` a world, as described in[world.clj](mw-engine.world.html); +
+ + 193      * `x` an integer representing an x coordinate in that world; +
+ + 194      * `y` an integer representing an y coordinate in that world; +
+ + 195      * `depth` an integer representing the distance from [x,y] that +
+ + 196        should be searched +
+ + 197      Gets the neighbours within the specified distance of the cell at +
+ + 198      coordinates [x,y] in this world." +
+ + 199    ([world x y depth] +
+ + 200     (memo-get-neighbours world x y depth)) +
+ + 201    ([world cell depth] +
+ + 202     (memo-get-neighbours world (:x cell) (:y cell) depth)) +
+ + 203    ([world cell] +
+ + 204     (memo-get-neighbours world (:x cell) (:y cell) 1))) +
+ + 205   +
+ + 206  (defn get-neighbours-with-property-value +
+ + 207    "Get the neighbours to distance depth of the cell at x, y in this world which +
+ + 208     have this value for this property. +
+ + 209   +
+ + 210      * `world` a world, as described in [world.clj](mw-engine.world.html); +
+ + 211      * `cell` a cell within that world; +
+ + 212      * `depth` an integer representing the distance from [x,y] that +
+ + 213        should be searched (optional); +
+ + 214      * `property` a keyword representing a property of the neighbours; +
+ + 215      * `value` a value of that property (or, possibly, the name of another); +
+ + 216      * `op` a comparator function to use in place of `=` (optional). +
+ + 217   +
+ + 218     It gets messy." +
+ + 219    ([world x y depth property value op] +
+ + 220     (filter +
+ + 221      #(eval +
+ + 222        (list op +
+ + 223              (or (get % property) (get-int % property)) +
+ + 224              value)) +
+ + 225      (get-neighbours world x y depth))) +
+ + 226    ([world x y depth property value] +
+ + 227     (get-neighbours-with-property-value world x y depth property value =)) +
+ + 228    ([world cell depth property value] +
+ + 229     (get-neighbours-with-property-value world (:x cell) (:y cell) depth +
+ + 230                                         property value)) +
+ + 231    ([world cell property value] +
+ + 232     (get-neighbours-with-property-value world cell 1 +
+ + 233                                         property value))) +
+ + 234   +
+ + 235  (defn get-neighbours-with-state +
+ + 236    "Get the neighbours to distance depth of the cell at x, y in this world which +
+ + 237     have this state. +
+ + 238   +
+ + 239      * `world` a world, as described in [world.clj](mw-engine.world.html); +
+ + 240      * `cell` a cell within that world; +
+ + 241      * `depth` an integer representing the distance from [x,y] that +
+ + 242        should be searched; +
+ + 243      * `state` a keyword representing a state in the world." +
+ + 244    ([world x y depth state] +
+ + 245     (filter #(= (:state %) state) (get-neighbours world x y depth))) +
+ + 246    ([world cell depth state] +
+ + 247     (get-neighbours-with-state world (:x cell) (:y cell) depth state)) +
+ + 248    ([world cell state] +
+ + 249     (get-neighbours-with-state world cell 1 state))) +
+ + 250   +
+ + 251  (defn get-least-cell +
+ + 252    "Return the cell from among these `cells` which has the lowest numeric value +
+ + 253    for this `property`." +
+ + 254    [cells property] +
+ + 255    (first (sort-by property (filter #(number? (property %)) cells)))) +
+ + 256   +
+ + 257  (defn get-most-cell +
+ + 258    "Return the cell from among these `cells` which has the highest numeric value +
+ + 259    for this `property`." +
+ + 260    [cells property] +
+ + 261    (last (sort-by property (filter #(number? (property %)) cells)))) +
+ + 262   +
+ + 263  (defn- set-cell-property +
+ + 264    "If this `cell`s x and y properties are equal to these `x` and `y` values, +
+ + 265     return a cell like this cell but with the value of this `property` set to +
+ + 266     this `value`. Otherwise, just return this `cell`." +
+ + 267    [cell x y property value] +
+ + 268    (cond +
+ + 269      (and (= x (:x cell)) (= y (:y cell))) +
+ + 270      (merge cell {property value :rule "Set by user"}) +
+ + 271      :else cell)) +
+ + 272   +
+ + 273  (defn set-property +
+ + 274    "Return a world like this `world` but with the value of exactly one `property` +
+ + 275     of one `cell` changed to this `value`" +
+ + 276    ([world cell property value] +
+ + 277     (set-property world (:x cell) (:y cell) property value)) +
+ + 278    ([world x y property value] +
+ + 279     (apply +
+ + 280      vector ;; we want a vector of vectors, not a list of lists, for efficiency +
+ + 281      (map +
+ + 282       (fn [row] +
+ + 283         (apply +
+ + 284          vector +
+ + 285          (map #(set-cell-property % x y property value) +
+ + 286               row))) +
+ + 287       world)))) +
+ + 288   +
+ + 289  (defn merge-cell +
+ + 290    "Return a world like this `world`, but merge the values from this `cell` with +
+ + 291     those from the cell in the world with the same co-ordinates" +
+ + 292    [world cell] +
+ + 293    (if (in-bounds? world (:x cell) (:y cell)) +
+ + 294      (map-world world +
+ + 295                 #(if +
+ + 296                   (and +
+ + 297                    (= (:x cell) (:x %2)) +
+ + 298                    (= (:y cell) (:y %2))) +
+ + 299                    (merge %2 cell) +
+ + 300                    %2)) +
+ + 301      world)) +
+ + 302   +
+ + 303  (defn rule-type +
+ + 304    "Return the rule-type of this compiled `rule`." +
+ + 305    [rule] +
+ + 306    (:rule-type (meta rule))) +
+ + 307   +
+ + 308  (defn add-history-event +
+ + 309    "If `cell` is non-nil, expect it to be a map representing a cell; add +
+ + 310     to its history an an event recording the firing of this rule. If +
+ + 311     `detail` is passed, treat it as a map of additional data to be +
+ + 312     added to the event." +
+ + 313    ([cell rule] +
+ + 314     (when cell (add-history-event cell rule {}))) +
+ + 315    ([result rule detail] +
+ + 316     (when result +
+ + 317       (let [rule-meta (meta rule) +
+ + 318             event {:rule (:source rule-meta) +
+ + 319                    :rule-type (:rule-type rule-meta) +
+ + 320                    :generation (get-int-or-zero +
+ + 321                                 result +
+ + 322                                 :generation)} +
+ + 323             event' (if detail (merge event detail) event)] +
+ + 324         (merge result +
+ + 325                {:history (concat +
+ + 326                           (:history result) +
+ + 327                           (list event'))}))))) +
+ + 328   +
+ + 329  (defn- event-narrative [event] +
+ + 330    (case (:rule-type event) +
+ + 331      :production (:rule event) +
+ + 332      :flow (format "%s %f units of %s %s %d,%d:\n    %s" +
+ + 333                    (name (:direction event)) +
+ + 334                    (:quantity event) +
+ + 335                    (:property event) +
+ + 336                    (if (= :sent (:direction event)) "to" "from") +
+ + 337                    (:x (:other event)) +
+ + 338                    (:y (:other event)) +
+ + 339                    (:rule event)))) +
+ + 340   +
+ + 341  (defn history-string +
+ + 342    "Return the history of this `cell` as a string for presentation to the user." +
+ + 343    [cell] +
+ + 344    (join "\n" +
+ + 345          (map #(format "%6d: %s" (:generation %) (event-narrative %)) +
+ + 346               (:history cell)))) +
+ + 347   +
+ + 348  (defn- extend-summary [summary rs rl event] +
+ + 349    (str summary +
+ + 350         (if rs (format "%d-%d (%d occurances): %s\n" rs +
+ + 351                        (:generation event) +
+ + 352                        rl +
+ + 353                        (event-narrative event)) +
+ + 354             (format "%d: %s\n" (:generation event) +
+ + 355                     (event-narrative event))))) +
+ + 356   +
+ + 357  (defn summarise-history +
+ + 358    "Return, as a string, a shorter summary of the history of this cell" +
+ + 359    [cell] +
+ + 360    (loop [history (rest (:history cell)) +
+ + 361           event (first (:history cell)) +
+ + 362           prev nil +
+ + 363           rs nil +
+ + 364           rl 0 +
+ + 365           summary ""] +
+ + 366      (cond (nil? event) (extend-summary summary rs rl prev) +
+ + 367            (= (:rule event) (:rule prev)) (recur +
+ + 368                                            (rest history) +
+ + 369                                            (first history) +
+ + 370                                            event +
+ + 371                                            (or rs (:generation event)) +
+ + 372                                            (inc rl) +
+ + 373                                            summary) +
+ + 374            :else (recur (rest history) +
+ + 375                         (first history) +
+ + 376                         event +
+ + 377                         nil +
+ + 378                         0 +
+ + 379                         (extend-summary summary rs (inc rl) event))))) +
+ + diff --git a/docs/cloverage/mw_engine/world.clj.html b/docs/cloverage/mw_engine/world.clj.html new file mode 100644 index 0000000..3aa1a5b --- /dev/null +++ b/docs/cloverage/mw_engine/world.clj.html @@ -0,0 +1,341 @@ + + + + mw_engine/world.clj + + + + 001  (ns ^{:doc "Functions to create and to print two dimensional cellular automata. +
+ + 002               +
+ + 003              Nothing in this namespace should determine what states are possible within +
+ + 004              the automaton, except for the initial state, :new. +
+ + 005   +
+ + 006              A cell is a map containing at least values for the keys `:x`, `:y`, and `:state`. +
+ + 007   +
+ + 008              A world is a two dimensional matrix (sequence of sequences) of cells, such +
+ + 009              that every cell's `:x` and `:y` properties reflect its place in the matrix." +
+ + 010        :author "Simon Brooke"} +
+ + 011   mw-engine.world +
+ + 012    (:require [clojure.string :as string] +
+ + 013              [mw-engine.utils :refer [population]])) +
+ + 014   +
+ + 015  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 016  ;;;; +
+ + 017  ;;;; mw-engine: the state/transition engine of MicroWorld. +
+ + 018  ;;;; +
+ + 019  ;;;; This program is free software; you can redistribute it and/or +
+ + 020  ;;;; modify it under the terms of the GNU General Public License +
+ + 021  ;;;; as published by the Free Software Foundation; either version 2 +
+ + 022  ;;;; of the License, or (at your option) any later version. +
+ + 023  ;;;; +
+ + 024  ;;;; This program is distributed in the hope that it will be useful, +
+ + 025  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +
+ + 026  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +
+ + 027  ;;;; GNU General Public License for more details. +
+ + 028  ;;;; +
+ + 029  ;;;; You should have received a copy of the GNU General Public License +
+ + 030  ;;;; along with this program; if not, write to the Free Software +
+ + 031  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, +
+ + 032  ;;;; USA. +
+ + 033  ;;;; +
+ + 034  ;;;; Copyright (C) 2014 Simon Brooke +
+ + 035  ;;;; +
+ + 036  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 037   +
+ + 038  (defn cell? +
+ + 039    "Return `true` if `obj` is a cell, as understood by MicroWorld, else `false`." +
+ + 040    [obj] +
+ + 041    (and (map? obj) ;; it's a map... +
+ + 042         ;; TODO: it's worth checking (and this does not) that cells have the +
+ + 043         ;; right co-ordinates! +
+ + 044         (pos-int? (:x obj)) ;; with an x co-ordinate... +
+ + 045         (pos-int? (:y obj)) ;; and a y co-ordinate... +
+ + 046         (keyword? (:state obj)))) ;; and a state which is a keyword. +
+ + 047   +
+ + 048  (defn world? +
+ + 049    "Return `true` if `obj` is a world, as understood by MicroWorld, else `false`." +
+ + 050    [obj] +
+ + 051    (and (coll? obj) ;; it's a collection... +
+ + 052         (every? coll? obj) ;; of collections... +
+ + 053         (= 1 (count (set (map count obj)))) ;; all of which are the same length... +
+ + 054         (every? cell? (flatten obj)))) ;; and every element of each of those is a cell. +
+ + 055   +
+ + 056  (defmacro make-cell +
+ + 057    "Create a minimal default cell at x, y +
+ + 058   +
+ + 059    * `x` the x coordinate at which this cell is created; +
+ + 060    * `y` the y coordinate at which this cell is created." +
+ + 061    [x y] +
+ + 062    `{:x ~x :y ~y :state :new}) +
+ + 063   +
+ + 064  (defn make-world +
+ + 065    "Make a world width cells from east to west, and height cells from north to +
+ + 066     south. +
+ + 067   +
+ + 068    * `width` a natural number representing the width of the matrix to be created; +
+ + 069    * `height` a natural number representing the height of the matrix to be created." +
+ + 070    [width height] +
+ + 071    (apply vector +
+ + 072           (map (fn [h] +
+ + 073                  (apply vector (map #(make-cell % h) (range width)))) +
+ + 074                (range height)))) +
+ + 075   +
+ + 076  (defn truncate-state +
+ + 077    "Truncate the print name of the state of this cell to at most limit characters." +
+ + 078    [cell limit] +
+ + 079    (let [s (:state cell)] +
+ + 080      (try +
+ + 081        (cond (> (count (str s)) limit) (subs (name s) 0 limit) +
+ + 082            :else s) +
+ + 083        (catch Exception any  +
+ + 084          (throw (ex-info (.getMessage any)  +
+ + 085                          {:cell cell +
+ + 086                           :limit limit +
+ + 087                           :exception-class (.getClass any)})))))) +
+ + 088   +
+ + 089  (defn format-cell +
+ + 090    "Return a formatted string summarising the current state of this cell." +
+ + 091    [cell] +
+ + 092    (format "%10s" +
+ + 093            (truncate-state cell 10))) +
+ + 094   +
+ + 095  (defn- format-world-row +
+ + 096    "Format one row in the state of a world for printing." +
+ + 097    [row] +
+ + 098    (string/join (map format-cell row))) +
+ + 099   +
+ + 100  (defn print-world +
+ + 101    "Print the current state of this world, and return nil. +
+ + 102   +
+ + 103    * `world` a world as defined above." +
+ + 104    [world] +
+ + 105    (println) +
+ + 106    (dorun +
+ + 107     (map +
+ + 108      #(println +
+ + 109        (format-world-row %)) +
+ + 110      world)) +
+ + 111    nil) +
+ + 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..748a2e7 --- /dev/null +++ b/docs/codox/index.html @@ -0,0 +1,12 @@ + +Mw-engine 0.3.0-SNAPSHOT

Mw-engine 0.3.0-SNAPSHOT

Released under the GNU General Public License v2

Cellular automaton world builder.

Installation

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

[mw-engine "0.3.0-SNAPSHOT"]

Topics

Namespaces

mw-engine.core

Functions to transform a world and run rules.

+

mw-engine.display

Simple functions to allow a world to be visualised.

+

mw-engine.drainage

Experimental, probably of no interest to anyone else; attempt to compute drainage on a world, assumed to have altitudes already set from a heightmap.

+

mw-engine.heightmap

Functions to apply a heightmap to a world.

+

mw-engine.natural-rules

A set of MicroWorld rules describing a simplified natural ecosystem.

+

mw-engine.world

Functions to create and to print two dimensional cellular automata.

+
\ No newline at end of file diff --git a/docs/codox/intro.html b/docs/codox/intro.html new file mode 100644 index 0000000..9baafa0 --- /dev/null +++ b/docs/codox/intro.html @@ -0,0 +1,5 @@ + +Introduction to mw-engine

Introduction to mw-engine

+

TODO: write great documentation

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