--- a/.hgignore Thu Oct 13 13:34:16 2011 +0200
+++ b/.hgignore Wed May 23 23:47:37 2012 +0200
@@ -16,5 +16,7 @@
sbt-launch*.jar
.scala_dependencies
*.orig
+.cache
+.settings
.idea
.idea_modules
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/INSTALL.txt Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,84 @@
+
+0. download code using mercurial, and switch to the webid branch
+ $ hg clone https://dvcs.w3.org/hg/read-write-web
+ $ cd read-write-web
+ $ hg checkout webid
+
+1. download java 6 or above for your Operating System - don't download just the JRE but also the java tools
+
+2. download scala http://www.scala-lang.org/
+
+3. download the scala build tool ( sbt ) from https://github.com/harrah/xsbt
+ I have an xsbt shell script that contains
+ java $SBT_PROPS -Xmx512m -Dfile.encoding=UTF-8 -jar `dirname $0`/jars/sbt-launch-0.11.0.jar "$@"
+
+4. set up some environmental variables for the https server to run on
+
+ export SBT_PROPS='-Djetty.ssl.keyStoreType=JKS -Djetty.ssl.keyStore=keys/KEYSTORE.jks -Djetty.ssl.keyStorePassword=secret'
+
+ Notice if you want to avoid browser warnings and you want to put this up on a public site then you need to get a CA signed certificate for your domain. There are providers that give those for free. There are protocols that will appear to make this no longer necessary
+
+5. run sbt, then start the server from the command line
+
+ $ sbt
+ > run --https 8443 test_www /2011/09
+
+ This will compile the server, start the https port on 8442 and use files in the test_www directory so that you can access them at https://localhost:8443/2011/09/
+
+6. connect to different resources
+
+6.1 GETing a public resource
+
+ $ curl -k https://localhost:8443/public/
+
+ If you access this via your browser and you have more than one webid certificate, your browser will ask you for even when you access this. We are working on a solution to stop this from happening.
+
+6.2 GETing a protected resource
+
+The following is a protected resource so if you access it without authentification credentials you will get
+
+ $ curl -i -k https://localhost:8443/2011/09/foaf.n3
+HTTP/1.1 401 Unauthorized
+Content-Length: 0
+Server: Jetty(7.2.2.v20101205)
+
+If you have a WebID enabled certificate ( http://webid.info/ ) with the public and private keys in a pem file, then you can access the resource with,
+
+ $ curl -E Certificates.pem -i -k https://localhost:8443/2011/09/foaf.n3
+
+since only Henry Story can view it as seen from the file
+
+ $ cat test_www/foaf.n3.protect.n3
+
+@prefix acl: <http://www.w3.org/ns/auth/acl#> .
+@prefix : <#> .
+
+:a1 a acl:Authorization;
+ acl:accessTo <foaf.n3>;
+ acl:mode acl:Read;
+ acl:agent <http://bblfish.net/people/henry/card#me> .
+
+If you want to give yourself access then replace Henry's WebID, "http://bblfish.net/people/henry/card#me" with your own, or make another example for that.
+
+6.3 Uploading a resource
+
+Say you wanted to upload an RDF file to the server
+
+$ curl http://bblfish.net/people/henry/card.rdf | curl -i -k -H "Content-Type: application/rdf+xml" -X PUT https://localhost:8443/2011/09/test2.rdf -T -
+HTTP/1.1 100 Continue
+
+ % Total % Received % Xferd Average Speed Time Time Time Current
+ Dload Upload Total Spent Left Speed
+100 24386 100 24386 0 0 2223 0 0:00:10 0:00:10 --:--:-- 33405
+HTTP/1.1 201 Created
+Content-Length: 0
+Server: Jetty(7.2.2.v20101205)
+
+the file will then be available as /2011/09/test2.rdf on the localhost server
+
+6.4 querying a resource with SPARQL
+
+You can write a SPARQL query and then query the given model by POSTing the query to the resource
+
+curl -k -i -H "Content-Type: application/sparql-query" -X POST https://localhost:8443/2011/09/test.rdf -T queryfriends.sparql
+
--- a/README.markdown Thu Oct 13 13:34:16 2011 +0200
+++ b/README.markdown Wed May 23 23:47:37 2012 +0200
@@ -23,11 +23,22 @@
* jar packager (assembly)
* eclipse plugin for sbt
* Web framework (Unfiltered)
-* embedded Web server (Jetty)
+* embedded Web server (Jetty or Netty)
* tests for web api (specs)
* logger (slf4j)
* the Jena/ARQ libraries
+Community
+---------
+
+For any improvement ideas and and bugfixes send e-mail to henry.story@bblfish.net
+
+This application is based on standards that the following groups are discussing:
+
+* the [read-write-web community group](http://www.w3.org/community/rww/)
+* the [WebID community group](http://www.w3.org/community/webid/)
+
+
How to start geeking
--------------------
@@ -40,7 +51,7 @@
### to auto-compile the source
- > ~ compile
+ > compile
### to launch tests under sbt (will cache all the dependencies the first time, can take a while)
@@ -48,39 +59,131 @@
### to run the Web App
- > run
+Get the full command line options
-or
+ > run
- > run 8080
+You are then given a choice of using either the Jetty or the Netty Server.
+( The Netty Server has better SSL/TLS and hence beter WebID support. )
+You will then get a listing of all the options.
+
+The following is known to work with https
+
+To start an insecure server start
+
+ > run --lang turtle --http 8080 test_www /2012/
+
+ou can now request resources using curl on the command line
+
+ $ curl -i -H "Accept: application/rdf+xml" http://localhost:8080/2012/foaf.n3
+
+It is possible to PUT, RDF resources too and a couple of image formats, as
+well as to create directories etc... The test suites have some good examples of this.
### to generate the eclipse configuration
> eclipse same-targets
+### to generate the IntelliJ configuration
+
+ > gen-idea
+
### to package the application as a stand-alone jar (creates target/read-write-web.jar)
> assembly
-Using the stand-alone jar
+### run RWW using the standalone jar
+
+ $ java -jar target/read-write-web.jar
+
+### to enable debug mode in sbt
+
+If you want to debug SBT using an IDE the start sbt with
+
+ $ bin/rwsbt.sh -d
+
+
+Access control with WebID
-------------------------
- java -jar target/read-write-web.jar 8080 ~/WWW/2011/09 /2011/09 [options]
-
-Options:
-
- * --relax All documents exist as empty RDF files (like a wiki).
- * --strict Documents must be created using PUT else they return 404
-
+### start server on https port with [WebID](http://webid.info/)
-HTTPS with WebID
-----------------
-
-### to run on https with WebID
+ > run --lang turtle --keyStore src/test/resources/KEYSTORE.jks --clientTLS noCA --ksPass secret --https 8443 test_www /2012/
- > java -Djetty.ssl.keyStoreType=JKS -Djetty.ssl.keyStore=KEYSTORE.jks -Djetty.ssl.keyStorePassword=secret -jar target/read-write-web.jar -https 8443
+You can now request resources using curl over https using the command line.
+Note: If the server itself needs to make requests over TLS for WebID authentication this will start in insecure [ --clientTLS noCA ] mode so that the server will not refuse a connection if it reaches a server (like itself) which does not have a CA signed certificate .
-### with debug enabled add the following parameters after 'java'
+The following file is readable by all and so you will be able to access it:
- -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
+ $ curl -k -i -H "Accept: application/rdf+xml" https://localhost:8443/2012/foaf.n3
+ HTTP/1.1 200 OK
+ ...
+In the `test_www` directory there is a .meta.n3 file which contains the access rules as defined by the http://www.w3.org/wiki/WebAccessControl vocabulary. ( this is still a very minimal implementation of what is possible ) These say that private.n3 requires authentication. And indeed:
+
+ $ curl -k -i -H "Accept: application/rdf+xml" https://localhost:8443/2012/private.n3
+ curl: (56) SSL read: error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate, errno 0
+
+Curl returns a SSL error, because the server asked curl for a client certificate which it did not offer and because curl forces the server to return the certificate ( which could be considered a bug IMHO ). A browser would return a 401 Unauthorized, with some extra data explaining the error. What would be nice would be to see this:
+
+ $ curl -k -i -H "Accept: application/rdf+xml" https://localhost:8443/2012/hello.n3
+ HTTP/1.1 401 Unauthorized
+ Server: Scala Netty Unfiltered Server
+ Connection: Keep-Alive
+ Content-Length: 0
+
+In order to be able to access protected.n3 you need to use a WebID enabled certificate
+when connecting and add that WebID to the access controlfile .meta.n3
+
+ $ curl -k -i -E src/test/resources/JohnDoe.pem https://localhost:8443/2012/private.n3
+ Enter PEM pass phrase:
+ HTTP/1.1 200 OK
+
+[ the curl password is "secret" ]
+
+### creating your own certificate
+
+You can create your own certificate in your browser using a service such as [https://my-profile.eu/](https://my-profile.eu/) This will save your certificate in the keychain associated with the browser.
+You can then edit the .meta.n3 file to give yourself read/write/execute access using that certificate)
+
+If you want to use that certificate using curl, follw these steps:
+
+* save the certificate to your hardrive as a pkcs12 ( p12 ) file
+* convert it to pem including private key
+
+ > openssl pkcs12 -in cert.p12 -out myCert.pem
+
+Extra Userful Services provided
+-------------------------------
+
+### verify your key
+
+If you have trouble with your certificate you can test if it is being verified correctly
+with
+
+ $ curl -k --verbose -i -E myCert.pem https://localhost:8443/test/WebId
+
+### simple authentication service
+
+RWW comes with a simple authentication service that you can use to help
+others who don't have WebID to get going without needing to deploy TLS
+services. Go to [https://localhost:8443/srv/idp](https://localhost:8443/srv/idp) in your browser .
+
+This of course is not installed if you run as server on --http and it is
+disabled for Jetty, as in Jetty I have not found how to do TLS renegotiation
+so that the certificate does not need to be requested if the resource is not
+protected. (On such servers one needs authentication to happen on a different
+port )
+
+TODO
+----
+
+There is still a lot to do. Some things we are working on:
+
+* improve asynchronous behavior using [akka.io](http://akka.io/)
+* make it easy to switch between Jena, Sesame and other frameworks using [banana-rdf](https://github.com/w3c/banana-rdf/)
+* improve the access control reasoning (which is very very basic for the moment)
+* improve architecture to work more fluidly with non RDF resources, such as pictures or videos
+* enrich the HTTP headers with the metadata for the access control files (so that one can follow one's nose)
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/runProguarded.sh Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+#run the proguard compiled version of readwriteweb.
+
+java -Dnetty.ssl.keyStoreType=JKS -Dsun.security.ssl.allowUnsafeRenegotiation=true -Dsun.security.ssl.allowLegacyHelloMessages=true -Dnetty.ssl.keyStore=`pwd`/src/test/resources/KEYSTORE.jks -Dnetty.ssl.keyStorePassword=secret -Xms64M -Xmx700M -XX:+CMSClassUnloadingEnabled -classpath readwriteweb.jar org.w3.readwriteweb.netty.ReadWriteWebNetty --https 8443 test_www /2011/09
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/rwsbt.sh Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+BASE="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
+KS=$BASE/src/test/resources/KEYSTORE.jks
+while [ $# -gt 0 ]
+do
+ case $1 in
+ -d) PROPS="$PROPS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
+ ;;
+ -n) PROPS="$PROPS -Dnetty.ssl.keyStoreType=JKS -Dnetty.ssl.keyStore=$KS -Dnetty.ssl.keyStorePassword=secret"
+ ;;
+ -j) PROPS="$PROPS -Djetty.ssl.keyStoreType=JKS -Djetty.ssl.keyStore=$KS -Djetty.ssl.keyStorePassword=secret"
+ ;;
+ -sslUnsafe) PROPS="$PROPS -Dsun.security.ssl.allowUnsafeRenegotiation=true"
+ ;; # see: http://download.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#workarounds
+ -sslLegacy) PROPS="$PROPS -Dsun.security.ssl.allowLegacyHelloMessages=true"
+ ;;
+ -sslDebug) PROPS="$PROPS -Djavax.net.debug=all"
+ ;; # see http://download.oracle.com/javase/1,5,0/docs/guide/security/jsse/ReadDebug.html
+ *) echo the arguments to use are -d
+ ;;
+ esac
+ shift 1
+ done
+
+export SBT_PROPS=$PROPS
+$BASE/sbt
--- a/project/build.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/project/build.scala Wed May 23 23:47:37 2012 +0200
@@ -1,42 +1,62 @@
import sbt._
import Keys._
-// some usefull libraries
+// some useful libraries
// they are pulled only if used
object Dependencies {
- val shiro_core = "org.apache.shiro" % "shiro-core" % "1.1.0"
- val shiro_web = "org.apache.shiro" % "shiro-web" % "1.1.0"
- val specs = "org.scala-tools.testing" %% "specs" % "1.6.9" % "test"
- val dispatch_http = "net.databinder" %% "dispatch-http" % "0.8.5"
- val unfiltered_filter = "net.databinder" %% "unfiltered-filter" % "0.5.0"
- val unfiltered_jetty = "net.databinder" %% "unfiltered-jetty" % "0.5.0"
+// val specs = "org.scala-tools.testing" %% "specs" % "1.6.9" % "test"
+ val specs2 = "org.specs2" %% "specs2" % "1.6.1"
+ val specs2_scalaz = "org.specs2" %% "specs2-scalaz-core" % "6.0.1" % "test"
+ val dispatch_version = "0.8.8"
+ val dispatch_http = "net.databinder" %% "dispatch-http" % dispatch_version
+ val dispatch_nio = "net.databinder" %% "dispatch-nio" % dispatch_version
+ val unfiltered_version = "0.6.1"
+ val unfiltered_filter = "net.databinder" %% "unfiltered-filter" % unfiltered_version
+ val unfiltered_jetty = "net.databinder" %% "unfiltered-jetty" % unfiltered_version
+ val unfiltered_netty = "net.databinder" %% "unfiltered-netty" % unfiltered_version
+ val scalate = "net.databinder" %% "unfiltered-scalate" % "0.5.1"
// val unfiltered_spec = "net.databinder" %% "unfiltered-spec" % "0.4.1" % "test"
val ivyUnfilteredSpec =
<dependencies>
- <dependency org="net.databinder" name="unfiltered-spec_2.9.1" rev="0.5.0">
+ <dependency org="net.databinder" name="unfiltered-spec_2.9.1" rev={unfiltered_version}>
<exclude org="net.databinder" module="dispatch-mime_2.9.0-1"/>
</dependency>
</dependencies>
- val slf4jSimple = "org.slf4j" % "slf4j-simple" % "1.5.8"
- val antiXML = "com.codecommit" %% "anti-xml" % "0.4-SNAPSHOT" % "test"
- val jena = "com.hp.hpl.jena" % "jena" % "2.6.4"
- val arq = "com.hp.hpl.jena" % "arq" % "2.8.8"
+ val antiXML = "com.codecommit" %% "anti-xml" % "0.3" % "test"
+ val jena = "org.apache.jena" % "jena-core" % "2.7.0-incubating"
+ val arq = "org.apache.jena" % "jena-arq" % "2.9.0-incubating"
+ val rdfa = "net.rootdev" % "java-rdfa" % "0.4.2-RC2"
+ val htmlparser = "nu.validator.htmlparser" % "htmlparser" % "1.2.1"
val grizzled = "org.clapper" %% "grizzled-scala" % "1.0.8" % "test"
- val scalaz = "org.scalaz" %% "scalaz-core" % "6.0.2"
- val jsslutils = "org.jsslutils" % "jsslutils" % "1.0.7"
- val argot = "org.clapper" %% "argot" % "0.3.5"
+ val scalaz = "org.scalaz" %% "scalaz-core" % "6.0.4"
+ val argot = "org.clapper" %% "argot" % "0.4"
+ val guava = "com.google.guava" % "guava" % "11.0"
+// val restlet = "org.restlet.dev" % "org.restlet" % "2.1-SNAPSHOT"
+// val restlet_ssl = "org.restlet.dev" % "org.restlet.ext.ssl" % "2.1-SNAPSHOT"
+ val jsslutils = "org.jsslutils" % "jsslutils" % "1.0.5"
+ val slf4s = "com.weiglewilczek.slf4s" %% "slf4s" % "1.0.7"
+// val akka_actor = "com.typesafe.akka" % "akka-actor" % "2.0-M3"
+ val async_http_client = "com.ning" % "async-http-client" % "1.7.0"
+ val aalto_xml = "com.fasterxml" % "aalto-xml" % "0.9.7"
+// val akka_remote = "com.typesafe.akka" % "akka-remote" % "2.0-M3"
+// val finagle_http = "com.twitter" %% "finagle-http" % "1.9.12"
+ val subcut = "org.scala-tools.subcut" %% "subcut" % "1.0"
}
// some usefull repositories
object Resolvers {
val novus = "repo.novus snaps" at "http://repo.novus.com/snapshots/"
+ val mavenLocal = "Local Maven Repository" at "file://" + (Path.userHome / ".m2" / "repository").absolutePath
+ val typesafeSnap = "Typesafe Repository" at "http://repo.typesafe.com/typesafe/snapshots/"
+ val sonatype = "Sonatype Release" at "http://oss.sonatype.org/content/repositories/releases"
+// val twitter = "Twitter Repository" at "http://maven.twttr.com/"
}
// general build settings
object BuildSettings {
val buildOrganization = "org.w3"
- val buildVersion = "0.1-SNAPSHOT"
+ val buildVersion = "0.2-SNAPSHOT"
val buildScalaVersion = "2.9.1"
val buildSettings = Defaults.defaultSettings ++ Seq (
@@ -57,6 +77,7 @@
import ProguardPlugin._
import sbtassembly.Plugin._
import sbtassembly.Plugin.AssemblyKeys._
+
def keepUnder(pakage:String):String = "-keep class %s.**" format pakage
@@ -64,38 +85,53 @@
val proguardSettings:Seq[Setting[_]] =
ProguardPlugin.proguardSettings ++ Seq[Setting[_]](
minJarPath := new File("readwriteweb.jar"),
- proguardOptions += keepMain("org.w3.readwriteweb.ReadWriteWebMain"),
+ proguardOptions += keepMain("org.w3.readwriteweb.netty.ReadWriteWebNetty"),
proguardOptions += keepUnder("org.w3.readwriteweb"),
+ proguardOptions += keepUnder("org.apache.xerces"),
proguardOptions += keepUnder("unfiltered"),
proguardOptions += keepUnder("org.apache.log4j"),
proguardOptions += keepUnder("com.hp.hpl.jena"),
- proguardOptions += "-keep class com.hp.hpl.jena.rdf.model.impl.ModelCom"
+ proguardOptions += "-keep class com.hp.hpl.jena.rdf.model.impl.ModelCom",
+ makeInJarFilter <<= (makeInJarFilter) {
+ (makeInJarFilter) => {
+ (file) => file match {
+ case "slf4j-simple-1.6.4.jar" => makeInJarFilter(file) + ",!org/slf4j/**"
+ case _ => makeInJarFilter(file)
+ }
+ }
+ }
)
+
+
val projectSettings =
Seq(
- resolvers += ScalaToolsReleases,
- resolvers += ScalaToolsSnapshots,
- libraryDependencies += specs,
+ resolvers ++= Seq( mavenLocal, sonatype, typesafeSnap, ScalaToolsReleases, ScalaToolsSnapshots ) ,
+ libraryDependencies += specs2,
+ libraryDependencies += specs2_scalaz,
// libraryDependencies += unfiltered_spec,
ivyXML := ivyUnfilteredSpec,
- libraryDependencies += dispatch_http,
- libraryDependencies += unfiltered_filter,
- libraryDependencies += unfiltered_jetty,
-// libraryDependencies += slf4jSimple,
- libraryDependencies += jena,
- libraryDependencies += arq,
- libraryDependencies += antiXML,
- libraryDependencies += grizzled,
- libraryDependencies += scalaz,
- libraryDependencies += jsslutils,
- libraryDependencies += argot,
- libraryDependencies += shiro_core,
- libraryDependencies += shiro_web,
+ libraryDependencies ++= Seq(dispatch_http, dispatch_nio, unfiltered_filter,
+ unfiltered_jetty, unfiltered_netty,
+ jena, arq, rdfa,
+ grizzled,
+ scalaz,
+ subcut,
+ jsslutils,
+ argot,
+ guava,
+ scalate,
+ htmlparser,
+ slf4s,
+ async_http_client,
+ aalto_xml, antiXML) ,
- jarName in assembly := "read-write-web.jar"
+ jarName in assembly := "read-write-web.jar",
+ mainClass in assembly := Some("org.w3.readwriteweb.netty.ReadWriteWebNetty")
)
+
+
lazy val project = Project(
id = "read-write-web",
base = file("."),
--- a/project/plugins/build.sbt Thu Oct 13 13:34:16 2011 +0200
+++ b/project/plugins/build.sbt Wed May 23 23:47:37 2012 +0200
@@ -1,10 +1,19 @@
-addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.0")
+resolvers += Resolver.url("sbt-plugin-releases",
+ new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns)
+
+//now here: https://github.com/sbt/sbt-assembly
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.3")
resolvers += Classpaths.typesafeResolver
-addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse" % "1.4.0")
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0")
-resolvers += "Proguard plugin repo" at "http://siasia.github.com/maven2"
+resolvers += "sonatype" at "https://oss.sonatype.org/content/groups/scala-tools/"
-addSbtPlugin("com.github.siasia" % "xsbt-proguard-plugin" % "0.1")
+libraryDependencies <+= sbtVersion(v => "com.github.siasia" %% "xsbt-proguard-plugin" % (v+"-0.1.2"))
+// addSbtPlugin("com.github.siasia" %% "xsbt-proguard-plugin" % "0.1.2")
+
+resolvers += "sbt-idea-repo" at "http://mpeltonen.github.com/maven/"
+
+addSbtPlugin("com.github.mpeltonen" %% "sbt-idea" % "1.1.0-SNAPSHOT")
--- a/sbt Thu Oct 13 13:34:16 2011 +0200
+++ b/sbt Wed May 23 23:47:37 2012 +0200
@@ -3,9 +3,9 @@
dir=$(dirname $0)
cd "$dir"
-url="http://repo.typesafe.com/typesafe/ivy-releases/org.scala-tools.sbt/sbt-launch/0.11.0/sbt-launch.jar"
+url="http://repo.typesafe.com/typesafe/ivy-releases/org.scala-tools.sbt/sbt-launch/0.11.2/sbt-launch.jar"
-sbt="sbt-launch-0.11.0.jar"
+sbt="sbt-launch-0.11.2.jar"
# set the right tool to download sbt
if [ -n "$tool" ]; then
@@ -38,5 +38,5 @@
fi
# tweak this line according to your needs
-java -Xmx512M -jar -Dfile.encoding=UTF8 -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m "$dir/$sbt" "$@"
+java $SBT_PROPS -Xmx512M -jar -Dfile.encoding=UTF8 -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m "$dir/$sbt" "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/patch/AsyncJenaParser.java Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package patch;
+
+import java.util.Iterator;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.Comment;
+import javax.xml.stream.events.DTD;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.EntityDeclaration;
+import javax.xml.stream.events.Namespace;
+import javax.xml.stream.events.ProcessingInstruction;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import com.fasterxml.aalto.AsyncXMLStreamReader;
+import com.fasterxml.aalto.stax.InputFactoryImpl;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ *
+ * Bridge StAX and SAX parsing, with support for asynchronous parsing
+ *
+ * @author Henry Story mostly adapted from Damian Steer's jena.rdf.arp.StAX2SAX
+ */
+public class AsyncJenaParser {
+ private final ContentHandler handler;
+ private final LexicalHandler lhandler;
+ private final XMLEventReader eventReader;
+ private final AsyncXMLStreamReader streamReader;
+
+ /**
+ * Primes a converter with a SAX handler.
+ *
+ * Note: if handler is also LexicalHandler it will pass on lexical events.
+ *
+ * @param handler
+ */
+ public AsyncJenaParser(ContentHandler handler, AsyncXMLStreamReader streamReader) throws XMLStreamException {
+ this.handler = handler;
+ this.lhandler = (handler instanceof LexicalHandler) ?
+ (LexicalHandler) handler :
+ NO_LEXICAL_HANDLER ;
+ handler.setDocumentLocator(new LocatorConv(streamReader));
+ final XMLInputFactory xf = InputFactoryImpl.newInstance();
+ this.streamReader = streamReader;
+ this.eventReader = xf.createXMLEventReader(streamReader);
+ }
+
+
+ public void parse() throws XMLStreamException, SAXException {
+ // We permit nesting, so keep at track of where we are
+ boolean consecutive_incomplete = false;
+ while (eventReader.hasNext()) {
+ try {
+ XMLEvent e = eventReader.nextEvent();
+ handleXMLEvent(e);
+ consecutive_incomplete=false;
+ } catch (XMLStreamException e) {
+ if (streamReader.getEventType() == AsyncXMLStreamReader.EVENT_INCOMPLETE) {
+ if (consecutive_incomplete) return;
+ else consecutive_incomplete=true;
+ } else throw e;
+ }
+ }
+ }
+
+ /**
+ * Handle the next event
+ * @param e
+ * @return true if the end of the document has been reached. (ie, we are back at level 0)
+ * @throws SAXException
+ */
+ private void handleXMLEvent(XMLEvent e) throws SAXException {
+ if (e.isStartDocument()) handler.startDocument();
+ else if (e.isEndDocument()) handler.endDocument();
+ else if (e.isStartElement()) emitSE(e.asStartElement());
+ else if (e.isEndElement()) emitEE(e.asEndElement());
+ else if (e.isProcessingInstruction()) emitPi((ProcessingInstruction) e);
+ else if (e.isCharacters()) emitChars(e.asCharacters());
+ else if (e.isAttribute()) emitAttr((Attribute) e);
+ else if (e.isEntityReference()) emitEnt((EntityDeclaration) e);
+ else if (e.isNamespace()) emitNS((Namespace) e);
+ else if (e instanceof Comment) emitComment((Comment) e);
+ else if (e instanceof DTD) emitDTD((DTD) e);
+ else {
+ //System.err.println("Unknown / unhandled event type " + e);
+ //throw new SAXException("Unknown / unhandled event type " + e);
+ }
+ }
+
+ private void emitSE(StartElement se) throws SAXException {
+ @SuppressWarnings("unchecked")
+ Iterator<Attribute> aIter = se.getAttributes() ;
+ handler.startElement(se.getName().getNamespaceURI(),
+ se.getName().getLocalPart(), qnameToS(se.getName()), convertAttrs(aIter));
+ @SuppressWarnings("unchecked")
+ Iterator<Namespace> it = se.getNamespaces();
+ while (it.hasNext()) emitNS(it.next());
+ }
+
+ private void emitEE(EndElement ee) throws SAXException {
+ handler.endElement(ee.getName().getNamespaceURI(),
+ ee.getName().getLocalPart(), qnameToS(ee.getName()));
+ @SuppressWarnings("unchecked")
+ Iterator<Namespace> it = ee.getNamespaces();
+ while (it.hasNext()) emitNSGone(it.next());
+ }
+
+ private void emitPi(ProcessingInstruction pi) throws SAXException {
+ handler.processingInstruction(pi.getTarget(), pi.getData());
+ }
+
+ private void emitChars(Characters chars) throws SAXException {
+ if (chars.isIgnorableWhiteSpace())
+ handler.ignorableWhitespace(chars.getData().toCharArray(),
+ 0, chars.getData().length());
+ else
+ handler.characters(chars.getData().toCharArray(),
+ 0, chars.getData().length());
+ }
+
+ private void emitAttr(Attribute attribute) {
+ // nowt to do
+ }
+
+ private void emitEnt(EntityDeclaration entityDeclaration) {
+ // nowt to do
+ }
+
+ private void emitNS(Namespace namespace) throws SAXException {
+ // Safety check to work around nasty tests
+ if (namespace.getPrefix() == null ||
+ namespace.getNamespaceURI() == null) return;
+ handler.startPrefixMapping(namespace.getPrefix(), namespace.getNamespaceURI());
+ }
+
+ private void emitNSGone(Namespace namespace) throws SAXException {
+ handler.endPrefixMapping(namespace.getPrefix());
+ }
+
+ private void emitComment(Comment comment) throws SAXException {
+ lhandler.comment(comment.getText().toCharArray(), 0, comment.getText().length());
+ }
+
+ private void emitDTD(DTD dtd) {
+ // Is this useful??
+ }
+
+ private Attributes convertAttrs(Iterator<Attribute> attributes) {
+ AttributesImpl toReturn = new AttributesImpl();
+ while (attributes.hasNext()) {
+ Attribute a = attributes.next();
+ toReturn.addAttribute(a.getName().getNamespaceURI(), a.getName().getLocalPart(),
+ qnameToS(a.getName()), a.getDTDType(), a.getValue());
+ }
+ return toReturn;
+ }
+
+ private String qnameToS(QName name) {
+ if (name.getPrefix().length() == 0) return name.getLocalPart();
+ else return name.getPrefix() + ":" + name.getLocalPart();
+ }
+
+ static class LocatorConv implements Locator {
+ private final XMLStreamReader reader;
+
+ public LocatorConv(XMLStreamReader reader) { this.reader = reader; }
+
+ @Override
+ public final String getPublicId() { return reader.getLocation().getPublicId(); }
+ @Override
+ public final String getSystemId() { return reader.getLocation().getSystemId(); }
+ @Override
+ public final int getLineNumber() { return reader.getLocation().getLineNumber(); }
+ @Override
+ public final int getColumnNumber() { return reader.getLocation().getColumnNumber(); }
+ }
+
+ final static LexicalHandler NO_LEXICAL_HANDLER = new LexicalHandler() {
+ @Override
+ public void startDTD(String string, String string1, String string2) throws SAXException {}
+ @Override
+ public void endDTD() throws SAXException {}
+ @Override
+ public void startEntity(String string) throws SAXException {}
+ @Override
+ public void endEntity(String string) throws SAXException {}
+ @Override
+ public void startCDATA() throws SAXException {}
+ @Override
+ public void endCDATA() throws SAXException {}
+ @Override
+ public void comment(char[] chars, int i, int i1) throws SAXException {}
+ };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/log4j.properties Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,9 @@
+// Appenders
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.layout=org.apache.log4j.PatternLayout
+// Pattern not for use in production ( %C
+log4j.appender.Console.layout.ConversionPattern=%-5p (%F:%L) : %m%n
+
+// Loggers
+log4j.rootLogger=info, Console
+log4j.logger.org.w3.readwriteweb=debug
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/ontologies/RelyingParty.n3 Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,176 @@
+# vocabulary to allow a RelyingParty to make a report on an attempt at a WebID authentication.
+
+@prefix cert: <http://www.w3.org/ns/auth/cert#> .
+@prefix rsa: <http://www.w3.org/ns/auth/rsa#> .
+@prefix earl: <http://www.w3.org/ns/earl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix dct: <http://purl.org/dc/terms/> .
+@prefix dc: <http://purl.org/dc/elements/1.1/> .
+@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix wit: <http://www.w3.org/2005/Incubator/webid/earl/RelyingParty#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix log: <http://www.w3.org/2000/10/swap/log#> .
+
+
+<#> a owl:Ontology .
+
+<> a foaf:Document;
+ dc:author <http://bblfish.net/people/henry/card#me>;
+ dc:contributor <http://www.bergnet.org/people/bergi/card#me>;
+ rdfs:comment "Document describing a vocabulary to allow a RelyingParty to make a report on an attempt at a WebID authentication."@en;
+ rdfs:seeAlso <http://www.w3.org/2005/Incubator/webid/earl/RelyingPartyExample#>.
+
+#
+# Classes
+#
+
+wit:WebIDClaim a rdfs:Class;
+ rdfs:comment "A WebID Claim is a graph that consists of a claim that a public key identifies some WebID. Every WebID published in a certificate constitutes one WebID claim: the claim that the referent of the WebID is the only one to know the private key of the public key that came in the certificate"@en.
+
+#
+# Properties
+#
+wit:claimedKey a rdfs:Property;
+ rdfs:comment "Public key of a WebID Claim."@en;
+ rdfs:domain wit:WebIDClaim;
+ rdfs:range rsa:RSAPublicKey.
+
+wit:claimedIdentity a rdfs:Property;
+ rdfs:comment "Identity URI of a WebID Claim."@en;
+ rdfs:domain wit:WebIDClaim.
+
+#
+# pure certificate tests
+#
+wit:certificateProvided a earl:TestCase;
+ dct:title "Did the client provide a X509 certificate?"@en;
+ dct:description "Without a client certificate this type of WebID Authentication can not take place."@en;
+ skos:note "If the client provided an certificate, the earl:pointer property must point to it. The certificate is described with the class cert:Certificate using the property cert:base64der. The property cert:principal_key must point to the contained public key. The public key is described with a rsa:publicKey which contains the properties rsa:modulus and rsa:public_exponent. The log:semantics property must point to a blank node that contains a log:includes property for every WebIDClaim."@en.
+
+wit:certificateProvidedSAN a earl:TestCase;
+ dct:title "Does the client certificate contain a subject alternative name?"@en;
+ dct:description "The client certificate must contain at least one Subject Alternative Name in the SAN field of the certificate"@en;
+ skos:note "The earl:subject property must point to the certificate. The earl:pointer must contain the complete subject alternative name string. The certificate is described with the class cert:Certificate using the property cert:base64der. The property cert:principal_key should point to the contained public key."@en.
+
+wit:certificateDateOk a earl:TestCase;
+ dct:title "Is the certificate alive?"@en;
+ dct:description "The time of this session should be between the begin and end date of the certificate validity times"@en;
+ skos:note "The earl:subject property must point to the certificate. The certificate is described with the class cert:Certificate using the property cert:base64der. The property cert:principal_key should point to the contained public key."@en.
+
+wit:certificatePubkeyRecognised a earl:TestCase;
+ dct:title "Could the public key be recognised?"@en;
+ dct:description "The public key in the certificate is recognised by the WebId code. If it is not then this server will not know how to match it with the remote WebID Profile. "@en;
+ skos:note "The earl:subject property must point to the certificate. The earl:pointer must point to the public key. The certificate is described with the class cert:Certificate using the property cert:base64der. The property cert:principal_key should point to the contained public key. The public key is described with the class rsa:RSAPublicKey with the properties rsa:modulus and rsa:public_exponent like described in the WebID specification."@en.
+
+wit:certificateCriticalExtensionsOk a earl:TestCase;
+ dct:title "Does the certificate contain no unnecessary critical extensions?"@en;
+ dct:description "Critical Extensions are not a direct problem for WebID, but may cause many servers to reject the certificate before the WebID code gets to see it. These tests should not generate errors but only warnings"@en;
+ skos:note "The earl:subject property must point to the certificate. The certificate is described with the class cert:Certificate using the property cert:base64der. The property cert:principal_key should point to the contained public key."@en.
+
+wit:certificateOk a earl:TestRequirement;
+ dct:title "Does the certificate fulfill all requirements for a WebID certificate?"@en;
+ dct:description "The certificate must be alive, have one or more WebIDs, should have a public key recognised by the semantic web layer, and should avoid having critical extensions. "@en;
+ dct:hasPart
+ wit:certificateProvided,
+ wit:certificateProvidedSAN,
+ wit:certificateDateOk,
+ wit:certificatePubkeyRecognised,
+ wit:certificateCriticalExtensionsOk;
+ skos:note "If any of the child test cases fails this test requirement must return earl:failed."@en.
+
+#
+# profile tests
+#
+wit:profileGet a earl:TestCase;
+ dct:title "Is the WebID Profile accessible and downloadable?"@en;
+ dct:description "The WebID profile must be retrievable if the claims are going to be verified."@en;
+ skos:note "The earl:subject property should point to the WebID profile, or to a link where a copy of that profile can be fetched. The content could also be included in the document." .
+
+wit:profileWellFormed a earl:TestCase;
+ dct:title "Is the profile well formed?"@en;
+ dct:description "The WebId Profile must be parseable Content and transformable to an RDF graph"@en;
+ skos:note "The earl:subject property should point to the WebID profile, or to a link where a copy of that profile can be fetched. The content could also be included in the document." .
+
+
+wit:profileAllKeysWellFormed a earl:TestCase;
+ dct:title "Does the profile contain only well formed keys for that WebID?"@en;
+ dct:description "All the keys in the profile should be well formed and semantically consistent. It is not necessarily fatal to a particular WebID authentication if they are not, but it is worth alerting the user, as this may lead to inconsistent user experience."@en;
+ skos:note "One does not need to test all keys in a profile, only those that are tied to the WebIDs found in the X509 cert. But to help users one could give them a deeper test of the profile."@en;
+ dct:hasPart
+ wit:profileWellFormedPubkey.
+
+wit:profileWellFormedPubkey a earl:TestRequirement;
+ dct:title "Is the public key well formed?"@en;
+ dct:description "A particular Public key should be well formed"@en;
+ skos:note "The earl:subject property must point to a graph that contains the public key and its webid relation. To help this being processed by tools that are not able to deal with n3 graphs, this should point using the log:n3string relation to a turtle serialisation of the graph (turtle is a subset of n3)"@en;
+ skos:note "The current cert ontology doesn't include properties for DSA, and so there are currently no tests for DSA keys either"@en;
+ dct:hasPart
+ wit:pubkeyRSAModulus,
+ wit:pubkeyRSAExponent.
+
+wit:pubkeyRSAModulus a earl:TestCase;
+ dct:title "Is the RSA modulus well formed?"@en;
+ dct:description "There may be a number of ways of writing the modulus. Is this server able to parse this particular modulus?"@en;
+ dct:hasPart
+ wit:pubkeyRSAModulusFunctional,
+ wit:pubkeyRSAModulusLiteral.
+
+wit:pubkeyRSAModulusFunctional a earl:TestCase;
+ dct:title "Does the public key contain only one modulus?"@en;
+ dct:description "More than one modulus if they don't convert to the same number will lead to erratic behavior (one server will choose one the other server will chose the other)"@en.
+
+wit:pubkeyRSAModulusLiteral a earl:TestCase;
+ dct:title "Is the RSA modulus a literal number?"@en;
+ dct:description "In the current ontology we have moved to literals as the standard way of describing modulus and exponents"@en.
+
+wit:pubkeyRSAExponent a earl:TestCase;
+ dct:title "Is the RSA public exponent well formed?"@en;
+ dct:description "There may be a number of ways of writing the exponent. Is this server able to parse this particular exponent?"@en;
+ dct:hasPart
+ wit:pubkeyRSAExponentFunctional,
+ wit:pubkeyRSAExponentLiteral.
+
+wit:pubkeyRSAExponentFunctional a earl:TestCase;
+ dct:title "Does the public key contain only one public exponent?"@en;
+ dct:description "More than one exponent if they don't convert to the same number is very likely to create erratic behavior (one server will choose one the other server will chose the other)"@en.
+
+wit:pubkeyRSAExponentLiteral a earl:TestCase;
+ dct:title "Is the RSA public exponent a literal number?"@en;
+ dct:description "In the current ontology we have moved to literals as the standard way of describing modulus and exponents"@en.
+
+wit:profileOk a earl:TestRequirement;
+ dct:title "Does the profile fulfill all requirements for WebID authentication?"@en;
+ dct:hasPart
+ wit:profileGet,
+ wit:profileWellFormed,
+ wit:profileAllKeysWellFormed.
+
+wit:pubkeyRSAModulusOldFunctional a earl:TestCase;
+ dct:title "If modulus is using non literal notation, is there only one cert:hex relation to plain literal?"@en;
+ skos:note "this should be a deprecated test sooner rather than later. Warn people to move to newer notation."@en.
+
+wit:pubkeyRSAExponentOldFunctional a earl:TestCase;
+ dct:title "If public exponent is using non literal notation, is there only one cert:decimal relation to plain literal?"@en.
+
+wit:pubkeyOldOk a earl:TestRequirement;
+ dct:title "Is the public key present in valid old non literal notation?"@en;
+ dct:hasPart
+ wit:pubkeyRSAModulusOldFunctional,
+ wit:pubkeyRSAExponentOldFunctional.
+
+#
+# webid protocol tests: ie: tying pubkey and Webid in certificate to remote WebID identifying description
+#
+wit:webidClaim a earl:TestRequirement;
+ dct:title "Could the particular WebID claim be verified?"@en;
+ dct:description "Verification of a particular WebID claim"@en;
+ dct:hasPart
+ wit:certificateOk,
+ wit:profileOk.
+
+wit:webidAuthentication a earl:TestRequirement;
+ dct:title "Could at least one WebID claim be verified?"@en;
+ dct:description "At least one WebID claimed in the certificate has public key that verifies."@en;
+ dct:hasPart wit:webidClaim.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_css/general.css Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,118 @@
+@charset "UTF-8";
+/* CSS Document */
+
+*{ outline:none; font-size:14px; color:#333333; margin:0px; padding:0px;font-family:Arial, Helvetica, sans-serif; }
+body{ }
+a{ display:inline-block; text-decoration:none; }
+.clear{ clear:both; }
+.hide{ display:none; }
+
+ul{ padding-left:20px; margin:5px 0px; }
+ul li{ padding:4px 0px; }
+
+h1, h2, h3 { }
+h3{ color:#666; font-weight:lighter; }
+
+
+
+/* GENERAL FORM */
+
+input, textarea { border:1px solid #333; width:300px; padding:4px; margin-bottom:10px; }
+button{ padding:5px 10px; border:none; background:#F2F2F2; color:#0083E2; cursor:pointer; margin-right:10px;-moz-border-radius: 5px; -webkit-border-radius: 5px; -khtml-border-radius: 5px;border-radius: 5px; }
+button:hover{ border:none; background:#CCC; color:#00396B; }
+select{ }
+
+a{ color:#0083E2; text-decoration:none; font-size:12px; }
+a:hover{ text-decoration:none; color:#00396B; }
+
+
+
+#topbar{ width:100%; height:50px; background:#333; color:#CCC; }
+#topbar img{ position:relative; top:-2px; }
+.wrapper, .wrapper h1{ color:#CCC; }
+.wrapper h1, .wrapper input, .wrapper button{ display:inline-block; }
+
+.wrapper h1{ font-size:24px; padding:10px 0px; margin-right:40px; cursor:pointer; position:relative; top:3px; }
+
+.wrapper form{ display:inline-block; width:280px; }
+.wrapper input{ width:240px; background:#666; border:1ps solid #000; position:relative; z-index:1; color:#CCC; }
+.wrapper button{ display:inline-block; position:relative; z-index:2; left:-30px; width:15px; height:15px; padding:0px; margin:0px; border:none; cursor:pointer; background:url(../a_img/search_btn.png) no-repeat; }
+
+.topbar_links{ text-decoration:none; font-size:16px; padding:4px; margin:0px 3px; color:#CCC; }
+.topbar_links:hover{ color:#999; }
+
+
+.wrapper div{ position:absolute; right:0px; text-align:right; top:18px; color:#CCC; }
+.wrapper div a{ color:#CCC; font-size:14px; text-decoration:none; }
+.wrapper div a:hover{ text-decoration:none; color:#999; }
+.wrapper div span{ margin:0px 4px; color:#ccc; }
+
+#site_wrapper, .wrapper{ width:960px; margin:0 auto; position:relative; }
+
+#site_wrapper{ margin-top:10px; margin-bottom:20px; min-height:500px; }
+
+#site_content{ width:100%; position:relative; }
+
+
+#left_column{ width:520px; float:left; padding-right:17px; border-right:1px solid #666; height:100%; min-height:900px; }
+
+#right_column{ width:400px; float:right; height:100%; }
+
+#footer{ margin-bottom:50px; margin-top:20px; padding-top:10px; border-top:1px solid #CCC; text-align:center; color:#9f9f9f; }
+
+
+#status_box{ padding:15px 0px; }
+#status_box h2{ padding:5px; font-size:16px; font-weight:normal; display:block; }
+#status_box textarea{ width:510px; height:20px; display:block; }
+#status_box button{ }
+#status_box button:hover{ }
+#status_box span{ font-size:11px; color:#999; font-style:oblique; }
+
+
+
+#load_more{ width:100%; background:#EEFAFF; padding:10px 0px; }
+
+
+
+/* FOR USER WALL FEED DISPLAY */
+.story_box{ width:100%; border-bottom:1px solid #CCC; padding:15px 0px 5px 0px; }
+.story_box:hover{ background:#F2F2F2; }
+
+.story_left_column{ float:left; width:40px; margin-right:18px; margin-bottom:15px; padding-left:3px; }
+.story_left_column img{ width:100%; }
+
+.story_right_column{float:right; width:875px; }
+.story_right_column input{ display:inline-block; width:15px; height:15px; float:left; margin-top:2px; }
+.text{ font-size:16px; margin-bottom:10px; }
+
+.story_bottom_row{ width:100%; }
+.story_bottom_left{ float:left; margin-left:3px; }
+.story_bottom_left span{ color:#B3B3B3; font-size:10px; margin-right:5px; }
+.story_bottom_left span a{font-size:10px; }
+.story_bottom_right{ float:right; margin-right:3px; }
+
+.strikethrough{ text-decoration:line-through; }
+
+
+
+
+/* FOR COMMENT SLIDE DOWN */
+.story_comments{ width:865px; padding:10px 5px; background:#F2F6FE; border-bottom:1px solid #CCC; margin-left:85px; }
+.story_comments_img{ float:left; width:40px; }
+.story_comments_txt{ float:right; width:800px; }
+.story_comments_txt textarea{ height:20px; width:780px !important; }
+.story_comments_txt strong{ color:#999; font-weight:lighter; }
+.story_comments_txt button{ }
+.story_comments_txt button:hover{ }
+
+/* FOR USER INFO DISPLAY */
+
+
+
+
+
+
+/* FOR PROFILE PAGE */
+#profile_img_holder{ width:80px; height:80px; border:1px solid #333333; background:url(img/ajax-loader.gif) 50% 50%; float:left; margin-right:20px; }
+#profile_img_holder img{ width:100%; height:100%; }
+
Binary file src/main/resources/people/a_img/ajax-loader.gif has changed
Binary file src/main/resources/people/a_img/avatar.png has changed
Binary file src/main/resources/people/a_img/clip.jpg has changed
Binary file src/main/resources/people/a_img/clip.png has changed
Binary file src/main/resources/people/a_img/favicon.ico has changed
Binary file src/main/resources/people/a_img/icon_right_minimizer.gif has changed
Binary file src/main/resources/people/a_img/icon_right_minimizer_hover.gif has changed
Binary file src/main/resources/people/a_img/icon_right_minimizer_reverse.gif has changed
Binary file src/main/resources/people/a_img/icon_right_minimizer_reverse_hover.gif has changed
Binary file src/main/resources/people/a_img/search_btn.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/ajaxupload.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,673 @@
+/**
+ * AJAX Upload ( http://valums.com/ajax-upload/ )
+ * Copyright (c) Andris Valums
+ * Licensed under the MIT license ( http://valums.com/mit-license/ )
+ * Thanks to Gary Haran, David Mark, Corey Burns and others for contributions
+ */
+(function () {
+ /* global window */
+ /* jslint browser: true, devel: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true */
+
+ /**
+ * Wrapper for FireBug's console.log
+ */
+ function log(){
+ if (typeof(console) != 'undefined' && typeof(console.log) == 'function'){
+ Array.prototype.unshift.call(arguments, '[Ajax Upload]');
+ console.log( Array.prototype.join.call(arguments, ' '));
+ }
+ }
+
+ /**
+ * Attaches event to a dom element.
+ * @param {Element} el
+ * @param type event name
+ * @param fn callback This refers to the passed element
+ */
+ function addEvent(el, type, fn){
+ if (el.addEventListener) {
+ el.addEventListener(type, fn, false);
+ } else if (el.attachEvent) {
+ el.attachEvent('on' + type, function(){
+ fn.call(el);
+ });
+ } else {
+ throw new Error('not supported or DOM not loaded');
+ }
+ }
+
+ /**
+ * Attaches resize event to a window, limiting
+ * number of event fired. Fires only when encounteres
+ * delay of 100 after series of events.
+ *
+ * Some browsers fire event multiple times when resizing
+ * http://www.quirksmode.org/dom/events/resize.html
+ *
+ * @param fn callback This refers to the passed element
+ */
+ function addResizeEvent(fn){
+ var timeout;
+
+ addEvent(window, 'resize', function(){
+ if (timeout){
+ clearTimeout(timeout);
+ }
+ timeout = setTimeout(fn, 100);
+ });
+ }
+
+ // Needs more testing, will be rewriten for next version
+ // getOffset function copied from jQuery lib (http://jquery.com/)
+ if (document.documentElement.getBoundingClientRect){
+ // Get Offset using getBoundingClientRect
+ // http://ejohn.org/blog/getboundingclientrect-is-awesome/
+ var getOffset = function(el){
+ var box = el.getBoundingClientRect();
+ var doc = el.ownerDocument;
+ var body = doc.body;
+ var docElem = doc.documentElement; // for ie
+ var clientTop = docElem.clientTop || body.clientTop || 0;
+ var clientLeft = docElem.clientLeft || body.clientLeft || 0;
+
+ // In Internet Explorer 7 getBoundingClientRect property is treated as physical,
+ // while others are logical. Make all logical, like in IE8.
+ var zoom = 1;
+ if (body.getBoundingClientRect) {
+ var bound = body.getBoundingClientRect();
+ zoom = (bound.right - bound.left) / body.clientWidth;
+ }
+
+ if (zoom > 1) {
+ clientTop = 0;
+ clientLeft = 0;
+ }
+
+ var top = box.top / zoom + (window.pageYOffset || docElem && docElem.scrollTop / zoom || body.scrollTop / zoom) - clientTop, left = box.left / zoom + (window.pageXOffset || docElem && docElem.scrollLeft / zoom || body.scrollLeft / zoom) - clientLeft;
+
+ return {
+ top: top,
+ left: left
+ };
+ };
+ } else {
+ // Get offset adding all offsets
+ var getOffset = function(el){
+ var top = 0, left = 0;
+ do {
+ top += el.offsetTop || 0;
+ left += el.offsetLeft || 0;
+ el = el.offsetParent;
+ } while (el);
+
+ return {
+ left: left,
+ top: top
+ };
+ };
+ }
+
+ /**
+ * Returns left, top, right and bottom properties describing the border-box,
+ * in pixels, with the top-left relative to the body
+ * @param {Element} el
+ * @return {Object} Contains left, top, right,bottom
+ */
+ function getBox(el){
+ var left, right, top, bottom;
+ var offset = getOffset(el);
+ left = offset.left;
+ top = offset.top;
+
+ right = left + el.offsetWidth;
+ bottom = top + el.offsetHeight;
+
+ return {
+ left: left,
+ right: right,
+ top: top,
+ bottom: bottom
+ };
+ }
+
+ /**
+ * Helper that takes object literal
+ * and add all properties to element.style
+ * @param {Element} el
+ * @param {Object} styles
+ */
+ function addStyles(el, styles){
+ for (var name in styles) {
+ if (styles.hasOwnProperty(name)) {
+ el.style[name] = styles[name];
+ }
+ }
+ }
+
+ /**
+ * Function places an absolutely positioned
+ * element on top of the specified element
+ * copying position and dimentions.
+ * @param {Element} from
+ * @param {Element} to
+ */
+ function copyLayout(from, to){
+ var box = getBox(from);
+
+ addStyles(to, {
+ position: 'absolute',
+ left : box.left + 'px',
+ top : box.top + 'px',
+ width : from.offsetWidth + 'px',
+ height : from.offsetHeight + 'px'
+ });
+ }
+
+ /**
+ * Creates and returns element from html chunk
+ * Uses innerHTML to create an element
+ */
+ var toElement = (function(){
+ var div = document.createElement('div');
+ return function(html){
+ div.innerHTML = html;
+ var el = div.firstChild;
+ return div.removeChild(el);
+ };
+ })();
+
+ /**
+ * Function generates unique id
+ * @return unique id
+ */
+ var getUID = (function(){
+ var id = 0;
+ return function(){
+ return 'ValumsAjaxUpload' + id++;
+ };
+ })();
+
+ /**
+ * Get file name from path
+ * @param {String} file path to file
+ * @return filename
+ */
+ function fileFromPath(file){
+ return file.replace(/.*(\/|\\)/, "");
+ }
+
+ /**
+ * Get file extension lowercase
+ * @param {String} file name
+ * @return file extenstion
+ */
+ function getExt(file){
+ return (-1 !== file.indexOf('.')) ? file.replace(/.*[.]/, '') : '';
+ }
+
+ function hasClass(el, name){
+ var re = new RegExp('\\b' + name + '\\b');
+ return re.test(el.className);
+ }
+ function addClass(el, name){
+ if ( ! hasClass(el, name)){
+ el.className += ' ' + name;
+ }
+ }
+ function removeClass(el, name){
+ var re = new RegExp('\\b' + name + '\\b');
+ el.className = el.className.replace(re, '');
+ }
+
+ function removeNode(el){
+ el.parentNode.removeChild(el);
+ }
+
+ /**
+ * Easy styling and uploading
+ * @constructor
+ * @param button An element you want convert to
+ * upload button. Tested dimentions up to 500x500px
+ * @param {Object} options See defaults below.
+ */
+ window.AjaxUpload = function(button, options){
+ this._settings = {
+ // Location of the server-side upload script
+ action: 'upload.php',
+ // File upload name
+ name: 'userfile',
+ // Additional data to send
+ data: {},
+ // Submit file as soon as it's selected
+ autoSubmit: true,
+ // The type of data that you're expecting back from the server.
+ // html and xml are detected automatically.
+ // Only useful when you are using json data as a response.
+ // Set to "json" in that case.
+ responseType: false,
+ // Class applied to button when mouse is hovered
+ //hoverClass: 'hover',
+ // Class applied to button when AU is disabled
+ disabledClass: 'disabled',
+ // When user selects a file, useful with autoSubmit disabled
+ // You can return false to cancel upload
+ onChange: function(file, extension){
+ },
+ // Callback to fire before file is uploaded
+ // You can return false to cancel upload
+ onSubmit: function(file, extension){
+ },
+ // Fired when file upload is completed
+ // WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE!
+ onComplete: function(file, response){
+ }
+ };
+
+ // Merge the users options with our defaults
+ for (var i in options) {
+ if (options.hasOwnProperty(i)){
+ this._settings[i] = options[i];
+ }
+ }
+
+ // button isn't necessary a dom element
+ if (button.jquery){
+ // jQuery object was passed
+ button = button[0];
+ } else if (typeof button == "string") {
+ if (/^#.*/.test(button)){
+ // If jQuery user passes #elementId don't break it
+ button = button.slice(1);
+ }
+
+ button = document.getElementById(button);
+ }
+
+ if ( ! button || button.nodeType !== 1){
+ throw new Error("Please make sure that you're passing a valid element");
+ }
+
+ if ( button.nodeName.toUpperCase() == 'A'){
+ // disable link
+ addEvent(button, 'click', function(e){
+ if (e && e.preventDefault){
+ e.preventDefault();
+ } else if (window.event){
+ window.event.returnValue = false;
+ }
+ });
+ }
+
+ // DOM element
+ this._button = button;
+ // DOM element
+ this._input = null;
+ // If disabled clicking on button won't do anything
+ this._disabled = false;
+
+ // if the button was disabled before refresh if will remain
+ // disabled in FireFox, let's fix it
+ this.enable();
+
+ this._rerouteClicks();
+ };
+
+ // assigning methods to our class
+ AjaxUpload.prototype = {
+ setData: function(data){
+ this._settings.data = data;
+ },
+ disable: function(){
+ addClass(this._button, this._settings.disabledClass);
+ this._disabled = true;
+
+ var nodeName = this._button.nodeName.toUpperCase();
+ if (nodeName == 'INPUT' || nodeName == 'BUTTON'){
+ this._button.setAttribute('disabled', 'disabled');
+ }
+
+ // hide input
+ if (this._input){
+ // We use visibility instead of display to fix problem with Safari 4
+ // The problem is that the value of input doesn't change if it
+ // has display none when user selects a file
+ this._input.parentNode.style.visibility = 'hidden';
+ }
+ },
+ enable: function(){
+ removeClass(this._button, this._settings.disabledClass);
+ this._button.removeAttribute('disabled');
+ this._disabled = false;
+
+ },
+ /**
+ * Creates invisible file input
+ * that will hover above the button
+ * <div><input type='file' /></div>
+ */
+ _createInput: function(){
+ var self = this;
+
+ var input = document.createElement("input");
+ input.setAttribute('type', 'file');
+ input.setAttribute('name', this._settings.name);
+
+ addStyles(input, {
+ 'position' : 'absolute',
+ // in Opera only 'browse' button
+ // is clickable and it is located at
+ // the right side of the input
+ 'right' : 0,
+ 'margin' : 0,
+ 'padding' : 0,
+ 'fontSize' : '480px',
+ 'cursor' : 'pointer'
+ });
+
+ var div = document.createElement("div");
+ addStyles(div, {
+ 'display' : 'block',
+ 'position' : 'absolute',
+ 'overflow' : 'hidden',
+ 'margin' : 0,
+ 'padding' : 0,
+ 'opacity' : 0,
+ // Make sure browse button is in the right side
+ // in Internet Explorer
+ 'direction' : 'ltr',
+ //Max zIndex supported by Opera 9.0-9.2
+ 'zIndex': 2147483583
+ });
+
+ // Make sure that element opacity exists.
+ // Otherwise use IE filter
+ if ( div.style.opacity !== "0") {
+ if (typeof(div.filters) == 'undefined'){
+ throw new Error('Opacity not supported by the browser');
+ }
+ div.style.filter = "alpha(opacity=0)";
+ }
+
+ addEvent(input, 'change', function(){
+
+ if ( ! input || input.value === ''){
+ return;
+ }
+
+ // Get filename from input, required
+ // as some browsers have path instead of it
+ var file = fileFromPath(input.value);
+
+ if (false === self._settings.onChange.call(self, file, getExt(file))){
+ self._clearInput();
+ return;
+ }
+
+ // Submit form when value is changed
+ if (self._settings.autoSubmit) {
+ self.submit();
+ }
+ });
+
+ addEvent(input, 'mouseover', function(){
+ addClass(self._button, self._settings.hoverClass);
+ });
+
+ addEvent(input, 'mouseout', function(){
+ removeClass(self._button, self._settings.hoverClass);
+
+ // We use visibility instead of display to fix problem with Safari 4
+ // The problem is that the value of input doesn't change if it
+ // has display none when user selects a file
+ input.parentNode.style.visibility = 'hidden';
+
+ });
+
+ div.appendChild(input);
+ document.body.appendChild(div);
+
+ this._input = input;
+ },
+ _clearInput : function(){
+ if (!this._input){
+ return;
+ }
+
+ // this._input.value = ''; Doesn't work in IE6
+ removeNode(this._input.parentNode);
+ this._input = null;
+ this._createInput();
+
+ removeClass(this._button, this._settings.hoverClass);
+ },
+ /**
+ * Function makes sure that when user clicks upload button,
+ * the this._input is clicked instead
+ */
+ _rerouteClicks: function(){
+ var self = this;
+
+ // IE will later display 'access denied' error
+ // if you use using self._input.click()
+ // other browsers just ignore click()
+
+ addEvent(self._button, 'mouseover', function(){
+ if (self._disabled){
+ return;
+ }
+
+ if ( ! self._input){
+ self._createInput();
+ }
+
+ var div = self._input.parentNode;
+ copyLayout(self._button, div);
+ div.style.visibility = 'visible';
+
+ });
+
+
+ // commented because we now hide input on mouseleave
+ /**
+ * When the window is resized the elements
+ * can be misaligned if button position depends
+ * on window size
+ */
+ //addResizeEvent(function(){
+ // if (self._input){
+ // copyLayout(self._button, self._input.parentNode);
+ // }
+ //});
+
+ },
+ /**
+ * Creates iframe with unique name
+ * @return {Element} iframe
+ */
+ _createIframe: function(){
+ // We can't use getTime, because it sometimes return
+ // same value in safari :(
+ var id = getUID();
+
+ // We can't use following code as the name attribute
+ // won't be properly registered in IE6, and new window
+ // on form submit will open
+ // var iframe = document.createElement('iframe');
+ // iframe.setAttribute('name', id);
+
+ var iframe = toElement('<iframe src="javascript:false;" name="' + id + '" />');
+ // src="javascript:false; was added
+ // because it possibly removes ie6 prompt
+ // "This page contains both secure and nonsecure items"
+ // Anyway, it doesn't do any harm.
+ iframe.setAttribute('id', id);
+
+ iframe.style.display = 'none';
+ document.body.appendChild(iframe);
+
+ return iframe;
+ },
+ /**
+ * Creates form, that will be submitted to iframe
+ * @param {Element} iframe Where to submit
+ * @return {Element} form
+ */
+ _createForm: function(iframe){
+ var settings = this._settings;
+
+ // We can't use the following code in IE6
+ // var form = document.createElement('form');
+ // form.setAttribute('method', 'post');
+ // form.setAttribute('enctype', 'multipart/form-data');
+ // Because in this case file won't be attached to request
+ var form = toElement('<form method="post" enctype="multipart/form-data"></form>');
+
+ form.setAttribute('action', settings.action);
+ form.setAttribute('target', iframe.name);
+ form.style.display = 'none';
+ document.body.appendChild(form);
+
+ // Create hidden input element for each data key
+ for (var prop in settings.data) {
+ if (settings.data.hasOwnProperty(prop)){
+ var el = document.createElement("input");
+ el.setAttribute('type', 'hidden');
+ el.setAttribute('name', prop);
+ el.setAttribute('value', settings.data[prop]);
+ form.appendChild(el);
+ }
+ }
+ return form;
+ },
+ /**
+ * Gets response from iframe and fires onComplete event when ready
+ * @param iframe
+ * @param file Filename to use in onComplete callback
+ */
+ _getResponse : function(iframe, file){
+ // getting response
+ var toDeleteFlag = false, self = this, settings = this._settings;
+
+ addEvent(iframe, 'load', function(){
+
+ if (// For Safari
+ iframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" ||
+ // For FF, IE
+ iframe.src == "javascript:'<html></html>';"){
+ // First time around, do not delete.
+ // We reload to blank page, so that reloading main page
+ // does not re-submit the post.
+
+ if (toDeleteFlag) {
+ // Fix busy state in FF3
+ setTimeout(function(){
+ removeNode(iframe);
+ }, 0);
+ }
+
+ return;
+ }
+
+ var doc = iframe.contentDocument ? iframe.contentDocument : window.frames[iframe.id].document;
+
+ // fixing Opera 9.26,10.00
+ if (doc.readyState && doc.readyState != 'complete') {
+ // Opera fires load event multiple times
+ // Even when the DOM is not ready yet
+ // this fix should not affect other browsers
+ return;
+ }
+
+ // fixing Opera 9.64
+ if (doc.body && doc.body.innerHTML == "false") {
+ // In Opera 9.64 event was fired second time
+ // when body.innerHTML changed from false
+ // to server response approx. after 1 sec
+ return;
+ }
+
+ var response;
+
+ if (doc.XMLDocument) {
+ // response is a xml document Internet Explorer property
+ response = doc.XMLDocument;
+ } else if (doc.body){
+ // response is html document or plain text
+ response = doc.body.innerHTML;
+
+ if (settings.responseType && settings.responseType.toLowerCase() == 'json') {
+ // If the document was sent as 'application/javascript' or
+ // 'text/javascript', then the browser wraps the text in a <pre>
+ // tag and performs html encoding on the contents. In this case,
+ // we need to pull the original text content from the text node's
+ // nodeValue property to retrieve the unmangled content.
+ // Note that IE6 only understands text/html
+ if (doc.body.firstChild && doc.body.firstChild.nodeName.toUpperCase() == 'PRE') {
+ response = doc.body.firstChild.firstChild.nodeValue;
+ }
+
+ if (response) {
+ response = eval("(" + response + ")");
+ } else {
+ response = {};
+ }
+ }
+ } else {
+ // response is a xml document
+ response = doc;
+ }
+
+ settings.onComplete.call(self, file, response);
+
+ // Reload blank page, so that reloading main page
+ // does not re-submit the post. Also, remember to
+ // delete the frame
+ toDeleteFlag = true;
+
+ // Fix IE mixed content issue
+ iframe.src = "javascript:'<html></html>';";
+ });
+ },
+ /**
+ * Upload file contained in this._input
+ */
+ submit: function(){
+ var self = this, settings = this._settings;
+
+ if ( ! this._input || this._input.value === ''){
+ return;
+ }
+
+ var file = fileFromPath(this._input.value);
+
+ // user returned false to cancel upload
+ if (false === settings.onSubmit.call(this, file, getExt(file))){
+ this._clearInput();
+ return;
+ }
+
+ // sending request
+ var iframe = this._createIframe();
+ var form = this._createForm(iframe);
+
+ // assuming following structure
+ // div -> input type='file'
+ removeNode(this._input.parentNode);
+ removeClass(self._button, self._settings.hoverClass);
+
+ form.appendChild(this._input);
+
+ form.submit();
+
+ // request set, clean up
+ removeNode(form); form = null;
+ removeNode(this._input); this._input = null;
+
+ // Get response from iframe and fire onComplete event when ready
+ this._getResponse(iframe, file);
+
+ // get ready for next request
+ this._createInput();
+ }
+ };
+})();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/cycle.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,218 @@
+/*
+ * jQuery Cycle Lite Plugin
+ * http://malsup.com/jquery/cycle/lite/
+ * Copyright (c) 2008-2011 M. Alsup
+ * Version: 1.3 (01-JUN-2011)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ * Requires: jQuery v1.3.2 or later
+ */
+;(function($) {
+
+var ver = 'Lite-1.3';
+
+$.fn.cycle = function(options) {
+ return this.each(function() {
+ options = options || {};
+
+ if (this.cycleTimeout) clearTimeout(this.cycleTimeout);
+ this.cycleTimeout = 0;
+ this.cyclePause = 0;
+
+ var $cont = $(this);
+ var $slides = options.slideExpr ? $(options.slideExpr, this) : $cont.children();
+ var els = $slides.get();
+ if (els.length < 2) {
+ window.console && console.log('terminating; too few slides: ' + els.length);
+ return; // don't bother
+ }
+
+ // support metadata plugin (v1.0 and v2.0)
+ var opts = $.extend({}, $.fn.cycle.defaults, options || {}, $.metadata ? $cont.metadata() : $.meta ? $cont.data() : {});
+ var meta = $.isFunction($cont.data) ? $cont.data(opts.metaAttr) : null;
+ if (meta)
+ opts = $.extend(opts, meta);
+
+ opts.before = opts.before ? [opts.before] : [];
+ opts.after = opts.after ? [opts.after] : [];
+ opts.after.unshift(function(){ opts.busy=0; });
+
+ // allow shorthand overrides of width, height and timeout
+ var cls = this.className;
+ opts.width = parseInt((cls.match(/w:(\d+)/)||[])[1]) || opts.width;
+ opts.height = parseInt((cls.match(/h:(\d+)/)||[])[1]) || opts.height;
+ opts.timeout = parseInt((cls.match(/t:(\d+)/)||[])[1]) || opts.timeout;
+
+ if ($cont.css('position') == 'static')
+ $cont.css('position', 'relative');
+ if (opts.width)
+ $cont.width(opts.width);
+ if (opts.height && opts.height != 'auto')
+ $cont.height(opts.height);
+
+ var first = 0;
+ $slides.css({position: 'absolute', top:0, left:0}).each(function(i) {
+ $(this).css('z-index', els.length-i)
+ });
+
+ $(els[first]).css('opacity',1).show(); // opacity bit needed to handle reinit case
+ if ($.browser.msie) els[first].style.removeAttribute('filter');
+
+ if (opts.fit && opts.width)
+ $slides.width(opts.width);
+ if (opts.fit && opts.height && opts.height != 'auto')
+ $slides.height(opts.height);
+ if (opts.pause)
+ $cont.hover(function(){this.cyclePause=1;}, function(){this.cyclePause=0;});
+
+ var txFn = $.fn.cycle.transitions[opts.fx];
+ txFn && txFn($cont, $slides, opts);
+
+ $slides.each(function() {
+ var $el = $(this);
+ this.cycleH = (opts.fit && opts.height) ? opts.height : $el.height();
+ this.cycleW = (opts.fit && opts.width) ? opts.width : $el.width();
+ });
+
+ if (opts.cssFirst)
+ $($slides[first]).css(opts.cssFirst);
+
+ if (opts.timeout) {
+ // ensure that timeout and speed settings are sane
+ if (opts.speed.constructor == String)
+ opts.speed = {slow: 600, fast: 200}[opts.speed] || 400;
+ if (!opts.sync)
+ opts.speed = opts.speed / 2;
+ while((opts.timeout - opts.speed) < 250)
+ opts.timeout += opts.speed;
+ }
+ opts.speedIn = opts.speed;
+ opts.speedOut = opts.speed;
+
+ opts.slideCount = els.length;
+ opts.currSlide = first;
+ opts.nextSlide = 1;
+
+ // fire artificial events
+ var e0 = $slides[first];
+ if (opts.before.length)
+ opts.before[0].apply(e0, [e0, e0, opts, true]);
+ if (opts.after.length > 1)
+ opts.after[1].apply(e0, [e0, e0, opts, true]);
+
+ if (opts.click && !opts.next)
+ opts.next = opts.click;
+ if (opts.next)
+ $(opts.next).bind('click', function(){return advance(els,opts,opts.rev?-1:1)});
+ if (opts.prev)
+ $(opts.prev).bind('click', function(){return advance(els,opts,opts.rev?1:-1)});
+
+ if (opts.timeout)
+ this.cycleTimeout = setTimeout(function() {
+ go(els,opts,0,!opts.rev)
+ }, opts.timeout + (opts.delay||0));
+ });
+};
+
+function go(els, opts, manual, fwd) {
+ if (opts.busy) return;
+ var p = els[0].parentNode, curr = els[opts.currSlide], next = els[opts.nextSlide];
+ if (p.cycleTimeout === 0 && !manual)
+ return;
+
+ if (manual || !p.cyclePause) {
+ if (opts.before.length)
+ $.each(opts.before, function(i,o) { o.apply(next, [curr, next, opts, fwd]); });
+ var after = function() {
+ if ($.browser.msie)
+ this.style.removeAttribute('filter');
+ $.each(opts.after, function(i,o) { o.apply(next, [curr, next, opts, fwd]); });
+ };
+
+ if (opts.nextSlide != opts.currSlide) {
+ opts.busy = 1;
+ $.fn.cycle.custom(curr, next, opts, after);
+ }
+ var roll = (opts.nextSlide + 1) == els.length;
+ opts.nextSlide = roll ? 0 : opts.nextSlide+1;
+ opts.currSlide = roll ? els.length-1 : opts.nextSlide-1;
+ }
+ if (opts.timeout)
+ p.cycleTimeout = setTimeout(function() { go(els,opts,0,!opts.rev) }, opts.timeout);
+};
+
+// advance slide forward or back
+function advance(els, opts, val) {
+ var p = els[0].parentNode, timeout = p.cycleTimeout;
+ if (timeout) {
+ clearTimeout(timeout);
+ p.cycleTimeout = 0;
+ }
+ opts.nextSlide = opts.currSlide + val;
+ if (opts.nextSlide < 0) {
+ opts.nextSlide = els.length - 1;
+ }
+ else if (opts.nextSlide >= els.length) {
+ opts.nextSlide = 0;
+ }
+ go(els, opts, 1, val>=0);
+ return false;
+};
+
+$.fn.cycle.custom = function(curr, next, opts, cb) {
+ var $l = $(curr), $n = $(next);
+ $n.css(opts.cssBefore);
+ var fn = function() {$n.animate(opts.animIn, opts.speedIn, opts.easeIn, cb)};
+ $l.animate(opts.animOut, opts.speedOut, opts.easeOut, function() {
+ $l.css(opts.cssAfter);
+ if (!opts.sync) fn();
+ });
+ if (opts.sync) fn();
+};
+
+$.fn.cycle.transitions = {
+ fade: function($cont, $slides, opts) {
+ $slides.not(':eq(0)').hide();
+ opts.cssBefore = { opacity: 0, display: 'block' };
+ opts.cssAfter = { display: 'none' };
+ opts.animOut = { opacity: 0 };
+ opts.animIn = { opacity: 1 };
+ },
+ fadeout: function($cont, $slides, opts) {
+ opts.before.push(function(curr,next,opts,fwd) {
+ $(curr).css('zIndex',opts.slideCount + (fwd === true ? 1 : 0));
+ $(next).css('zIndex',opts.slideCount + (fwd === true ? 0 : 1));
+ });
+ $slides.not(':eq(0)').hide();
+ opts.cssBefore = { opacity: 1, display: 'block', zIndex: 1 };
+ opts.cssAfter = { display: 'none', zIndex: 0 };
+ opts.animOut = { opacity: 0 };
+ }
+};
+
+$.fn.cycle.ver = function() { return ver; };
+
+// @see: http://malsup.com/jquery/cycle/lite/
+$.fn.cycle.defaults = {
+ animIn: {},
+ animOut: {},
+ fx: 'fade',
+ after: null,
+ before: null,
+ cssBefore: {},
+ cssAfter: {},
+ delay: 0,
+ fit: 0,
+ height: 'auto',
+ metaAttr: 'cycle',
+ next: null,
+ pause: 0,
+ prev: null,
+ speed: 1000,
+ slideExpr: null,
+ sync: 1,
+ timeout: 4000
+};
+
+})(jQuery);
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/general.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,664 @@
+// JavaScript Document
+
+
+$(window).ready(function(){
+
+
+ /*
+
+ // AJAX FILE UPLOADER
+ var button1 = $('#status_upload_file'), interval;
+
+ new AjaxUpload(button1, {
+ onSubmit : function(file , ext){
+
+ if (! (ext && /^(jpg)$/i.test(ext))){
+ // extension is not allowed
+ alert('Error: invalid file extension (only jpg for the moment)');
+ // cancel upload
+ return false;
+ }
+ },
+ action: 'LINKTOFILE.php',
+ name: 'status_file',
+ onSubmit : function(file, ext){
+
+ // Disable the send status button until it is sent
+ $('#status_btn_submit').attr('disabled', 'disabled');
+
+ // change button text, when user selects file
+ button1.text('Uploading');
+
+ // If you want to allow uploading only 1 file at time,
+ // you can disable upload button
+ this.disable();
+
+ // Uploding -> Uploading. -> Uploading...
+ interval = window.setInterval(function(){
+ var text = button1.text();
+ if (text.length < 13){
+ button1.text(text + '.');
+ } else {
+ button1.text('Uploading');
+ }
+ }, 200);
+ },
+ onComplete: function(file, response){
+ button1.text('Uploaded');
+
+ window.clearInterval(interval);
+
+ // enable upload button
+ this.enable();
+
+ //Re enable the button to submit the post
+ $('#status_btn_submit').removeAttr('disabled');
+
+ // add file to the list
+ $('#status_file_name').html(response);
+ $('#status_file_name').fadeIn('fast');
+
+ $('#status_file_temp_name').val(response);
+
+
+
+ }
+ });
+
+ */
+
+});
+
+$(document).ready(function(){
+
+
+
+
+
+ // Column minimizer
+ $('#min_right_column').click(function(){
+
+ $('#right_column').animate({width: 'toggle'});
+
+ if($(this).hasClass('min_right_column_normal')){
+ // for the button
+ $(this).removeClass('min_right_column_normal');
+ $(this).addClass('min_right_column_reverse');
+
+ // for the left column
+ $('#left_column').addClass('left_column_full');
+ $('.text').addClass('text_full');
+ $('.story_right_column').addClass('text_full');
+
+ } else {
+ // for the button
+ $(this).removeClass('min_right_column_reverse');
+ $(this).addClass('min_right_column_normal');
+
+ // for the left column
+ $('#left_column').removeClass('left_column_full');
+ $('.text').removeClass('text_full');
+ $('.story_right_column').removeClass('text_full');
+ }
+ });
+
+
+
+
+
+
+ var searching_results = new Array();
+
+ $("#status_input").autocomplete( searching_results , {
+ multiple: true,
+ multipleSeparator: " ",
+ scroll: true
+ });
+
+ $("#main_search").autocomplete( searching_results , {
+ multiple: true,
+ multipleSeparator: " ",
+ scroll: true
+ });
+
+
+ $('#status_input').focus(function(){
+ if($(this).val() === ''){
+ $(this).animate({
+ height: '70'
+ }, 800, function() {
+ // Animation complete.
+ });
+ }
+ $('#status_options_file').slideToggle('fast');
+ });
+
+ $('#status_input').blur(function(){
+ /*if($(this).val() === ''){
+ $(this).animate({
+ height: '20'
+ }, 800, function() {
+ // Animation complete.
+ });
+ }
+ $('#status_options_file').slideToggle('fast');
+ */
+ });
+
+
+ $('.story_comment_textarea').live('focus',function(){
+ if($(this).val() === ''){
+ $(this).animate({
+ height: '50'
+ }, 800, function() {
+ // Animation complete.
+ });
+ }
+ });
+
+ $('.story_comment_textarea').live('blur',function(){
+ if($(this).val() === ''){
+ $(this).animate({
+ height: '20'
+ }, 800, function() {
+ // Animation complete.
+ });
+ }
+ });
+
+
+ $('.show_comment').live('click',function(){
+ var feed = $(this).attr('title');
+ $('#comment_area_'+feed).slideToggle('fast');
+
+ return false;
+ });
+
+
+ $('#logo').click(function(){
+
+ window.location.href = "";
+
+ return false;
+ });
+
+
+
+
+
+
+
+ $('#form_status').submit(function(){
+
+ $.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: $(this).serialize(),
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ $('#status_input').blur();
+ },
+ success:function(data){
+
+
+
+ if( data.error === false){
+ //Success
+
+ $('#listing').prepend(data.toprint);
+ // Check if it is full screen
+ if( $('#left_column').hasClass('left_column_full') ){
+ $('.text').addClass('text_full');
+ $('.story_right_column').addClass('text_full');
+ }
+
+ $('#status_input').val('');
+ $('#status_file_name').html('');
+ $('#status_file_temp_name').val('');
+
+ $('#status_input').focus();
+
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("Message has not been added");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+ });
+
+ return false
+ });
+
+
+
+
+
+
+ $('.comments_form').submit(function(){
+
+
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: $(this).serialize(),
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+
+
+ if( data.error === false){
+ //Success
+ //$('#update span').html(successMsg);
+ //results = true;
+ $('#comment_field_'+data.id_feed).val('');
+ $('#placing_'+data.id_feed).append(data.toprint);
+
+ $('#comment_field_'+data.id_feed).animate({
+ height: '20'
+ }, 400, function() {
+ // Animation complete.
+ });
+
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("Message has not been added");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+});
+
+ return false
+ });
+
+
+
+ $('.add_network').live('click',function(){
+
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: { 'actions' : 'add_network' , 'new_id_user' : $(this).attr('title') },
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+
+
+ if( data.error === false){
+ //Success
+ //$('#update span').html(successMsg);
+ //results = true;
+ alert('Friend has been added to your network');
+
+
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("Message has not been added");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+});
+
+ return false
+ });
+
+
+ $('.remove_network').live('click',function(){
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: { 'actions' : 'remove_network' , 'new_id_user' : $(this).attr('title') },
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+ if( data.error === false){
+
+ window.location.href = "";
+
+ }
+ if(data.error === true){
+
+ alert("Message has not been added");
+ }
+
+ },
+ error:function(data){
+
+ }
+});
+
+ return false
+ });
+
+
+
+ $('#main_search').focus(function(){
+ var value = $(this).val();
+ var title = 'Search';
+
+ if( value === title ){
+ $(this).val('');
+ }
+
+ });
+
+
+
+ $('#form_register').submit(function(){
+
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: $(this).serialize(),
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+
+
+ if( data.error === false){
+ //Success
+ //$('#update span').html(successMsg);
+ //results = true;
+ window.location.href = "";
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("You have not been registered");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+});
+
+ return false;
+
+ }); // END OF THE LOGIN
+
+
+
+
+ $('#profile_update').submit(function(){
+
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: $(this).serialize(),
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+
+
+ if( data.error === false){
+ //Success
+ //$('#update span').html(successMsg);
+ //results = true;
+ window.location.href = "";
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("You have not been registered");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+});
+
+ return false;
+
+ }); // END OF THE LOGIN
+
+
+
+ $('#profile_update_pwd').submit(function(){
+
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: $(this).serialize(),
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+
+
+ if( data.error === false){
+ //Success
+ $('#field_pwd').val('');
+ $('#field_cpwd').val('');
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("Password has not been changed");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+});
+
+ return false;
+
+ }); // END OF THE LOGIN profile_update_pwd
+
+
+ $('#share_email').submit(function(){
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: $(this).serialize(),
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+ if( data.error === false){
+
+ $('#share_email').fadeOut('fast');
+ $('#share_email_response').fadeIn('fast');
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("There was an error. No email has been sent.");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+});
+
+ return false;
+
+ }); // END OF THE LOGIN
+
+
+
+ $('.todo_status').live('click',function(){
+
+ var value = $(this).is(':checked');
+ if(value === true ){ value = 1; } else { value = 2; }
+
+ var id_feed = $(this).val();
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: { 'actions' : 'update_todo_status' , 'id_feed' : id_feed , 'value' : value },
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+ if( data.error === false){
+ if(value == 1){
+ $('#text_'+id_feed).addClass('strikethrough');
+ }
+ if(value == 2){
+ $('#text_'+id_feed).removeClass('strikethrough');
+ }
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("Update has not been completed");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+});
+
+ }); // END OF THE LOGIN
+
+
+ $('.todo_status_module').live('click',function(){
+
+ var value = $(this).is(':checked');
+ if(value === true ){ value = 1; } else { value = 2; }
+
+ var id_feed = $(this).val();
+ var thing = $(this).parent('li');
+
+$.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: { 'actions' : 'update_todo_status' , 'id_feed' : id_feed , 'value' : value },
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+ if( data.error === false){
+ if(value == 1){
+ $(thing).addClass('strikethrough');
+ }
+ if(value == 2){
+ $(thing).removeClass('strikethrough');
+ }
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("Update has not been completed");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+});
+
+ }); // END OF THE LOGIN
+
+
+ $('.remove_feed').live('click',function(){
+
+ var id_feed = $(this).attr('id');
+
+ var confirm_delete = confirm("Are you sure you want to delete this post?");
+ if(!confirm_delete){ return false; }
+
+ $.ajax({
+ type: 'GET',
+ url: 'LINKTOFILE.php',
+ data: { 'actions' : 'remove_status' , 'id_feed' : id_feed },
+ dataType : 'json',
+ beforeSend:function(){
+ //$('#update span').html(befpreMsg);
+ },
+ success:function(data){
+
+ if( data.error === false){
+
+ $('#story_box_'+id_feed).fadeOut('fast');
+
+ }
+ if(data.error === true){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ alert("Update has not been removed");
+ }
+
+ },
+ error:function(data){
+ //$('#update span').html(errorMsg);
+ //results = false;
+ }
+ });
+
+ return false;
+
+ }); // END OF THE LOGIN
+
+
+});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/changelog.txt Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,27 @@
+1.1
+---
+* Added matchContains: "word" option, match only the start of words instead of everywhere
+* Fixed mustMatch to trigger result event when no match was found
+* Fixed the issue where an autocomplete was applied after the field had focus
+* Extended multiple complete to enable editing words not at the end of the field (doesn't work in Opera)
+
+1.0.2
+-----
+* Fixed missing semicolon
+
+1.0.1
+-----
+* Fixed element creation (<ul> to <ul/> and <li> to </li>)
+* Fixed ac_even class (was ac_event)
+* Fixed bgiframe usage: now its really optional
+* Removed the blur-on-return workaround, added a less obtrusive one only for Opera
+* Fixed hold cursor keys: Opera needs keypress, everyone else keydown to scroll through result list when holding cursor key
+* Updated package to jQuery 1.2.5, removing dimensions
+* Fixed multiple-mustMatch: Remove only the last term when no match is found
+* Fixed multiple without mustMatch: Don't select the last active when no match is found (on tab/return)
+* Fixed multiple cursor position: Put cursor at end of input after selecting a value
+
+1.0
+---
+
+* First release.
\ No newline at end of file
Binary file src/main/resources/people/a_js/jquery-autocomplete/demo/bg.gif has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/emails.php Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,27 @@
+<?php
+$q = strtolower($_GET["q"]);
+if (!$q) return;
+$items = array(
+ "Peter Pan"=>"peter@pan.de",
+ "Molly"=>"molly@yahoo.com",
+ "Forneria Marconi"=>"live@japan.jp",
+ "Master Sync"=>"205bw@samsung.com",
+ "Dr. Tech de Log"=>"g15@logitech.com",
+ "Don Corleone"=>"don@vegas.com",
+ "Mc Chick"=>"info@donalds.org",
+ "Donnie Darko"=>"dd@timeshift.info",
+ "Quake The Net"=>"webmaster@quakenet.org",
+ "Dr. Write"=>"write@writable.com"
+);
+
+$result = array();
+foreach ($items as $key=>$value) {
+ if (strpos(strtolower($key), $q) !== false) {
+ array_push($result, array(
+ "name" => $key,
+ "to" => $value
+ ));
+ }
+}
+echo json_encode($result);
+?>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/emails.phps Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,27 @@
+<?php
+$q = strtolower($_GET["q"]);
+if (!$q) return;
+$items = array(
+ "Peter Pan"=>"peter@pan.de",
+ "Molly"=>"molly@yahoo.com",
+ "Forneria Marconi"=>"live@japan.jp",
+ "Master Sync"=>"205bw@samsung.com",
+ "Dr. Tech de Log"=>"g15@logitech.com",
+ "Don Corleone"=>"don@vegas.com",
+ "Mc Chick"=>"info@donalds.org",
+ "Donnie Darko"=>"dd@timeshift.info",
+ "Quake The Net"=>"webmaster@quakenet.org",
+ "Dr. Write"=>"write@writable.com"
+);
+
+$result = array();
+foreach ($items as $key=>$value) {
+ if (strpos(strtolower($key), $q) !== false) {
+ array_push($result, array(
+ "name" => $key,
+ "to" => $value
+ ));
+ }
+}
+echo json_encode($result);
+?>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/images.php Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,9 @@
+<?php
+$term = $_REQUEST['q'];
+$images = array_slice(scandir("images"), 2);
+foreach($images as $value) {
+ if( strpos(strtolower($value), $term) === 0 ) {
+ echo $value . "\n";
+ }
+}
+?>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/index.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,272 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+
+<title>jQuery Autocomplete Plugin</title>
+<script type="text/javascript" src="../lib/jquery.js"></script>
+<script type='text/javascript' src='../lib/jquery.bgiframe.min.js'></script>
+<script type='text/javascript' src='../lib/jquery.ajaxQueue.js'></script>
+<script type='text/javascript' src='../lib/thickbox-compressed.js'></script>
+<script type='text/javascript' src='../jquery.autocomplete.js'></script>
+<script type='text/javascript' src='localdata.js'></script>
+<link rel="stylesheet" type="text/css" href="main.css" />
+<link rel="stylesheet" type="text/css" href="../jquery.autocomplete.css" />
+<link rel="stylesheet" type="text/css" href="../lib/thickbox.css" />
+
+<script type="text/javascript">
+$().ready(function() {
+
+ function log(event, data, formatted) {
+ $("<li>").html( !data ? "No match!" : "Selected: " + formatted).appendTo("#result");
+ }
+
+ function formatItem(row) {
+ return row[0] + " (<strong>id: " + row[1] + "</strong>)";
+ }
+ function formatResult(row) {
+ return row[0].replace(/(<.+?>)/gi, '');
+ }
+
+ $("#suggest1").focus().autocomplete(cities);
+ $("#month").autocomplete(months, {
+ minChars: 0,
+ max: 12,
+ autoFill: true,
+ mustMatch: true,
+ matchContains: false,
+ scrollHeight: 220,
+ formatItem: function(data, i, total) {
+ // don't show the current month in the list of values (for whatever reason)
+ if ( data[0] == months[new Date().getMonth()] )
+ return false;
+ return data[0];
+ }
+ });
+ $("#suggest13").autocomplete(emails, {
+ minChars: 0,
+ width: 310,
+ matchContains: "word",
+ autoFill: false,
+ formatItem: function(row, i, max) {
+ return i + "/" + max + ": \"" + row.name + "\" [" + row.to + "]";
+ },
+ formatMatch: function(row, i, max) {
+ return row.name + " " + row.to;
+ },
+ formatResult: function(row) {
+ return row.to;
+ }
+ });
+ $("#singleBirdRemote").autocomplete("search.php", {
+ width: 260,
+ selectFirst: false
+ });
+ $("#suggest14").autocomplete(cities, {
+ matchContains: true,
+ minChars: 0
+ });
+ $("#suggest3").autocomplete(cities, {
+ multiple: true,
+ mustMatch: true,
+ autoFill: true
+ });
+ $("#suggest4").autocomplete('search.php', {
+ width: 300,
+ multiple: true,
+ matchContains: true,
+ formatItem: formatItem,
+ formatResult: formatResult
+ });
+ $("#imageSearch").autocomplete("images.php", {
+ width: 320,
+ max: 4,
+ highlight: false,
+ scroll: true,
+ scrollHeight: 300,
+ formatItem: function(data, i, n, value) {
+ return "<img src='images/" + value + "'/> " + value.split(".")[0];
+ },
+ formatResult: function(data, value) {
+ return value.split(".")[0];
+ }
+ });
+ $("#tags").autocomplete(["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "pearl"], {
+ width: 320,
+ max: 4,
+ highlight: false,
+ multiple: true,
+ multipleSeparator: " ",
+ scroll: true,
+ scrollHeight: 300
+ });
+
+
+ $(":text, textarea").result(log).next().click(function() {
+ $(this).prev().search();
+ });
+ $("#singleBirdRemote").result(function(event, data, formatted) {
+ if (data)
+ $(this).parent().next().find("input").val(data[1]);
+ });
+ $("#suggest4").result(function(event, data, formatted) {
+ var hidden = $(this).parent().next().find(">:input");
+ hidden.val( (hidden.val() ? hidden.val() + ";" : hidden.val()) + data[1]);
+ });
+ $("#suggest15").autocomplete(cities, { scroll: true } );
+ $("#scrollChange").click(changeScrollHeight);
+
+ $("#thickboxEmail").autocomplete(emails, {
+ minChars: 0,
+ width: 310,
+ matchContains: true,
+ highlightItem: false,
+ formatItem: function(row, i, max, term) {
+ return row.name.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + "<br><span style='font-size: 80%;'>Email: <" + row.to + "></span>";
+ },
+ formatResult: function(row) {
+ return row.to;
+ }
+ });
+
+ $("#clear").click(function() {
+ $(":input").unautocomplete();
+ });
+});
+
+function changeOptions(){
+ var max = parseInt(window.prompt('Please type number of items to display:', jQuery.Autocompleter.defaults.max));
+ if (max > 0) {
+ $("#suggest1").setOptions({
+ max: max
+ });
+ }
+}
+
+function changeScrollHeight() {
+ var h = parseInt(window.prompt('Please type new scroll height (number in pixels):', jQuery.Autocompleter.defaults.scrollHeight));
+ if(h > 0) {
+ $("#suggest1").setOptions({
+ scrollHeight: h
+ });
+ }
+}
+
+function changeToMonths(){
+ $("#suggest1")
+ // clear existing data
+ .val("")
+ // change the local data to months
+ .setOptions({data: months})
+ // get the label tag
+ .prev()
+ // update the label tag
+ .text("Month (local):");
+}
+</script>
+
+</head>
+
+<body>
+
+<h1 id="banner"><a href="http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/">jQuery Autocomplete Plugin</a> Demo</h1>
+
+<div id="content">
+
+ <form autocomplete="off">
+ <p>
+ <label>Single City (local):</label>
+ <input type="text" id="suggest1" />
+ <input type="button" value="Get Value" />
+ <input type="button" value="Change Max Items" onclick="changeOptions();" />
+ <input type="button" value="Change to Month Data" onclick="changeToMonths();" />
+ <input type="button" value="Change scroll height" id="scrollChange" />
+ </p>
+ <p>
+ <label>Month (local):</label>
+ <input type="text" id="month" />
+ <input type="button" value="Get Value" />
+ (Current month is excluded from list)
+ </p>
+ <p>
+ <label>E-Mail (local):</label>
+ <input type="text" id="suggest13" />
+ <input type="button" value="Get Value" />
+ </p>
+ <p>
+ <label>Single Bird (remote):</label>
+ <input type="text" id="singleBirdRemote" />
+ <input type="button" value="Get Value" />
+ </p>
+ <p>
+ <label>Hidden input</label>
+ <input />
+ </p>
+ <p>
+ <label>Single City (contains):</label>
+ <input type="text" id="suggest14" />
+ <input type="button" value="Get Value" />
+ </p>
+ <p>
+ <label>Multiple Cities (local):</label>
+ <textarea id='suggest3' cols='40' rows='3'></textarea>
+ <input type="button" value="Get Value" />
+ </p>
+ <p>
+ <label>Multiple Birds (remote):</label>
+ <textarea id='suggest4'></textarea>
+ <input type="button" value="Get Value" />
+ </p>
+ <p>
+ <label>Hidden input</label>
+ <textarea></textarea>
+ </p>
+ <p>
+ <label>Image search (remote):</label>
+ <input type="text" id='imageSearch' />
+ <input type="button" value="Get Value" />
+ </p>
+ <p>
+ <label>Tags (local):</label>
+ <input type="text" id='tags' />
+ <input type="button" value="Get Value" />
+ </p>
+ <p>
+ <label>Some dropdown (<3 IE):</label>
+ <select>
+ <option value="">Item 12334455</option>
+ <option value="2">Item 2</option>
+ <option value="3">Item 3</option>
+ <option value="4">Item 4</option>
+ </select>
+ </p>
+
+ <input type="submit" value="Submit" />
+ </form>
+
+ <p>
+ <a href="#TB_inline?height=155&width=400&inlineId=modalWindow" class="thickbox">Click here for an autocomplete inside a thickbox window.</a> (this should work even if it is beyond the fold)
+ </p>
+
+ <div id="modalWindow" style="display: none;">
+ <p>
+ <label>E-Mail (local):</label>
+ <input type="text" id="thickboxEmail" />
+ <input type="button" value="Get Value" />
+ </p>
+ </div>
+
+ <button id="clear">Remove all autocompletes</button>
+
+ <a href="search.phps">PHP script used to for remote autocomplete</a>
+
+ <h3>Result:</h3> <ol id="result"></ol>
+
+</div>
+<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+_uacct = "UA-2623402-1";
+urchinTracker();
+</script>
+</body>
+</html>
Binary file src/main/resources/people/a_js/jquery-autocomplete/demo/indicator.gif has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/json.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+
+<title>jQuery Autocomplete Plugin</title>
+<script type="text/javascript" src="../lib/jquery.js"></script>
+<script type='text/javascript' src='../lib/jquery.bgiframe.min.js'></script>
+<script type='text/javascript' src='../lib/jquery.ajaxQueue.js'></script>
+<script type='text/javascript' src='../lib/thickbox-compressed.js'></script>
+<script type='text/javascript' src='../jquery.autocomplete.js'></script>
+<script type='text/javascript' src='localdata.js'></script>
+<link rel="stylesheet" type="text/css" href="main.css" />
+<link rel="stylesheet" type="text/css" href="../jquery.autocomplete.css" />
+<link rel="stylesheet" type="text/css" href="../lib/thickbox.css" />
+
+<script type="text/javascript">
+$(function() {
+ function format(mail) {
+ return mail.name + " <" + mail.to + ">";
+ }
+ $("#email").autocomplete('emails.php', {
+ multiple: true,
+ dataType: "json",
+ parse: function(data) {
+ return $.map(data, function(row) {
+ return {
+ data: row,
+ value: row.name,
+ result: row.name + " <" + row.to + ">"
+ }
+ });
+ },
+ formatItem: function(item) {
+ return format(item);
+ }
+ }).result(function(e, item) {
+ $("#content").append("<p>selected " + format(item) + "</p>");
+ });
+});
+</script>
+
+</head>
+
+<body>
+
+<h1 id="banner"><a href="http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/">jQuery Autocomplete Plugin</a> Demo</h1>
+
+<div id="content">
+
+ <form autocomplete="off">
+ <p>
+ <label>E-Mail (remote json):</label>
+ <textarea cols="120" id="email"></textarea>
+ </p>
+
+ <input type="submit" value="Submit" />
+ </form>
+
+ <a href="emails.phps">Server-side script creating the JSON data</a>
+
+</div>
+<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+_uacct = "UA-2623402-1";
+urchinTracker();
+</script>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/localdata.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,216 @@
+var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
+var emails = [
+ { name: "Peter Pan", to: "peter@pan.de" },
+ { name: "Molly", to: "molly@yahoo.com" },
+ { name: "Forneria Marconi", to: "live@japan.jp" },
+ { name: "Master <em>Sync</em>", to: "205bw@samsung.com" },
+ { name: "Dr. <strong>Tech</strong> de Log", to: "g15@logitech.com" },
+ { name: "Don Corleone", to: "don@vegas.com" },
+ { name: "Mc Chick", to: "info@donalds.org" },
+ { name: "Donnie Darko", to: "dd@timeshift.info" },
+ { name: "Quake The Net", to: "webmaster@quakenet.org" },
+ { name: "Dr. Write", to: "write@writable.com" }
+];
+var cities = [
+ "Aberdeen", "Ada", "Adamsville", "Addyston", "Adelphi", "Adena", "Adrian", "Akron",
+ "Albany", "Alexandria", "Alger", "Alledonia", "Alliance", "Alpha", "Alvada",
+ "Alvordton", "Amanda", "Amelia", "Amesville", "Amherst", "Amlin", "Amsden",
+ "Amsterdam", "Andover", "Anna", "Ansonia", "Antwerp", "Apple Creek", "Arcadia",
+ "Arcanum", "Archbold", "Arlington", "Ashland", "Ashley", "Ashtabula", "Ashville",
+ "Athens", "Attica", "Atwater", "Augusta", "Aurora", "Austinburg", "Ava", "Avon",
+ "Avon Lake", "Bainbridge", "Bakersville", "Baltic", "Baltimore", "Bannock",
+ "Barberton", "Barlow", "Barnesville", "Bartlett", "Barton", "Bascom", "Batavia",
+ "Bath", "Bay Village", "Beach City", "Beachwood", "Beallsville", "Beaver",
+ "Beaverdam", "Bedford", "Bellaire", "Bellbrook", "Belle Center", "Belle Valley",
+ "Bellefontaine", "Bellevue", "Bellville", "Belmont", "Belmore", "Beloit", "Belpre",
+ "Benton Ridge", "Bentonville", "Berea", "Bergholz", "Berkey", "Berlin",
+ "Berlin Center", "Berlin Heights", "Bethel", "Bethesda", "Bettsville", "Beverly",
+ "Bidwell", "Big Prairie", "Birmingham", "Blacklick", "Bladensburg", "Blaine",
+ "Blakeslee", "Blanchester", "Blissfield", "Bloomdale", "Bloomingburg",
+ "Bloomingdale", "Bloomville", "Blue Creek", "Blue Rock", "Bluffton",
+ "Bolivar", "Botkins", "Bourneville", "Bowerston", "Bowersville",
+ "Bowling Green", "Bradford", "Bradner", "Brady Lake", "Brecksville",
+ "Bremen", "Brewster", "Brice", "Bridgeport", "Brilliant", "Brinkhaven",
+ "Bristolville", "Broadview Heights", "Broadway", "Brookfield", "Brookpark",
+ "Brookville", "Brownsville", "Brunswick", "Bryan", "Buchtel", "Buckeye Lake",
+ "Buckland", "Bucyrus", "Buffalo", "Buford", "Burbank", "Burghill", "Burgoon",
+ "Burkettsville", "Burton", "Butler", "Byesville", "Cable", "Cadiz", "Cairo",
+ "Caldwell", "Caledonia", "Cambridge", "Camden", "Cameron", "Camp Dennison",
+ "Campbell", "Canal Fulton", "Canal Winchester", "Canfield", "Canton", "Carbon Hill",
+ "Carbondale", "Cardington", "Carey", "Carroll", "Carrollton", "Casstown",
+ "Castalia", "Catawba", "Cecil", "Cedarville", "Celina", "Centerburg",
+ "Chagrin Falls", "Chandlersville", "Chardon", "Charm", "Chatfield", "Chauncey",
+ "Cherry Fork", "Chesapeake", "Cheshire", "Chester", "Chesterhill", "Chesterland",
+ "Chesterville", "Chickasaw", "Chillicothe", "Chilo", "Chippewa Lake",
+ "Christiansburg", "Cincinnati", "Circleville", "Clarington", "Clarksburg",
+ "Clarksville", "Clay Center", "Clayton", "Cleveland", "Cleves", "Clifton",
+ "Clinton", "Cloverdale", "Clyde", "Coal Run", "Coalton", "Coldwater", "Colerain",
+ "College Corner", "Collins", "Collinsville", "Colton", "Columbia Station",
+ "Columbiana", "Columbus", "Columbus Grove", "Commercial Point", "Conesville",
+ "Conneaut", "Conover", "Continental", "Convoy", "Coolville", "Corning", "Cortland",
+ "Coshocton", "Covington", "Creola", "Crestline", "Creston", "Crooksville",
+ "Croton", "Crown City", "Cuba", "Cumberland", "Curtice", "Custar", "Cutler",
+ "Cuyahoga Falls", "Cygnet", "Cynthiana", "Dalton", "Damascus", "Danville",
+ "Dayton", "De Graff", "Decatur", "Deerfield", "Deersville", "Defiance",
+ "Delaware", "Dellroy", "Delphos", "Delta", "Dennison", "Derby", "Derwent",
+ "Deshler", "Dexter City", "Diamond", "Dillonvale", "Dola", "Donnelsville",
+ "Dorset", "Dover", "Doylestown", "Dresden", "Dublin", "Dunbridge", "Duncan Falls",
+ "Dundee", "Dunkirk", "Dupont", "East Claridon", "East Fultonham",
+ "East Liberty", "East Liverpool", "East Palestine", "East Rochester",
+ "East Sparta", "East Springfield", "Eastlake", "Eaton", "Edgerton", "Edison",
+ "Edon", "Eldorado", "Elgin", "Elkton", "Ellsworth", "Elmore", "Elyria",
+ "Empire", "Englewood", "Enon", "Etna", "Euclid", "Evansport", "Fairborn",
+ "Fairfield", "Fairpoint", "Fairview", "Farmdale", "Farmer", "Farmersville",
+ "Fayette", "Fayetteville", "Feesburg", "Felicity", "Findlay", "Flat Rock",
+ "Fleming", "Fletcher", "Flushing", "Forest", "Fort Jennings", "Fort Loramie",
+ "Fort Recovery", "Fostoria", "Fowler", "Frankfort", "Franklin",
+ "Franklin Furnace", "Frazeysburg", "Fredericksburg", "Fredericktown",
+ "Freeport", "Fremont", "Fresno", "Friendship", "Fulton", "Fultonham",
+ "Galena", "Galion", "Gallipolis", "Galloway", "Gambier", "Garrettsville",
+ "Gates Mills", "Geneva", "Genoa", "Georgetown", "Germantown", "Gettysburg",
+ "Gibsonburg", "Girard", "Glandorf", "Glencoe", "Glenford", "Glenmont",
+ "Glouster", "Gnadenhutten", "Gomer", "Goshen", "Grafton", "Grand Rapids",
+ "Grand River", "Granville", "Gratiot", "Gratis", "Graysville", "Graytown",
+ "Green", "Green Camp", "Green Springs", "Greenfield", "Greenford",
+ "Greentown", "Greenville", "Greenwich", "Grelton", "Grove City",
+ "Groveport", "Grover Hill", "Guysville", "Gypsum", "Hallsville",
+ "Hamden", "Hamersville", "Hamilton", "Hamler", "Hammondsville",
+ "Hannibal", "Hanoverton", "Harbor View", "Harlem Springs", "Harpster",
+ "Harrisburg", "Harrison", "Harrisville", "Harrod", "Hartford", "Hartville",
+ "Harveysburg", "Haskins", "Haverhill", "Haviland", "Haydenville", "Hayesville",
+ "Heath", "Hebron", "Helena", "Hicksville", "Higginsport", "Highland", "Hilliard",
+ "Hillsboro", "Hinckley", "Hiram", "Hockingport", "Holgate", "Holland",
+ "Hollansburg", "Holloway", "Holmesville", "Homer", "Homerville", "Homeworth",
+ "Hooven", "Hopedale", "Hopewell", "Houston", "Howard", "Hoytville", "Hubbard",
+ "Hudson", "Huntsburg", "Huntsville", "Huron", "Iberia", "Independence",
+ "Irondale", "Ironton", "Irwin", "Isle Saint George", "Jackson", "Jackson Center",
+ "Jacksontown", "Jacksonville", "Jacobsburg", "Jamestown", "Jasper",
+ "Jefferson", "Jeffersonville", "Jenera", "Jeromesville", "Jerry City",
+ "Jerusalem", "Jewell", "Jewett", "Johnstown", "Junction City", "Kalida",
+ "Kansas", "Keene", "Kelleys Island", "Kensington", "Kent", "Kenton",
+ "Kerr", "Kettlersville", "Kidron", "Kilbourne", "Killbuck", "Kimbolton",
+ "Kings Mills", "Kingston", "Kingsville", "Kinsman", "Kipling", "Kipton",
+ "Kirby", "Kirkersville", "Kitts Hill", "Kunkle", "La Rue", "Lacarne",
+ "Lafayette", "Lafferty", "Lagrange", "Laings", "Lake Milton", "Lakemore",
+ "Lakeside Marblehead", "Lakeview", "Lakeville", "Lakewood", "Lancaster",
+ "Langsville", "Lansing", "Latham", "Latty", "Laura", "Laurelville",
+ "Leavittsburg", "Lebanon", "Lees Creek", "Leesburg", "Leesville",
+ "Leetonia", "Leipsic", "Lemoyne", "Lewis Center", "Lewisburg",
+ "Lewistown", "Lewisville", "Liberty Center", "Lima", "Limaville",
+ "Lindsey", "Lisbon", "Litchfield", "Lithopolis", "Little Hocking",
+ "Lockbourne", "Lodi", "Logan", "London", "Londonderry",
+ "Long Bottom", "Lorain", "Lore City", "Loudonville", "Louisville",
+ "Loveland", "Lowell", "Lowellville", "Lower Salem", "Lucas",
+ "Lucasville", "Luckey", "Ludlow Falls", "Lynchburg", "Lynx",
+ "Lyons", "Macedonia", "Macksburg", "Madison", "Magnetic Springs",
+ "Magnolia", "Maineville", "Malaga", "Malinta", "Malta", "Malvern",
+ "Manchester", "Mansfield", "Mantua", "Maple Heights", "Maplewood",
+ "Marathon", "Marengo", "Maria Stein", "Marietta", "Marion",
+ "Mark Center", "Marshallville", "Martel", "Martin", "Martins Ferry",
+ "Martinsburg", "Martinsville", "Marysville", "Mason", "Massillon",
+ "Masury", "Maumee", "Maximo", "Maynard", "Mc Arthur", "Mc Clure",
+ "Mc Comb", "Mc Connelsville", "Mc Cutchenville", "Mc Dermott",
+ "Mc Donald", "Mc Guffey", "Mechanicsburg", "Mechanicstown",
+ "Medina", "Medway", "Melmore", "Melrose", "Mendon", "Mentor",
+ "Mesopotamia", "Metamora", "Miamisburg", "Miamitown", "Miamiville",
+ "Middle Bass", "Middle Point", "Middlebranch", "Middleburg",
+ "Middlefield", "Middleport", "Middletown", "Midland", "Midvale",
+ "Milan", "Milford", "Milford Center", "Millbury", "Milledgeville",
+ "Miller City", "Millersburg", "Millersport", "Millfield",
+ "Milton Center", "Mineral City", "Mineral Ridge", "Minerva",
+ "Minford", "Mingo", "Mingo Junction", "Minster", "Mogadore",
+ "Monclova", "Monroe", "Monroeville", "Montezuma", "Montpelier",
+ "Montville", "Morral", "Morristown", "Morrow", "Moscow",
+ "Mount Blanchard", "Mount Cory", "Mount Eaton", "Mount Gilead",
+ "Mount Hope", "Mount Liberty", "Mount Orab", "Mount Perry",
+ "Mount Pleasant", "Mount Saint Joseph", "Mount Sterling",
+ "Mount Vernon", "Mount Victory", "Mowrystown", "Moxahala",
+ "Munroe Falls", "Murray City", "Nankin", "Napoleon", "Nashport",
+ "Nashville", "Navarre", "Neapolis", "Neffs", "Negley",
+ "Nelsonville", "Nevada", "Neville", "New Albany", "New Athens",
+ "New Bavaria", "New Bloomington", "New Bremen", "New Carlisle",
+ "New Concord", "New Hampshire", "New Haven", "New Holland",
+ "New Knoxville", "New Lebanon", "New Lexington", "New London",
+ "New Madison", "New Marshfield", "New Matamoras", "New Middletown",
+ "New Paris", "New Philadelphia", "New Plymouth", "New Richmond",
+ "New Riegel", "New Rumley", "New Springfield", "New Straitsville",
+ "New Vienna", "New Washington", "New Waterford", "New Weston",
+ "Newark", "Newbury", "Newcomerstown", "Newport", "Newton Falls",
+ "Newtonsville", "Ney", "Niles", "North Baltimore", "North Bend",
+ "North Benton", "North Bloomfield", "North Fairfield",
+ "North Georgetown", "North Hampton", "North Jackson",
+ "North Kingsville", "North Lawrence", "North Lewisburg",
+ "North Lima", "North Olmsted", "North Ridgeville", "North Robinson",
+ "North Royalton", "North Star", "Northfield", "Northwood", "Norwalk",
+ "Norwich", "Nova", "Novelty", "Oak Harbor", "Oak Hill", "Oakwood",
+ "Oberlin", "Oceola", "Ohio City", "Okeana", "Okolona", "Old Fort",
+ "Old Washington", "Olmsted Falls", "Ontario", "Orangeville",
+ "Oregon", "Oregonia", "Orient", "Orrville", "Orwell", "Osgood",
+ "Ostrander", "Ottawa", "Ottoville", "Otway", "Overpeck",
+ "Owensville", "Oxford", "Painesville", "Palestine", "Pandora",
+ "Paris", "Parkman", "Pataskala", "Patriot", "Paulding", "Payne",
+ "Pedro", "Peebles", "Pemberton", "Pemberville", "Peninsula",
+ "Perry", "Perrysburg", "Perrysville", "Petersburg", "Pettisville",
+ "Phillipsburg", "Philo", "Pickerington", "Piedmont", "Pierpont",
+ "Piketon", "Piney Fork", "Pioneer", "Piqua", "Pitsburg",
+ "Plain City", "Plainfield", "Pleasant City", "Pleasant Hill",
+ "Pleasant Plain", "Pleasantville", "Plymouth", "Polk",
+ "Pomeroy", "Port Clinton", "Port Jefferson", "Port Washington",
+ "Port William", "Portage", "Portland", "Portsmouth", "Potsdam",
+ "Powell", "Powhatan Point", "Proctorville", "Prospect", "Put in Bay",
+ "Quaker City", "Quincy", "Racine", "Radnor", "Randolph", "Rarden",
+ "Ravenna", "Rawson", "Ray", "Rayland", "Raymond", "Reedsville",
+ "Reesville", "Reno", "Republic", "Reynoldsburg", "Richfield",
+ "Richmond", "Richmond Dale", "Richwood", "Ridgeville Corners",
+ "Ridgeway", "Rio Grande", "Ripley", "Risingsun", "Rittman",
+ "Robertsville", "Rock Camp", "Rock Creek", "Rockbridge", "Rockford",
+ "Rocky Ridge", "Rocky River", "Rogers", "Rome", "Rootstown", "Roseville",
+ "Rosewood", "Ross", "Rossburg", "Rossford", "Roundhead", "Rudolph",
+ "Rushsylvania", "Rushville", "Russells Point", "Russellville", "Russia",
+ "Rutland", "Sabina", "Saint Clairsville", "Saint Henry", "Saint Johns",
+ "Saint Louisville", "Saint Marys", "Saint Paris", "Salem", "Salesville",
+ "Salineville", "Sandusky", "Sandyville", "Sarahsville", "Sardinia",
+ "Sardis", "Savannah", "Scio", "Scioto Furnace", "Scott", "Scottown",
+ "Seaman", "Sebring", "Sedalia", "Senecaville", "Seven Mile", "Seville",
+ "Shade", "Shadyside", "Shandon", "Sharon Center", "Sharpsburg",
+ "Shauck", "Shawnee", "Sheffield Lake", "Shelby", "Sherrodsville",
+ "Sherwood", "Shiloh", "Short Creek", "Shreve", "Sidney", "Sinking Spring",
+ "Smithfield", "Smithville", "Solon", "Somerdale", "Somerset",
+ "Somerville", "South Bloomingville", "South Charleston", "South Lebanon",
+ "South Point", "South Salem", "South Solon", "South Vienna",
+ "South Webster", "Southington", "Sparta", "Spencer", "Spencerville",
+ "Spring Valley", "Springboro", "Springfield", "Stafford", "Sterling",
+ "Steubenville", "Stewart", "Stillwater", "Stockdale", "Stockport",
+ "Stone Creek", "Stony Ridge", "Stout", "Stoutsville", "Stow", "Strasburg",
+ "Stratton", "Streetsboro", "Strongsville", "Struthers", "Stryker",
+ "Sugar Grove", "Sugarcreek", "Sullivan", "Sulphur Springs", "Summerfield",
+ "Summit Station", "Summitville", "Sunbury", "Swanton", "Sycamore",
+ "Sycamore Valley", "Sylvania", "Syracuse", "Tallmadge", "Tarlton",
+ "Terrace Park", "The Plains", "Thompson", "Thornville", "Thurman",
+ "Thurston", "Tiffin", "Tiltonsville", "Tipp City", "Tippecanoe", "Tiro",
+ "Toledo", "Tontogany", "Torch", "Toronto", "Tremont City", "Trenton",
+ "Trimble", "Trinway", "Troy", "Tuppers Plains", "Tuscarawas", "Twinsburg",
+ "Uhrichsville", "Union City", "Union Furnace", "Unionport", "Uniontown",
+ "Unionville", "Unionville Center", "Uniopolis", "Upper Sandusky", "Urbana",
+ "Utica", "Valley City", "Van Buren", "Van Wert", "Vandalia", "Vanlue",
+ "Vaughnsville", "Venedocia", "Vermilion", "Verona", "Versailles",
+ "Vickery", "Vienna", "Vincent", "Vinton", "Wadsworth", "Wakefield",
+ "Wakeman", "Walbridge", "Waldo", "Walhonding", "Walnut Creek", "Wapakoneta",
+ "Warnock", "Warren", "Warsaw", "Washington Court House",
+ "Washingtonville", "Waterford", "Waterloo", "Watertown", "Waterville",
+ "Wauseon", "Waverly", "Wayland", "Wayne", "Waynesburg", "Waynesfield",
+ "Waynesville", "Wellington", "Wellston", "Wellsville", "West Alexandria",
+ "West Chester", "West Elkton", "West Farmington", "West Jefferson",
+ "West Lafayette", "West Liberty", "West Manchester", "West Mansfield",
+ "West Millgrove", "West Milton", "West Point", "West Portsmouth",
+ "West Rushville", "West Salem", "West Union", "West Unity", "Westerville",
+ "Westfield Center", "Westlake", "Weston", "Westville", "Wharton",
+ "Wheelersburg", "Whipple", "White Cottage", "Whitehouse", "Wickliffe",
+ "Wilberforce", "Wilkesville", "Willard", "Williamsburg", "Williamsfield",
+ "Williamsport", "Williamstown", "Williston", "Willoughby", "Willow Wood",
+ "Willshire", "Wilmington", "Wilmot", "Winchester", "Windham", "Windsor",
+ "Winesburg", "Wingett Run", "Winona", "Wolf Run", "Woodsfield",
+ "Woodstock", "Woodville", "Wooster", "Wren", "Xenia", "Yellow Springs",
+ "Yorkshire", "Yorkville", "Youngstown", "Zaleski", "Zanesfield", "Zanesville",
+ "Zoar"
+];
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/main.css Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,53 @@
+body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0}
+table{border-collapse:collapse;border-spacing:0}
+fieldset,img{border:0}
+address,caption,cite,code,dfn,th,var{font-style:normal;font-weight:normal}
+ol,ul{list-style:none}
+caption,th{text-align:left}
+h1,h2,h3,h4,h5,h6{font-size:100%;font-style:normal;font-weight:normal}
+q:before,q:after{content:''}
+body{font:13px arial,helvetica,clean,sans-serif;font-size:small;}
+select,input,textarea{font:99% arial,helvetica,clean,sans-serif}
+pre,code{font:115% monospace;font-size:100%}
+body * {line-height:1.22em}
+body {
+ color: #202020;
+}
+
+h1 {
+ color: #fff;
+ background: #06b;
+ padding: 10px;
+ font-size: 200%;
+}
+
+h2 {
+ color: #000;
+ font-size: 150%;
+ padding: 10px 0;
+}
+
+h3 {
+ color: #000;
+ font-size: 120%;
+ padding: 10px 0;
+}
+
+ul {
+ list-style: disc inside;
+ margin-left: 1em;
+}
+
+#content {
+ padding: 10px;
+}
+
+label {
+ float: left;
+ width: 12em;
+}
+input[type=text] { width: 15em; }
+
+#banner { padding: 15px; background-color: #06b; color: white; font-size: large; border-bottom: 1px solid #ccc;
+ background: url(bg.gif) repeat-x; text-align: center }
+#banner a { color: white; }
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/search.php Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,578 @@
+<?php
+
+$q = strtolower($_GET["q"]);
+if (!$q) return;
+$items = array(
+"Great <em>Bittern</em>"=>"Botaurus stellaris",
+"Little <em>Grebe</em>"=>"Tachybaptus ruficollis",
+"Black-necked Grebe"=>"Podiceps nigricollis",
+"Little Bittern"=>"Ixobrychus minutus",
+"Black-crowned Night Heron"=>"Nycticorax nycticorax",
+"Purple Heron"=>"Ardea purpurea",
+"White Stork"=>"Ciconia ciconia",
+"Spoonbill"=>"Platalea leucorodia",
+"Red-crested Pochard"=>"Netta rufina",
+"Common Eider"=>"Somateria mollissima",
+"Red Kite"=>"Milvus milvus",
+"Hen Harrier"=>"Circus cyaneus",
+"Montagu`s Harrier"=>"Circus pygargus",
+"Black Grouse"=>"Tetrao tetrix",
+"Grey Partridge"=>"Perdix perdix",
+"Spotted Crake"=>"Porzana porzana",
+"Corncrake"=>"Crex crex",
+"Common Crane"=>"Grus grus",
+"Avocet"=>"Recurvirostra avosetta",
+"Stone Curlew"=>"Burhinus oedicnemus",
+"Common Ringed Plover"=>"Charadrius hiaticula",
+"Kentish Plover"=>"Charadrius alexandrinus",
+"Ruff"=>"Philomachus pugnax",
+"Common Snipe"=>"Gallinago gallinago",
+"Black-tailed Godwit"=>"Limosa limosa",
+"Common Redshank"=>"Tringa totanus",
+"Sandwich Tern"=>"Sterna sandvicensis",
+"Common Tern"=>"Sterna hirundo",
+"Arctic Tern"=>"Sterna paradisaea",
+"Little Tern"=>"Sternula albifrons",
+"Black Tern"=>"Chlidonias niger",
+"Barn Owl"=>"Tyto alba",
+"Little Owl"=>"Athene noctua",
+"Short-eared Owl"=>"Asio flammeus",
+"European Nightjar"=>"Caprimulgus europaeus",
+"Common Kingfisher"=>"Alcedo atthis",
+"Eurasian Hoopoe"=>"Upupa epops",
+"Eurasian Wryneck"=>"Jynx torquilla",
+"European Green Woodpecker"=>"Picus viridis",
+"Crested Lark"=>"Galerida cristata",
+"White-headed Duck"=>"Oxyura leucocephala",
+"Pale-bellied Brent Goose"=>"Branta hrota",
+"Tawny Pipit"=>"Anthus campestris",
+"Whinchat"=>"Saxicola rubetra",
+"European Stonechat"=>"Saxicola rubicola",
+"Northern Wheatear"=>"Oenanthe oenanthe",
+"Savi`s Warbler"=>"Locustella luscinioides",
+"Sedge Warbler"=>"Acrocephalus schoenobaenus",
+"Great Reed Warbler"=>"Acrocephalus arundinaceus",
+"Bearded Reedling"=>"Panurus biarmicus",
+"Red-backed Shrike"=>"Lanius collurio",
+"Great Grey Shrike"=>"Lanius excubitor",
+"Woodchat Shrike"=>"Lanius senator",
+"Common Raven"=>"Corvus corax",
+"Yellowhammer"=>"Emberiza citrinella",
+"Ortolan Bunting"=>"Emberiza hortulana",
+"Corn Bunting"=>"Emberiza calandra",
+"Great Cormorant"=>"Phalacrocorax carbo",
+"Hawfinch"=>"Coccothraustes coccothraustes",
+"Common Shelduck"=>"Tadorna tadorna",
+"Bluethroat"=>"Luscinia svecica",
+"Grey Heron"=>"Ardea cinerea",
+"Barn Swallow"=>"Hirundo rustica",
+"Hooded Crow"=>"Corvus cornix",
+"Dunlin"=>"Calidris alpina",
+"Eurasian Pied Flycatcher"=>"Ficedula hypoleuca",
+"Eurasian Nuthatch"=>"Sitta europaea",
+"Short-toed Tree Creeper"=>"Certhia brachydactyla",
+"Wood Lark"=>"Lullula arborea",
+"Tree Pipit"=>"Anthus trivialis",
+"Eurasian Hobby"=>"Falco subbuteo",
+"Marsh Warbler"=>"Acrocephalus palustris",
+"Wood Sandpiper"=>"Tringa glareola",
+"Tawny Owl"=>"Strix aluco",
+"Lesser Whitethroat"=>"Sylvia curruca",
+"Barnacle Goose"=>"Branta leucopsis",
+"Common Goldeneye"=>"Bucephala clangula",
+"Western Marsh Harrier"=>"Circus aeruginosus",
+"Common Buzzard"=>"Buteo buteo",
+"Sanderling"=>"Calidris alba",
+"Little Gull"=>"Larus minutus",
+"Eurasian Magpie"=>"Pica pica",
+"Willow Warbler"=>"Phylloscopus trochilus",
+"Wood Warbler"=>"Phylloscopus sibilatrix",
+"Great Crested Grebe"=>"Podiceps cristatus",
+"Eurasian Jay"=>"Garrulus glandarius",
+"Common Redstart"=>"Phoenicurus phoenicurus",
+"Blue-headed Wagtail"=>"Motacilla flava",
+"Common Swift"=>"Apus apus",
+"Marsh Tit"=>"Poecile palustris",
+"Goldcrest"=>"Regulus regulus",
+"European Golden Plover"=>"Pluvialis apricaria",
+"Eurasian Bullfinch"=>"Pyrrhula pyrrhula",
+"Common Whitethroat"=>"Sylvia communis",
+"Meadow Pipit"=>"Anthus pratensis",
+"Greylag Goose"=>"Anser anser",
+"Spotted Flycatcher"=>"Muscicapa striata",
+"European Greenfinch"=>"Carduelis chloris",
+"Common Greenshank"=>"Tringa nebularia",
+"Great Spotted Woodpecker"=>"Dendrocopos major",
+"Greater Canada Goose"=>"Branta canadensis",
+"Mistle Thrush"=>"Turdus viscivorus",
+"Great Black-backed Gull"=>"Larus marinus",
+"Goosander"=>"Mergus merganser",
+"Great Egret"=>"Casmerodius albus",
+"Northern Goshawk"=>"Accipiter gentilis",
+"Dunnock"=>"Prunella modularis",
+"Stock Dove"=>"Columba oenas",
+"Common Wood Pigeon"=>"Columba palumbus",
+"Eurasian Woodcock"=>"Scolopax rusticola",
+"House Sparrow"=>"Passer domesticus",
+"Common House Martin"=>"Delichon urbicum",
+"Red Knot"=>"Calidris canutus",
+"Western Jackdaw"=>"Corvus monedula",
+"Brambling"=>"Fringilla montifringilla",
+"Northern Lapwing"=>"Vanellus vanellus",
+"European Reed Warbler"=>"Acrocephalus scirpaceus",
+"Lesser Black-backed Gull"=>"Larus fuscus",
+"Little Egret"=>"Egretta garzetta",
+"Little Stint"=>"Calidris minuta",
+"Common Linnet"=>"Carduelis cannabina",
+"Mute Swan"=>"Cygnus olor",
+"Common Cuckoo"=>"Cuculus canorus",
+"Black-headed Gull"=>"Larus ridibundus",
+"Greater White-fronted Goose"=>"Anser albifrons",
+"Great Tit"=>"Parus major",
+"Redwing"=>"Turdus iliacus",
+"Gadwall"=>"Anas strepera",
+"Fieldfare"=>"Turdus pilaris",
+"Tufted Duck"=>"Aythya fuligula",
+"Crested Tit"=>"Lophophanes cristatus",
+"Willow Tit"=>"Poecile montanus",
+"Eurasian Coot"=>"Fulica atra",
+"Common Blackbird"=>"Turdus merula",
+"Smew"=>"Mergus albellus",
+"Common Sandpiper"=>"Actitis hypoleucos",
+"Sand Martin"=>"Riparia riparia",
+"Purple Sandpiper"=>"Calidris maritima",
+"Northern Pintail"=>"Anas acuta",
+"Blue Tit"=>"Cyanistes caeruleus",
+"European Goldfinch"=>"Carduelis carduelis",
+"Eurasian Whimbrel"=>"Numenius phaeopus",
+"Common Reed Bunting"=>"Emberiza schoeniclus",
+"Eurasian Tree Sparrow"=>"Passer montanus",
+"Rook"=>"Corvus frugilegus",
+"European Robin"=>"Erithacus rubecula",
+"Bar-tailed Godwit"=>"Limosa lapponica",
+"Dark-bellied Brent Goose"=>"Branta bernicla",
+"Eurasian Oystercatcher"=>"Haematopus ostralegus",
+"Eurasian Siskin"=>"Carduelis spinus",
+"Northern Shoveler"=>"Anas clypeata",
+"Eurasian Wigeon"=>"Anas penelope",
+"Eurasian Sparrow Hawk"=>"Accipiter nisus",
+"Icterine Warbler"=>"Hippolais icterina",
+"Common Starling"=>"Sturnus vulgaris",
+"Long-tailed Tit"=>"Aegithalos caudatus",
+"Ruddy Turnstone"=>"Arenaria interpres",
+"Mew Gull"=>"Larus canus",
+"Common Pochard"=>"Aythya ferina",
+"Common Chiffchaff"=>"Phylloscopus collybita",
+"Greater Scaup"=>"Aythya marila",
+"Common Kestrel"=>"Falco tinnunculus",
+"Garden Warbler"=>"Sylvia borin",
+"Eurasian Collared Dove"=>"Streptopelia decaocto",
+"Eurasian Skylark"=>"Alauda arvensis",
+"Common Chaffinch"=>"Fringilla coelebs",
+"Common Moorhen"=>"Gallinula chloropus",
+"Water Pipit"=>"Anthus spinoletta",
+"Mallard"=>"Anas platyrhynchos",
+"Winter Wren"=>"Troglodytes troglodytes",
+"Common Teal"=>"Anas crecca",
+"Green Sandpiper"=>"Tringa ochropus",
+"White Wagtail"=>"Motacilla alba",
+"Eurasian Curlew"=>"Numenius arquata",
+"Song Thrush"=>"Turdus philomelos",
+"European Herring Gull"=>"Larus argentatus",
+"Grey Plover"=>"Pluvialis squatarola",
+"Carrion Crow"=>"Corvus corone",
+"Coal Tit"=>"Periparus ater",
+"Spotted Redshank"=>"Tringa erythropus",
+"Blackcap"=>"Sylvia atricapilla",
+"Egyptian Vulture"=>"Neophron percnopterus",
+"Razorbill"=>"Alca torda",
+"Alpine Swift"=>"Apus melba",
+"Long-legged Buzzard"=>"Buteo rufinus",
+"Audouin`s Gull"=>"Larus audouinii",
+"Balearic Shearwater"=>"Puffinus mauretanicus",
+"Upland Sandpiper"=>"Bartramia longicauda",
+"Greater Spotted Eagle"=>"Aquila clanga",
+"Ring Ouzel"=>"Turdus torquatus",
+"Yellow-browed Warbler"=>"Phylloscopus inornatus",
+"Blue Rock Thrush"=>"Monticola solitarius",
+"Buff-breasted Sandpiper"=>"Tryngites subruficollis",
+"Jack Snipe"=>"Lymnocryptes minimus",
+"White-rumped Sandpiper"=>"Calidris fuscicollis",
+"Ruddy Shelduck"=>"Tadorna ferruginea",
+"Cetti's Warbler"=>"Cettia cetti",
+"Citrine Wagtail"=>"Motacilla citreola",
+"Roseate Tern"=>"Sterna dougallii",
+"Black-legged Kittiwake"=>"Rissa tridactyla",
+"Pygmy Cormorant"=>"Phalacrocorax pygmeus",
+"Booted Eagle"=>"Aquila pennata",
+"Lesser White-fronted Goose"=>"Anser erythropus",
+"Little Bunting"=>"Emberiza pusilla",
+"Eleonora's Falcon"=>"Falco eleonorae",
+"European Serin"=>"Serinus serinus",
+"Twite"=>"Carduelis flavirostris",
+"Yellow-legged Gull"=>"Larus michahellis",
+"Gyr Falcon"=>"Falco rusticolus",
+"Greenish Warbler"=>"Phylloscopus trochiloides",
+"Red-necked Phalarope"=>"Phalaropus lobatus",
+"Mealy Redpoll"=>"Carduelis flammea",
+"Glaucous Gull"=>"Larus hyperboreus",
+"Great Skua"=>"Stercorarius skua",
+"Great Bustard"=>"Otis tarda",
+"Velvet Scoter"=>"Melanitta fusca",
+"Pine Grosbeak"=>"Pinicola enucleator",
+"House Crow"=>"Corvus splendens",
+"Hume`s Leaf Warbler"=>"Phylloscopus humei",
+"Great Northern Loon"=>"Gavia immer",
+"Long-tailed Duck"=>"Clangula hyemalis",
+"Lapland Longspur"=>"Calcarius lapponicus",
+"Northern Gannet"=>"Morus bassanus",
+"Eastern Imperial Eagle"=>"Aquila heliaca",
+"Little Auk"=>"Alle alle",
+"Lesser Spotted Woodpecker"=>"Dendrocopos minor",
+"Iceland Gull"=>"Larus glaucoides",
+"Parasitic Jaeger"=>"Stercorarius parasiticus",
+"Bewick`s Swan"=>"Cygnus bewickii",
+"Little Bustard"=>"Tetrax tetrax",
+"Little Crake"=>"Porzana parva",
+"Baillon`s Crake"=>"Porzana pusilla",
+"Long-tailed Jaeger"=>"Stercorarius longicaudus",
+"King Eider"=>"Somateria spectabilis",
+"Greater Short-toed Lark"=>"Calandrella brachydactyla",
+"Houbara Bustard"=>"Chlamydotis undulata",
+"Curlew Sandpiper"=>"Calidris ferruginea",
+"Common Crossbill"=>"Loxia curvirostra",
+"European Shag"=>"Phalacrocorax aristotelis",
+"Horned Grebe"=>"Podiceps auritus",
+"Common Quail"=>"Coturnix coturnix",
+"Bearded Vulture"=>"Gypaetus barbatus",
+"Lanner Falcon"=>"Falco biarmicus",
+"Middle Spotted Woodpecker"=>"Dendrocopos medius",
+"Pomarine Jaeger"=>"Stercorarius pomarinus",
+"Red-breasted Merganser"=>"Mergus serrator",
+"Eurasian Black Vulture"=>"Aegypius monachus",
+"Eurasian Dotterel"=>"Charadrius morinellus",
+"Common Nightingale"=>"Luscinia megarhynchos",
+"Northern willow warbler"=>"Phylloscopus trochilus acredula",
+"Manx Shearwater"=>"Puffinus puffinus",
+"Northern Fulmar"=>"Fulmarus glacialis",
+"Eurasian Eagle Owl"=>"Bubo bubo",
+"Orphean Warbler"=>"Sylvia hortensis",
+"Melodious Warbler"=>"Hippolais polyglotta",
+"Pallas's Leaf Warbler"=>"Phylloscopus proregulus",
+"Atlantic Puffin"=>"Fratercula arctica",
+"Black-throated Loon"=>"Gavia arctica",
+"Bohemian Waxwing"=>"Bombycilla garrulus",
+"Marsh Sandpiper"=>"Tringa stagnatilis",
+"Great Snipe"=>"Gallinago media",
+"Squacco Heron"=>"Ardeola ralloides",
+"Long-eared Owl"=>"Asio otus",
+"Caspian Tern"=>"Hydroprogne caspia",
+"Red-breasted Goose"=>"Branta ruficollis",
+"Red-throated Loon"=>"Gavia stellata",
+"Common Rosefinch"=>"Carpodacus erythrinus",
+"Red-footed Falcon"=>"Falco vespertinus",
+"Ross's Goose"=>"Anser rossii",
+"Red Phalarope"=>"Phalaropus fulicarius",
+"Pied Wagtail"=>"Motacilla yarrellii",
+"Rose-coloured Starling"=>"Sturnus roseus",
+"Rough-legged Buzzard"=>"Buteo lagopus",
+"Saker Falcon"=>"Falco cherrug",
+"European Roller"=>"Coracias garrulus",
+"Short-toed Eagle"=>"Circaetus gallicus",
+"Peregrine Falcon"=>"Falco peregrinus",
+"Merlin"=>"Falco columbarius",
+"Snow Goose"=>"Anser caerulescens",
+"Snowy Owl"=>"Bubo scandiacus",
+"Snow Bunting"=>"Plectrophenax nivalis",
+"Common Grasshopper Warbler"=>"Locustella naevia",
+"Golden Eagle"=>"Aquila chrysaetos",
+"Black-winged Stilt"=>"Himantopus himantopus",
+"Steppe Eagle"=>"Aquila nipalensis",
+"Pallid Harrier"=>"Circus macrourus",
+"European Storm-petrel"=>"Hydrobates pelagicus",
+"Horned Lark"=>"Eremophila alpestris",
+"Eurasian Treecreeper"=>"Certhia familiaris",
+"Taiga Bean Goose"=>"Anser fabalis",
+"Temminck`s Stint"=>"Calidris temminckii",
+"Terek Sandpiper"=>"Xenus cinereus",
+"Tundra Bean Goose"=>"Anser serrirostris",
+"European Turtle Dove"=>"Streptopelia turtur",
+"Leach`s Storm-petrel"=>"Oceanodroma leucorhoa",
+"Eurasian Griffon Vulture"=>"Gyps fulvus",
+"Paddyfield Warbler"=>"Acrocephalus agricola",
+"Osprey"=>"Pandion haliaetus",
+"Firecrest"=>"Regulus ignicapilla",
+"Water Rail"=>"Rallus aquaticus",
+"European Honey Buzzard"=>"Pernis apivorus",
+"Eurasian Golden Oriole"=>"Oriolus oriolus",
+"Whooper Swan"=>"Cygnus cygnus",
+"Two-barred Crossbill"=>"Loxia leucoptera",
+"White-tailed Eagle"=>"Haliaeetus albicilla",
+"Atlantic Murre"=>"Uria aalge",
+"Garganey"=>"Anas querquedula",
+"Black Redstart"=>"Phoenicurus ochruros",
+"Common Scoter"=>"Melanitta nigra",
+"Rock Pipit"=>"Anthus petrosus",
+"Lesser Spotted Eagle"=>"Aquila pomarina",
+"Cattle Egret"=>"Bubulcus ibis",
+"White-winged Black Tern"=>"Chlidonias leucopterus",
+"Black Stork"=>"Ciconia nigra",
+"Mediterranean Gull"=>"Larus melanocephalus",
+"Black Kite"=>"Milvus migrans",
+"Yellow Wagtail"=>"Motacilla flavissima",
+"Red-necked Grebe"=>"Podiceps grisegena",
+"Gull-billed Tern"=>"Gelochelidon nilotica",
+"Pectoral Sandpiper"=>"Calidris melanotos",
+"Barred Warbler"=>"Sylvia nisoria",
+"Red-throated Pipit"=>"Anthus cervinus",
+"Grey Wagtail"=>"Motacilla cinerea",
+"Richard`s Pipit"=>"Anthus richardi",
+"Black Woodpecker"=>"Dryocopus martius",
+"Little Ringed Plover"=>"Charadrius dubius",
+"Whiskered Tern"=>"Chlidonias hybrida",
+"Lesser Redpoll"=>"Carduelis cabaret",
+"Pallas' Bunting"=>"Emberiza pallasi",
+"Ferruginous Duck"=>"Aythya nyroca",
+"Whistling Swan"=>"Cygnus columbianus",
+"Black Brant"=>"Branta nigricans",
+"Marbled Teal"=>"Marmaronetta angustirostris",
+"Canvasback"=>"Aythya valisineria",
+"Redhead"=>"Aythya americana",
+"Lesser Scaup"=>"Aythya affinis",
+"Steller`s Eider"=>"Polysticta stelleri",
+"Spectacled Eider"=>"Somateria fischeri",
+"Harlequin Duck"=>"Histronicus histrionicus",
+"Black Scoter"=>"Melanitta americana",
+"Surf Scoter"=>"Melanitta perspicillata",
+"Barrow`s Goldeneye"=>"Bucephala islandica",
+"Falcated Duck"=>"Anas falcata",
+"American Wigeon"=>"Anas americana",
+"Blue-winged Teal"=>"Anas discors",
+"American Black Duck"=>"Anas rubripes",
+"Baikal Teal"=>"Anas formosa",
+"Green-Winged Teal"=>"Anas carolinensis",
+"Hazel Grouse"=>"Bonasa bonasia",
+"Rock Partridge"=>"Alectoris graeca",
+"Red-legged Partridge"=>"Alectoris rufa",
+"Yellow-billed Loon"=>"Gavia adamsii",
+"Cory`s Shearwater"=>"Calonectris borealis",
+"Madeiran Storm-Petrel"=>"Oceanodroma castro",
+"Great White Pelican"=>"Pelecanus onocrotalus",
+"Dalmatian Pelican"=>"Pelecanus crispus",
+"American Bittern"=>"Botaurus lentiginosus",
+"Glossy Ibis"=>"Plegadis falcinellus",
+"Spanish Imperial Eagle"=>"Aquila adalberti",
+"Lesser Kestrel"=>"Falco naumanni",
+"Houbara Bustard"=>"Chlamydotis undulata",
+"Crab-Plover"=>"Dromas ardeola",
+"Cream-coloured Courser"=>"Cursorius cursor",
+"Collared Pratincole"=>"Glareola pratincola",
+"Black-winged Pratincole"=>"Glareola nordmanni",
+"Killdeer"=>"Charadrius vociferus",
+"Lesser Sand Plover"=>"Charadrius mongolus",
+"Greater Sand Plover"=>"Charadrius leschenaultii",
+"Caspian Plover"=>"Charadrius asiaticus",
+"American Golden Plover"=>"Pluvialis dominica",
+"Pacific Golden Plover"=>"Pluvialis fulva",
+"Sharp-tailed Sandpiper"=>"Calidris acuminata",
+"Broad-billed Sandpiper"=>"Limicola falcinellus",
+"Spoon-Billed Sandpiper"=>"Eurynorhynchus pygmaeus",
+"Short-Billed Dowitcher"=>"Limnodromus griseus",
+"Long-billed Dowitcher"=>"Limnodromus scolopaceus",
+"Hudsonian Godwit"=>"Limosa haemastica",
+"Little Curlew"=>"Numenius minutus",
+"Lesser Yellowlegs"=>"Tringa flavipes",
+"Wilson`s Phalarope"=>"Phalaropus tricolor",
+"Pallas`s Gull"=>"Larus ichthyaetus",
+"Laughing Gull"=>"Larus atricilla",
+"Franklin`s Gull"=>"Larus pipixcan",
+"Bonaparte`s Gull"=>"Larus philadelphia",
+"Ring-billed Gull"=>"Larus delawarensis",
+"American Herring Gull"=>"Larus smithsonianus",
+"Caspian Gull"=>"Larus cachinnans",
+"Ivory Gull"=>"Pagophila eburnea",
+"Royal Tern"=>"Sterna maxima",
+"Brünnich`s Murre"=>"Uria lomvia",
+"Crested Auklet"=>"Aethia cristatella",
+"Parakeet Auklet"=>"Cyclorrhynchus psittacula",
+"Tufted Puffin"=>"Lunda cirrhata",
+"Laughing Dove"=>"Streptopelia senegalensis",
+"Great Spotted Cuckoo"=>"Clamator glandarius",
+"Great Grey Owl"=>"Strix nebulosa",
+"Tengmalm`s Owl"=>"Aegolius funereus",
+"Red-Necked Nightjar"=>"Caprimulgus ruficollis",
+"Chimney Swift"=>"Chaetura pelagica",
+"Green Bea-Eater"=>"Merops orientalis",
+"Grey-headed Woodpecker"=>"Picus canus",
+"Lesser Short-Toed Lark"=>"Calandrella rufescens",
+"Eurasian Crag Martin"=>"Hirundo rupestris",
+"Red-rumped Swallow"=>"Cecropis daurica",
+"Blyth`s Pipit"=>"Anthus godlewskii",
+"Pechora Pipit"=>"Anthus gustavi",
+"Grey-headed Wagtail"=>"Motacilla thunbergi",
+"Yellow-Headed Wagtail"=>"Motacilla lutea",
+"White-throated Dipper"=>"Cinclus cinclus",
+"Rufous-Tailed Scrub Robin"=>"Cercotrichas galactotes",
+"Thrush Nightingale"=>"Luscinia luscinia",
+"White-throated Robin"=>"Irania gutturalis",
+"Caspian Stonechat"=>"Saxicola maura variegata",
+"Western Black-eared Wheatear"=>"Oenanthe hispanica",
+"Rufous-tailed Rock Thrush"=>"Monticola saxatilis",
+"Red-throated Thrush/Black-throated"=>"Turdus ruficollis",
+"American Robin"=>"Turdus migratorius",
+"Zitting Cisticola"=>"Cisticola juncidis",
+"Lanceolated Warbler"=>"Locustella lanceolata",
+"River Warbler"=>"Locustella fluviatilis",
+"Blyth`s Reed Warbler"=>"Acrocephalus dumetorum",
+"Caspian Reed Warbler"=>"Acrocephalus fuscus",
+"Aquatic Warbler"=>"Acrocephalus paludicola",
+"Booted Warbler"=>"Acrocephalus caligatus",
+"Marmora's Warbler"=>"Sylvia sarda",
+"Dartford Warbler"=>"Sylvia undata",
+"Subalpine Warbler"=>"Sylvia cantillans",
+"Ménétries's Warbler"=>"Sylvia mystacea",
+"Rüppel's Warbler"=>"Sylvia rueppelli",
+"Asian Desert Warbler"=>"Sylvia nana",
+"Western Orphean Warbler"=>"Sylvia hortensis hortensis",
+"Arctic Warbler"=>"Phylloscopus borealis",
+"Radde`s Warbler"=>"Phylloscopus schwarzi",
+"Western Bonelli`s Warbler"=>"Phylloscopus bonelli",
+"Red-breasted Flycatcher"=>"Ficedula parva",
+"Eurasian Penduline Tit"=>"Remiz pendulinus",
+"Daurian Shrike"=>"Lanius isabellinus",
+"Long-Tailed Shrike"=>"Lanius schach",
+"Lesser Grey Shrike"=>"Lanius minor",
+"Southern Grey Shrike"=>"Lanius meridionalis",
+"Masked Shrike"=>"Lanius nubicus",
+"Spotted Nutcracker"=>"Nucifraga caryocatactes",
+"Daurian Jackdaw"=>"Corvus dauuricus",
+"Purple-Backed Starling"=>"Sturnus sturninus",
+"Red-Fronted Serin"=>"Serinus pusillus",
+"Arctic Redpoll"=>"Carduelis hornemanni",
+"Scottish Crossbill"=>"Loxia scotica",
+"Parrot Crossbill"=>"Loxia pytyopsittacus",
+"Black-faced Bunting"=>"Emberiza spodocephala",
+"Pink-footed Goose"=>"Anser brachyrhynchus",
+"Black-winged Kite"=>"Elanus caeruleus",
+"European Bee-eater"=>"Merops apiaster",
+"Sabine`s Gull"=>"Larus sabini",
+"Sooty Shearwater"=>"Puffinus griseus",
+"Lesser Canada Goose"=>"Branta hutchinsii",
+"Ring-necked Duck"=>"Aythya collaris",
+"Greater Flamingo"=>"Phoenicopterus roseus",
+"Iberian Chiffchaff"=>"Phylloscopus ibericus",
+"Ashy-headed Wagtail"=>"Motacilla cinereocapilla",
+"Stilt Sandpiper"=>"Calidris himantopus",
+"Siberian Stonechat"=>"Saxicola maurus",
+"Greater Yellowlegs"=>"Tringa melanoleuca",
+"Forster`s Tern"=>"Sterna forsteri",
+"Dusky Warbler"=>"Phylloscopus fuscatus",
+"Cirl Bunting"=>"Emberiza cirlus",
+"Olive-backed Pipit"=>"Anthus hodgsoni",
+"Sociable Lapwing"=>"Vanellus gregarius",
+"Spotted Sandpiper"=>"Actitis macularius",
+"Baird`s Sandpiper"=>"Calidris bairdii",
+"Rustic Bunting"=>"Emberiza rustica",
+"Yellow-browed Bunting"=>"Emberiza chrysophrys",
+"Great Shearwater"=>"Puffinus gravis",
+"Bonelli`s Eagle"=>"Aquila fasciata",
+"Calandra Lark"=>"Melanocorypha calandra",
+"Sardinian Warbler"=>"Sylvia melanocephala",
+"Ross's Gull"=>"Larus roseus",
+"Yellow-Breasted Bunting"=>"Emberiza aureola",
+"Pine Bunting"=>"Emberiza leucocephalos",
+"Black Guillemot"=>"Cepphus grylle",
+"Pied-billed Grebe"=>"Podilymbus podiceps",
+"Soft-plumaged Petrel"=>"Pterodroma mollis",
+"Bulwer's Petrel"=>"Bulweria bulwerii",
+"White-Faced Storm-Petrel"=>"Pelagodroma marina",
+"Pallas’s Fish Eagle"=>"Haliaeetus leucoryphus",
+"Sandhill Crane"=>"Grus canadensis",
+"Macqueen’s Bustard"=>"Chlamydotis macqueenii",
+"White-tailed Lapwing"=>"Vanellus leucurus",
+"Great Knot"=>"Calidris tenuirostris",
+"Semipalmated Sandpiper"=>"Calidris pusilla",
+"Red-necked Stint"=>"Calidris ruficollis",
+"Slender-billed Curlew"=>"Numenius tenuirostris",
+"Bridled Tern"=>"Onychoprion anaethetus",
+"Pallas’s Sandgrouse"=>"Syrrhaptes paradoxus",
+"European Scops Owl"=>"Otus scops",
+"Northern Hawk Owl"=>"Surnia ulula",
+"White-Throated Needletail"=>"Hirundapus caudacutus",
+"Belted Kingfisher"=>"Ceryle alcyon",
+"Blue-cheeked Bee-eater"=>"Merops persicus",
+"Black-headed Wagtail"=>"Motacilla feldegg",
+"Northern Mockingbird"=>"Mimus polyglottos",
+"Alpine Accentor"=>"Prunella collaris",
+"Red-flanked Bluetail"=>"Tarsiger cyanurus",
+"Isabelline Wheatear"=>"Oenanthe isabellina",
+"Pied Wheatear"=>"Oenanthe pleschanka",
+"Eastern Black-eared Wheatear"=>"Oenanthe melanoleuca",
+"Desert Wheatear"=>"Oenanthe deserti",
+"White`s Thrush"=>"Zoothera aurea",
+"Siberian Thrush"=>"Zoothera sibirica",
+"Eyebrowed Thrush"=>"Turdus obscurus",
+"Dusky Thrush"=>"Turdus eunomus",
+"Black-throated Thrush"=>"Turdus atrogularis",
+"Pallas`s Grasshopper Warbler"=>"Locustella certhiola",
+"Spectacled Warbler"=>"Sylvia conspicillata",
+"Two-barred Warbler"=>"Phylloscopus plumbeitarsus",
+"Eastern Bonelli’s Warbler"=>"Phylloscopus orientalis",
+"Collared Flycatcher"=>"Ficedula albicollis",
+"Wallcreeper"=>"Tichodroma muraria",
+"Turkestan Shrike"=>"Lanius phoenicuroides",
+"Steppe Grey Shrike"=>"Lanius pallidirostris",
+"Spanish Sparrow"=>"Passer hispaniolensis",
+"Red-eyed Vireo"=>"Vireo olivaceus",
+"Myrtle Warbler"=>"Dendroica coronata",
+"White-crowned Sparrow"=>"Zonotrichia leucophrys",
+"White-throated Sparrow"=>"Zonotrichia albicollis",
+"Cretzschmar`s Bunting"=>"Emberiza caesia",
+"Chestnut Bunting"=>"Emberiza rutila",
+"Red-headed Bunting"=>"Emberiza bruniceps",
+"Black-headed Bunting"=>"Emberiza melanocephala",
+"Indigo Bunting"=>"Passerina cyanea",
+"Balearic Woodchat Shrike"=>"Lanius senator badius",
+"Demoiselle Crane"=>"Grus virgo",
+"Chough"=>"Pyrrhocorax pyrrhocorax",
+"Red-Billed Chough"=>"Pyrrhocorax graculus",
+"Elegant Tern"=>"Sterna elegans",
+"Chukar"=>"Alectoris chukar",
+"Yellow-Billed Cuckoo"=>"Coccyzus americanus",
+"American Sandwich Tern"=>"Sterna sandvicensis acuflavida",
+"Olive-Tree Warbler"=>"Hippolais olivetorum",
+"Eastern Olivaceous Warbler"=>"Acrocephalus pallidus",
+"Indian Cormorant"=>"Phalacrocorax fuscicollis",
+"Spur-Winged Lapwing"=>"Vanellus spinosus",
+"Yelkouan Shearwater"=>"Puffinus yelkouan",
+"Trumpeter Finch"=>"Bucanetes githagineus",
+"Red Grouse"=>"Lagopus scoticus",
+"Rock Ptarmigan"=>"Lagopus mutus",
+"Long-Tailed Cormorant"=>"Phalacrocorax africanus",
+"Double-crested Cormorant"=>"Phalacrocorax auritus",
+"Magnificent Frigatebird"=>"Fregata magnificens",
+"Naumann's Thrush"=>"Turdus naumanni",
+"Oriental Pratincole"=>"Glareola maldivarum",
+"Bufflehead"=>"Bucephala albeola",
+"Snowfinch"=>"Montifrigilla nivalis",
+"Ural owl"=>"Strix uralensis",
+"Spanish Wagtail"=>"Motacilla iberiae",
+"Song Sparrow"=>"Melospiza melodia",
+"Rock Bunting"=>"Emberiza cia",
+"Siberian Rubythroat"=>"Luscinia calliope",
+"Pallid Swift"=>"Apus pallidus",
+"Eurasian Pygmy Owl"=>"Glaucidium passerinum",
+"Madeira Little Shearwater"=>"Puffinus baroli",
+"House Finch"=>"Carpodacus mexicanus",
+"Green Heron"=>"Butorides virescens",
+"Solitary Sandpiper"=>"Tringa solitaria",
+"Heuglin's Gull"=>"Larus heuglini"
+);
+
+foreach ($items as $key=>$value) {
+ if (strpos(strtolower($key), $q) !== false) {
+ echo "$key|$value\n";
+ }
+}
+
+?>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/demo/search.phps Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,578 @@
+<?php
+
+$q = strtolower($_GET["q"]);
+if (!$q) return;
+$items = array(
+"Great <em>Bittern</em>"=>"Botaurus stellaris",
+"Little <em>Grebe</em>"=>"Tachybaptus ruficollis",
+"Black-necked Grebe"=>"Podiceps nigricollis",
+"Little Bittern"=>"Ixobrychus minutus",
+"Black-crowned Night Heron"=>"Nycticorax nycticorax",
+"Purple Heron"=>"Ardea purpurea",
+"White Stork"=>"Ciconia ciconia",
+"Spoonbill"=>"Platalea leucorodia",
+"Red-crested Pochard"=>"Netta rufina",
+"Common Eider"=>"Somateria mollissima",
+"Red Kite"=>"Milvus milvus",
+"Hen Harrier"=>"Circus cyaneus",
+"Montagu`s Harrier"=>"Circus pygargus",
+"Black Grouse"=>"Tetrao tetrix",
+"Grey Partridge"=>"Perdix perdix",
+"Spotted Crake"=>"Porzana porzana",
+"Corncrake"=>"Crex crex",
+"Common Crane"=>"Grus grus",
+"Avocet"=>"Recurvirostra avosetta",
+"Stone Curlew"=>"Burhinus oedicnemus",
+"Common Ringed Plover"=>"Charadrius hiaticula",
+"Kentish Plover"=>"Charadrius alexandrinus",
+"Ruff"=>"Philomachus pugnax",
+"Common Snipe"=>"Gallinago gallinago",
+"Black-tailed Godwit"=>"Limosa limosa",
+"Common Redshank"=>"Tringa totanus",
+"Sandwich Tern"=>"Sterna sandvicensis",
+"Common Tern"=>"Sterna hirundo",
+"Arctic Tern"=>"Sterna paradisaea",
+"Little Tern"=>"Sternula albifrons",
+"Black Tern"=>"Chlidonias niger",
+"Barn Owl"=>"Tyto alba",
+"Little Owl"=>"Athene noctua",
+"Short-eared Owl"=>"Asio flammeus",
+"European Nightjar"=>"Caprimulgus europaeus",
+"Common Kingfisher"=>"Alcedo atthis",
+"Eurasian Hoopoe"=>"Upupa epops",
+"Eurasian Wryneck"=>"Jynx torquilla",
+"European Green Woodpecker"=>"Picus viridis",
+"Crested Lark"=>"Galerida cristata",
+"White-headed Duck"=>"Oxyura leucocephala",
+"Pale-bellied Brent Goose"=>"Branta hrota",
+"Tawny Pipit"=>"Anthus campestris",
+"Whinchat"=>"Saxicola rubetra",
+"European Stonechat"=>"Saxicola rubicola",
+"Northern Wheatear"=>"Oenanthe oenanthe",
+"Savi`s Warbler"=>"Locustella luscinioides",
+"Sedge Warbler"=>"Acrocephalus schoenobaenus",
+"Great Reed Warbler"=>"Acrocephalus arundinaceus",
+"Bearded Reedling"=>"Panurus biarmicus",
+"Red-backed Shrike"=>"Lanius collurio",
+"Great Grey Shrike"=>"Lanius excubitor",
+"Woodchat Shrike"=>"Lanius senator",
+"Common Raven"=>"Corvus corax",
+"Yellowhammer"=>"Emberiza citrinella",
+"Ortolan Bunting"=>"Emberiza hortulana",
+"Corn Bunting"=>"Emberiza calandra",
+"Great Cormorant"=>"Phalacrocorax carbo",
+"Hawfinch"=>"Coccothraustes coccothraustes",
+"Common Shelduck"=>"Tadorna tadorna",
+"Bluethroat"=>"Luscinia svecica",
+"Grey Heron"=>"Ardea cinerea",
+"Barn Swallow"=>"Hirundo rustica",
+"Hooded Crow"=>"Corvus cornix",
+"Dunlin"=>"Calidris alpina",
+"Eurasian Pied Flycatcher"=>"Ficedula hypoleuca",
+"Eurasian Nuthatch"=>"Sitta europaea",
+"Short-toed Tree Creeper"=>"Certhia brachydactyla",
+"Wood Lark"=>"Lullula arborea",
+"Tree Pipit"=>"Anthus trivialis",
+"Eurasian Hobby"=>"Falco subbuteo",
+"Marsh Warbler"=>"Acrocephalus palustris",
+"Wood Sandpiper"=>"Tringa glareola",
+"Tawny Owl"=>"Strix aluco",
+"Lesser Whitethroat"=>"Sylvia curruca",
+"Barnacle Goose"=>"Branta leucopsis",
+"Common Goldeneye"=>"Bucephala clangula",
+"Western Marsh Harrier"=>"Circus aeruginosus",
+"Common Buzzard"=>"Buteo buteo",
+"Sanderling"=>"Calidris alba",
+"Little Gull"=>"Larus minutus",
+"Eurasian Magpie"=>"Pica pica",
+"Willow Warbler"=>"Phylloscopus trochilus",
+"Wood Warbler"=>"Phylloscopus sibilatrix",
+"Great Crested Grebe"=>"Podiceps cristatus",
+"Eurasian Jay"=>"Garrulus glandarius",
+"Common Redstart"=>"Phoenicurus phoenicurus",
+"Blue-headed Wagtail"=>"Motacilla flava",
+"Common Swift"=>"Apus apus",
+"Marsh Tit"=>"Poecile palustris",
+"Goldcrest"=>"Regulus regulus",
+"European Golden Plover"=>"Pluvialis apricaria",
+"Eurasian Bullfinch"=>"Pyrrhula pyrrhula",
+"Common Whitethroat"=>"Sylvia communis",
+"Meadow Pipit"=>"Anthus pratensis",
+"Greylag Goose"=>"Anser anser",
+"Spotted Flycatcher"=>"Muscicapa striata",
+"European Greenfinch"=>"Carduelis chloris",
+"Common Greenshank"=>"Tringa nebularia",
+"Great Spotted Woodpecker"=>"Dendrocopos major",
+"Greater Canada Goose"=>"Branta canadensis",
+"Mistle Thrush"=>"Turdus viscivorus",
+"Great Black-backed Gull"=>"Larus marinus",
+"Goosander"=>"Mergus merganser",
+"Great Egret"=>"Casmerodius albus",
+"Northern Goshawk"=>"Accipiter gentilis",
+"Dunnock"=>"Prunella modularis",
+"Stock Dove"=>"Columba oenas",
+"Common Wood Pigeon"=>"Columba palumbus",
+"Eurasian Woodcock"=>"Scolopax rusticola",
+"House Sparrow"=>"Passer domesticus",
+"Common House Martin"=>"Delichon urbicum",
+"Red Knot"=>"Calidris canutus",
+"Western Jackdaw"=>"Corvus monedula",
+"Brambling"=>"Fringilla montifringilla",
+"Northern Lapwing"=>"Vanellus vanellus",
+"European Reed Warbler"=>"Acrocephalus scirpaceus",
+"Lesser Black-backed Gull"=>"Larus fuscus",
+"Little Egret"=>"Egretta garzetta",
+"Little Stint"=>"Calidris minuta",
+"Common Linnet"=>"Carduelis cannabina",
+"Mute Swan"=>"Cygnus olor",
+"Common Cuckoo"=>"Cuculus canorus",
+"Black-headed Gull"=>"Larus ridibundus",
+"Greater White-fronted Goose"=>"Anser albifrons",
+"Great Tit"=>"Parus major",
+"Redwing"=>"Turdus iliacus",
+"Gadwall"=>"Anas strepera",
+"Fieldfare"=>"Turdus pilaris",
+"Tufted Duck"=>"Aythya fuligula",
+"Crested Tit"=>"Lophophanes cristatus",
+"Willow Tit"=>"Poecile montanus",
+"Eurasian Coot"=>"Fulica atra",
+"Common Blackbird"=>"Turdus merula",
+"Smew"=>"Mergus albellus",
+"Common Sandpiper"=>"Actitis hypoleucos",
+"Sand Martin"=>"Riparia riparia",
+"Purple Sandpiper"=>"Calidris maritima",
+"Northern Pintail"=>"Anas acuta",
+"Blue Tit"=>"Cyanistes caeruleus",
+"European Goldfinch"=>"Carduelis carduelis",
+"Eurasian Whimbrel"=>"Numenius phaeopus",
+"Common Reed Bunting"=>"Emberiza schoeniclus",
+"Eurasian Tree Sparrow"=>"Passer montanus",
+"Rook"=>"Corvus frugilegus",
+"European Robin"=>"Erithacus rubecula",
+"Bar-tailed Godwit"=>"Limosa lapponica",
+"Dark-bellied Brent Goose"=>"Branta bernicla",
+"Eurasian Oystercatcher"=>"Haematopus ostralegus",
+"Eurasian Siskin"=>"Carduelis spinus",
+"Northern Shoveler"=>"Anas clypeata",
+"Eurasian Wigeon"=>"Anas penelope",
+"Eurasian Sparrow Hawk"=>"Accipiter nisus",
+"Icterine Warbler"=>"Hippolais icterina",
+"Common Starling"=>"Sturnus vulgaris",
+"Long-tailed Tit"=>"Aegithalos caudatus",
+"Ruddy Turnstone"=>"Arenaria interpres",
+"Mew Gull"=>"Larus canus",
+"Common Pochard"=>"Aythya ferina",
+"Common Chiffchaff"=>"Phylloscopus collybita",
+"Greater Scaup"=>"Aythya marila",
+"Common Kestrel"=>"Falco tinnunculus",
+"Garden Warbler"=>"Sylvia borin",
+"Eurasian Collared Dove"=>"Streptopelia decaocto",
+"Eurasian Skylark"=>"Alauda arvensis",
+"Common Chaffinch"=>"Fringilla coelebs",
+"Common Moorhen"=>"Gallinula chloropus",
+"Water Pipit"=>"Anthus spinoletta",
+"Mallard"=>"Anas platyrhynchos",
+"Winter Wren"=>"Troglodytes troglodytes",
+"Common Teal"=>"Anas crecca",
+"Green Sandpiper"=>"Tringa ochropus",
+"White Wagtail"=>"Motacilla alba",
+"Eurasian Curlew"=>"Numenius arquata",
+"Song Thrush"=>"Turdus philomelos",
+"European Herring Gull"=>"Larus argentatus",
+"Grey Plover"=>"Pluvialis squatarola",
+"Carrion Crow"=>"Corvus corone",
+"Coal Tit"=>"Periparus ater",
+"Spotted Redshank"=>"Tringa erythropus",
+"Blackcap"=>"Sylvia atricapilla",
+"Egyptian Vulture"=>"Neophron percnopterus",
+"Razorbill"=>"Alca torda",
+"Alpine Swift"=>"Apus melba",
+"Long-legged Buzzard"=>"Buteo rufinus",
+"Audouin`s Gull"=>"Larus audouinii",
+"Balearic Shearwater"=>"Puffinus mauretanicus",
+"Upland Sandpiper"=>"Bartramia longicauda",
+"Greater Spotted Eagle"=>"Aquila clanga",
+"Ring Ouzel"=>"Turdus torquatus",
+"Yellow-browed Warbler"=>"Phylloscopus inornatus",
+"Blue Rock Thrush"=>"Monticola solitarius",
+"Buff-breasted Sandpiper"=>"Tryngites subruficollis",
+"Jack Snipe"=>"Lymnocryptes minimus",
+"White-rumped Sandpiper"=>"Calidris fuscicollis",
+"Ruddy Shelduck"=>"Tadorna ferruginea",
+"Cetti's Warbler"=>"Cettia cetti",
+"Citrine Wagtail"=>"Motacilla citreola",
+"Roseate Tern"=>"Sterna dougallii",
+"Black-legged Kittiwake"=>"Rissa tridactyla",
+"Pygmy Cormorant"=>"Phalacrocorax pygmeus",
+"Booted Eagle"=>"Aquila pennata",
+"Lesser White-fronted Goose"=>"Anser erythropus",
+"Little Bunting"=>"Emberiza pusilla",
+"Eleonora's Falcon"=>"Falco eleonorae",
+"European Serin"=>"Serinus serinus",
+"Twite"=>"Carduelis flavirostris",
+"Yellow-legged Gull"=>"Larus michahellis",
+"Gyr Falcon"=>"Falco rusticolus",
+"Greenish Warbler"=>"Phylloscopus trochiloides",
+"Red-necked Phalarope"=>"Phalaropus lobatus",
+"Mealy Redpoll"=>"Carduelis flammea",
+"Glaucous Gull"=>"Larus hyperboreus",
+"Great Skua"=>"Stercorarius skua",
+"Great Bustard"=>"Otis tarda",
+"Velvet Scoter"=>"Melanitta fusca",
+"Pine Grosbeak"=>"Pinicola enucleator",
+"House Crow"=>"Corvus splendens",
+"Hume`s Leaf Warbler"=>"Phylloscopus humei",
+"Great Northern Loon"=>"Gavia immer",
+"Long-tailed Duck"=>"Clangula hyemalis",
+"Lapland Longspur"=>"Calcarius lapponicus",
+"Northern Gannet"=>"Morus bassanus",
+"Eastern Imperial Eagle"=>"Aquila heliaca",
+"Little Auk"=>"Alle alle",
+"Lesser Spotted Woodpecker"=>"Dendrocopos minor",
+"Iceland Gull"=>"Larus glaucoides",
+"Parasitic Jaeger"=>"Stercorarius parasiticus",
+"Bewick`s Swan"=>"Cygnus bewickii",
+"Little Bustard"=>"Tetrax tetrax",
+"Little Crake"=>"Porzana parva",
+"Baillon`s Crake"=>"Porzana pusilla",
+"Long-tailed Jaeger"=>"Stercorarius longicaudus",
+"King Eider"=>"Somateria spectabilis",
+"Greater Short-toed Lark"=>"Calandrella brachydactyla",
+"Houbara Bustard"=>"Chlamydotis undulata",
+"Curlew Sandpiper"=>"Calidris ferruginea",
+"Common Crossbill"=>"Loxia curvirostra",
+"European Shag"=>"Phalacrocorax aristotelis",
+"Horned Grebe"=>"Podiceps auritus",
+"Common Quail"=>"Coturnix coturnix",
+"Bearded Vulture"=>"Gypaetus barbatus",
+"Lanner Falcon"=>"Falco biarmicus",
+"Middle Spotted Woodpecker"=>"Dendrocopos medius",
+"Pomarine Jaeger"=>"Stercorarius pomarinus",
+"Red-breasted Merganser"=>"Mergus serrator",
+"Eurasian Black Vulture"=>"Aegypius monachus",
+"Eurasian Dotterel"=>"Charadrius morinellus",
+"Common Nightingale"=>"Luscinia megarhynchos",
+"Northern willow warbler"=>"Phylloscopus trochilus acredula",
+"Manx Shearwater"=>"Puffinus puffinus",
+"Northern Fulmar"=>"Fulmarus glacialis",
+"Eurasian Eagle Owl"=>"Bubo bubo",
+"Orphean Warbler"=>"Sylvia hortensis",
+"Melodious Warbler"=>"Hippolais polyglotta",
+"Pallas's Leaf Warbler"=>"Phylloscopus proregulus",
+"Atlantic Puffin"=>"Fratercula arctica",
+"Black-throated Loon"=>"Gavia arctica",
+"Bohemian Waxwing"=>"Bombycilla garrulus",
+"Marsh Sandpiper"=>"Tringa stagnatilis",
+"Great Snipe"=>"Gallinago media",
+"Squacco Heron"=>"Ardeola ralloides",
+"Long-eared Owl"=>"Asio otus",
+"Caspian Tern"=>"Hydroprogne caspia",
+"Red-breasted Goose"=>"Branta ruficollis",
+"Red-throated Loon"=>"Gavia stellata",
+"Common Rosefinch"=>"Carpodacus erythrinus",
+"Red-footed Falcon"=>"Falco vespertinus",
+"Ross's Goose"=>"Anser rossii",
+"Red Phalarope"=>"Phalaropus fulicarius",
+"Pied Wagtail"=>"Motacilla yarrellii",
+"Rose-coloured Starling"=>"Sturnus roseus",
+"Rough-legged Buzzard"=>"Buteo lagopus",
+"Saker Falcon"=>"Falco cherrug",
+"European Roller"=>"Coracias garrulus",
+"Short-toed Eagle"=>"Circaetus gallicus",
+"Peregrine Falcon"=>"Falco peregrinus",
+"Merlin"=>"Falco columbarius",
+"Snow Goose"=>"Anser caerulescens",
+"Snowy Owl"=>"Bubo scandiacus",
+"Snow Bunting"=>"Plectrophenax nivalis",
+"Common Grasshopper Warbler"=>"Locustella naevia",
+"Golden Eagle"=>"Aquila chrysaetos",
+"Black-winged Stilt"=>"Himantopus himantopus",
+"Steppe Eagle"=>"Aquila nipalensis",
+"Pallid Harrier"=>"Circus macrourus",
+"European Storm-petrel"=>"Hydrobates pelagicus",
+"Horned Lark"=>"Eremophila alpestris",
+"Eurasian Treecreeper"=>"Certhia familiaris",
+"Taiga Bean Goose"=>"Anser fabalis",
+"Temminck`s Stint"=>"Calidris temminckii",
+"Terek Sandpiper"=>"Xenus cinereus",
+"Tundra Bean Goose"=>"Anser serrirostris",
+"European Turtle Dove"=>"Streptopelia turtur",
+"Leach`s Storm-petrel"=>"Oceanodroma leucorhoa",
+"Eurasian Griffon Vulture"=>"Gyps fulvus",
+"Paddyfield Warbler"=>"Acrocephalus agricola",
+"Osprey"=>"Pandion haliaetus",
+"Firecrest"=>"Regulus ignicapilla",
+"Water Rail"=>"Rallus aquaticus",
+"European Honey Buzzard"=>"Pernis apivorus",
+"Eurasian Golden Oriole"=>"Oriolus oriolus",
+"Whooper Swan"=>"Cygnus cygnus",
+"Two-barred Crossbill"=>"Loxia leucoptera",
+"White-tailed Eagle"=>"Haliaeetus albicilla",
+"Atlantic Murre"=>"Uria aalge",
+"Garganey"=>"Anas querquedula",
+"Black Redstart"=>"Phoenicurus ochruros",
+"Common Scoter"=>"Melanitta nigra",
+"Rock Pipit"=>"Anthus petrosus",
+"Lesser Spotted Eagle"=>"Aquila pomarina",
+"Cattle Egret"=>"Bubulcus ibis",
+"White-winged Black Tern"=>"Chlidonias leucopterus",
+"Black Stork"=>"Ciconia nigra",
+"Mediterranean Gull"=>"Larus melanocephalus",
+"Black Kite"=>"Milvus migrans",
+"Yellow Wagtail"=>"Motacilla flavissima",
+"Red-necked Grebe"=>"Podiceps grisegena",
+"Gull-billed Tern"=>"Gelochelidon nilotica",
+"Pectoral Sandpiper"=>"Calidris melanotos",
+"Barred Warbler"=>"Sylvia nisoria",
+"Red-throated Pipit"=>"Anthus cervinus",
+"Grey Wagtail"=>"Motacilla cinerea",
+"Richard`s Pipit"=>"Anthus richardi",
+"Black Woodpecker"=>"Dryocopus martius",
+"Little Ringed Plover"=>"Charadrius dubius",
+"Whiskered Tern"=>"Chlidonias hybrida",
+"Lesser Redpoll"=>"Carduelis cabaret",
+"Pallas' Bunting"=>"Emberiza pallasi",
+"Ferruginous Duck"=>"Aythya nyroca",
+"Whistling Swan"=>"Cygnus columbianus",
+"Black Brant"=>"Branta nigricans",
+"Marbled Teal"=>"Marmaronetta angustirostris",
+"Canvasback"=>"Aythya valisineria",
+"Redhead"=>"Aythya americana",
+"Lesser Scaup"=>"Aythya affinis",
+"Steller`s Eider"=>"Polysticta stelleri",
+"Spectacled Eider"=>"Somateria fischeri",
+"Harlequin Duck"=>"Histronicus histrionicus",
+"Black Scoter"=>"Melanitta americana",
+"Surf Scoter"=>"Melanitta perspicillata",
+"Barrow`s Goldeneye"=>"Bucephala islandica",
+"Falcated Duck"=>"Anas falcata",
+"American Wigeon"=>"Anas americana",
+"Blue-winged Teal"=>"Anas discors",
+"American Black Duck"=>"Anas rubripes",
+"Baikal Teal"=>"Anas formosa",
+"Green-Winged Teal"=>"Anas carolinensis",
+"Hazel Grouse"=>"Bonasa bonasia",
+"Rock Partridge"=>"Alectoris graeca",
+"Red-legged Partridge"=>"Alectoris rufa",
+"Yellow-billed Loon"=>"Gavia adamsii",
+"Cory`s Shearwater"=>"Calonectris borealis",
+"Madeiran Storm-Petrel"=>"Oceanodroma castro",
+"Great White Pelican"=>"Pelecanus onocrotalus",
+"Dalmatian Pelican"=>"Pelecanus crispus",
+"American Bittern"=>"Botaurus lentiginosus",
+"Glossy Ibis"=>"Plegadis falcinellus",
+"Spanish Imperial Eagle"=>"Aquila adalberti",
+"Lesser Kestrel"=>"Falco naumanni",
+"Houbara Bustard"=>"Chlamydotis undulata",
+"Crab-Plover"=>"Dromas ardeola",
+"Cream-coloured Courser"=>"Cursorius cursor",
+"Collared Pratincole"=>"Glareola pratincola",
+"Black-winged Pratincole"=>"Glareola nordmanni",
+"Killdeer"=>"Charadrius vociferus",
+"Lesser Sand Plover"=>"Charadrius mongolus",
+"Greater Sand Plover"=>"Charadrius leschenaultii",
+"Caspian Plover"=>"Charadrius asiaticus",
+"American Golden Plover"=>"Pluvialis dominica",
+"Pacific Golden Plover"=>"Pluvialis fulva",
+"Sharp-tailed Sandpiper"=>"Calidris acuminata",
+"Broad-billed Sandpiper"=>"Limicola falcinellus",
+"Spoon-Billed Sandpiper"=>"Eurynorhynchus pygmaeus",
+"Short-Billed Dowitcher"=>"Limnodromus griseus",
+"Long-billed Dowitcher"=>"Limnodromus scolopaceus",
+"Hudsonian Godwit"=>"Limosa haemastica",
+"Little Curlew"=>"Numenius minutus",
+"Lesser Yellowlegs"=>"Tringa flavipes",
+"Wilson`s Phalarope"=>"Phalaropus tricolor",
+"Pallas`s Gull"=>"Larus ichthyaetus",
+"Laughing Gull"=>"Larus atricilla",
+"Franklin`s Gull"=>"Larus pipixcan",
+"Bonaparte`s Gull"=>"Larus philadelphia",
+"Ring-billed Gull"=>"Larus delawarensis",
+"American Herring Gull"=>"Larus smithsonianus",
+"Caspian Gull"=>"Larus cachinnans",
+"Ivory Gull"=>"Pagophila eburnea",
+"Royal Tern"=>"Sterna maxima",
+"Brünnich`s Murre"=>"Uria lomvia",
+"Crested Auklet"=>"Aethia cristatella",
+"Parakeet Auklet"=>"Cyclorrhynchus psittacula",
+"Tufted Puffin"=>"Lunda cirrhata",
+"Laughing Dove"=>"Streptopelia senegalensis",
+"Great Spotted Cuckoo"=>"Clamator glandarius",
+"Great Grey Owl"=>"Strix nebulosa",
+"Tengmalm`s Owl"=>"Aegolius funereus",
+"Red-Necked Nightjar"=>"Caprimulgus ruficollis",
+"Chimney Swift"=>"Chaetura pelagica",
+"Green Bea-Eater"=>"Merops orientalis",
+"Grey-headed Woodpecker"=>"Picus canus",
+"Lesser Short-Toed Lark"=>"Calandrella rufescens",
+"Eurasian Crag Martin"=>"Hirundo rupestris",
+"Red-rumped Swallow"=>"Cecropis daurica",
+"Blyth`s Pipit"=>"Anthus godlewskii",
+"Pechora Pipit"=>"Anthus gustavi",
+"Grey-headed Wagtail"=>"Motacilla thunbergi",
+"Yellow-Headed Wagtail"=>"Motacilla lutea",
+"White-throated Dipper"=>"Cinclus cinclus",
+"Rufous-Tailed Scrub Robin"=>"Cercotrichas galactotes",
+"Thrush Nightingale"=>"Luscinia luscinia",
+"White-throated Robin"=>"Irania gutturalis",
+"Caspian Stonechat"=>"Saxicola maura variegata",
+"Western Black-eared Wheatear"=>"Oenanthe hispanica",
+"Rufous-tailed Rock Thrush"=>"Monticola saxatilis",
+"Red-throated Thrush/Black-throated"=>"Turdus ruficollis",
+"American Robin"=>"Turdus migratorius",
+"Zitting Cisticola"=>"Cisticola juncidis",
+"Lanceolated Warbler"=>"Locustella lanceolata",
+"River Warbler"=>"Locustella fluviatilis",
+"Blyth`s Reed Warbler"=>"Acrocephalus dumetorum",
+"Caspian Reed Warbler"=>"Acrocephalus fuscus",
+"Aquatic Warbler"=>"Acrocephalus paludicola",
+"Booted Warbler"=>"Acrocephalus caligatus",
+"Marmora's Warbler"=>"Sylvia sarda",
+"Dartford Warbler"=>"Sylvia undata",
+"Subalpine Warbler"=>"Sylvia cantillans",
+"Ménétries's Warbler"=>"Sylvia mystacea",
+"Rüppel's Warbler"=>"Sylvia rueppelli",
+"Asian Desert Warbler"=>"Sylvia nana",
+"Western Orphean Warbler"=>"Sylvia hortensis hortensis",
+"Arctic Warbler"=>"Phylloscopus borealis",
+"Radde`s Warbler"=>"Phylloscopus schwarzi",
+"Western Bonelli`s Warbler"=>"Phylloscopus bonelli",
+"Red-breasted Flycatcher"=>"Ficedula parva",
+"Eurasian Penduline Tit"=>"Remiz pendulinus",
+"Daurian Shrike"=>"Lanius isabellinus",
+"Long-Tailed Shrike"=>"Lanius schach",
+"Lesser Grey Shrike"=>"Lanius minor",
+"Southern Grey Shrike"=>"Lanius meridionalis",
+"Masked Shrike"=>"Lanius nubicus",
+"Spotted Nutcracker"=>"Nucifraga caryocatactes",
+"Daurian Jackdaw"=>"Corvus dauuricus",
+"Purple-Backed Starling"=>"Sturnus sturninus",
+"Red-Fronted Serin"=>"Serinus pusillus",
+"Arctic Redpoll"=>"Carduelis hornemanni",
+"Scottish Crossbill"=>"Loxia scotica",
+"Parrot Crossbill"=>"Loxia pytyopsittacus",
+"Black-faced Bunting"=>"Emberiza spodocephala",
+"Pink-footed Goose"=>"Anser brachyrhynchus",
+"Black-winged Kite"=>"Elanus caeruleus",
+"European Bee-eater"=>"Merops apiaster",
+"Sabine`s Gull"=>"Larus sabini",
+"Sooty Shearwater"=>"Puffinus griseus",
+"Lesser Canada Goose"=>"Branta hutchinsii",
+"Ring-necked Duck"=>"Aythya collaris",
+"Greater Flamingo"=>"Phoenicopterus roseus",
+"Iberian Chiffchaff"=>"Phylloscopus ibericus",
+"Ashy-headed Wagtail"=>"Motacilla cinereocapilla",
+"Stilt Sandpiper"=>"Calidris himantopus",
+"Siberian Stonechat"=>"Saxicola maurus",
+"Greater Yellowlegs"=>"Tringa melanoleuca",
+"Forster`s Tern"=>"Sterna forsteri",
+"Dusky Warbler"=>"Phylloscopus fuscatus",
+"Cirl Bunting"=>"Emberiza cirlus",
+"Olive-backed Pipit"=>"Anthus hodgsoni",
+"Sociable Lapwing"=>"Vanellus gregarius",
+"Spotted Sandpiper"=>"Actitis macularius",
+"Baird`s Sandpiper"=>"Calidris bairdii",
+"Rustic Bunting"=>"Emberiza rustica",
+"Yellow-browed Bunting"=>"Emberiza chrysophrys",
+"Great Shearwater"=>"Puffinus gravis",
+"Bonelli`s Eagle"=>"Aquila fasciata",
+"Calandra Lark"=>"Melanocorypha calandra",
+"Sardinian Warbler"=>"Sylvia melanocephala",
+"Ross's Gull"=>"Larus roseus",
+"Yellow-Breasted Bunting"=>"Emberiza aureola",
+"Pine Bunting"=>"Emberiza leucocephalos",
+"Black Guillemot"=>"Cepphus grylle",
+"Pied-billed Grebe"=>"Podilymbus podiceps",
+"Soft-plumaged Petrel"=>"Pterodroma mollis",
+"Bulwer's Petrel"=>"Bulweria bulwerii",
+"White-Faced Storm-Petrel"=>"Pelagodroma marina",
+"Pallas’s Fish Eagle"=>"Haliaeetus leucoryphus",
+"Sandhill Crane"=>"Grus canadensis",
+"Macqueen’s Bustard"=>"Chlamydotis macqueenii",
+"White-tailed Lapwing"=>"Vanellus leucurus",
+"Great Knot"=>"Calidris tenuirostris",
+"Semipalmated Sandpiper"=>"Calidris pusilla",
+"Red-necked Stint"=>"Calidris ruficollis",
+"Slender-billed Curlew"=>"Numenius tenuirostris",
+"Bridled Tern"=>"Onychoprion anaethetus",
+"Pallas’s Sandgrouse"=>"Syrrhaptes paradoxus",
+"European Scops Owl"=>"Otus scops",
+"Northern Hawk Owl"=>"Surnia ulula",
+"White-Throated Needletail"=>"Hirundapus caudacutus",
+"Belted Kingfisher"=>"Ceryle alcyon",
+"Blue-cheeked Bee-eater"=>"Merops persicus",
+"Black-headed Wagtail"=>"Motacilla feldegg",
+"Northern Mockingbird"=>"Mimus polyglottos",
+"Alpine Accentor"=>"Prunella collaris",
+"Red-flanked Bluetail"=>"Tarsiger cyanurus",
+"Isabelline Wheatear"=>"Oenanthe isabellina",
+"Pied Wheatear"=>"Oenanthe pleschanka",
+"Eastern Black-eared Wheatear"=>"Oenanthe melanoleuca",
+"Desert Wheatear"=>"Oenanthe deserti",
+"White`s Thrush"=>"Zoothera aurea",
+"Siberian Thrush"=>"Zoothera sibirica",
+"Eyebrowed Thrush"=>"Turdus obscurus",
+"Dusky Thrush"=>"Turdus eunomus",
+"Black-throated Thrush"=>"Turdus atrogularis",
+"Pallas`s Grasshopper Warbler"=>"Locustella certhiola",
+"Spectacled Warbler"=>"Sylvia conspicillata",
+"Two-barred Warbler"=>"Phylloscopus plumbeitarsus",
+"Eastern Bonelli’s Warbler"=>"Phylloscopus orientalis",
+"Collared Flycatcher"=>"Ficedula albicollis",
+"Wallcreeper"=>"Tichodroma muraria",
+"Turkestan Shrike"=>"Lanius phoenicuroides",
+"Steppe Grey Shrike"=>"Lanius pallidirostris",
+"Spanish Sparrow"=>"Passer hispaniolensis",
+"Red-eyed Vireo"=>"Vireo olivaceus",
+"Myrtle Warbler"=>"Dendroica coronata",
+"White-crowned Sparrow"=>"Zonotrichia leucophrys",
+"White-throated Sparrow"=>"Zonotrichia albicollis",
+"Cretzschmar`s Bunting"=>"Emberiza caesia",
+"Chestnut Bunting"=>"Emberiza rutila",
+"Red-headed Bunting"=>"Emberiza bruniceps",
+"Black-headed Bunting"=>"Emberiza melanocephala",
+"Indigo Bunting"=>"Passerina cyanea",
+"Balearic Woodchat Shrike"=>"Lanius senator badius",
+"Demoiselle Crane"=>"Grus virgo",
+"Chough"=>"Pyrrhocorax pyrrhocorax",
+"Red-Billed Chough"=>"Pyrrhocorax graculus",
+"Elegant Tern"=>"Sterna elegans",
+"Chukar"=>"Alectoris chukar",
+"Yellow-Billed Cuckoo"=>"Coccyzus americanus",
+"American Sandwich Tern"=>"Sterna sandvicensis acuflavida",
+"Olive-Tree Warbler"=>"Hippolais olivetorum",
+"Eastern Olivaceous Warbler"=>"Acrocephalus pallidus",
+"Indian Cormorant"=>"Phalacrocorax fuscicollis",
+"Spur-Winged Lapwing"=>"Vanellus spinosus",
+"Yelkouan Shearwater"=>"Puffinus yelkouan",
+"Trumpeter Finch"=>"Bucanetes githagineus",
+"Red Grouse"=>"Lagopus scoticus",
+"Rock Ptarmigan"=>"Lagopus mutus",
+"Long-Tailed Cormorant"=>"Phalacrocorax africanus",
+"Double-crested Cormorant"=>"Phalacrocorax auritus",
+"Magnificent Frigatebird"=>"Fregata magnificens",
+"Naumann's Thrush"=>"Turdus naumanni",
+"Oriental Pratincole"=>"Glareola maldivarum",
+"Bufflehead"=>"Bucephala albeola",
+"Snowfinch"=>"Montifrigilla nivalis",
+"Ural owl"=>"Strix uralensis",
+"Spanish Wagtail"=>"Motacilla iberiae",
+"Song Sparrow"=>"Melospiza melodia",
+"Rock Bunting"=>"Emberiza cia",
+"Siberian Rubythroat"=>"Luscinia calliope",
+"Pallid Swift"=>"Apus pallidus",
+"Eurasian Pygmy Owl"=>"Glaucidium passerinum",
+"Madeira Little Shearwater"=>"Puffinus baroli",
+"House Finch"=>"Carpodacus mexicanus",
+"Green Heron"=>"Butorides virescens",
+"Solitary Sandpiper"=>"Tringa solitaria",
+"Heuglin's Gull"=>"Larus heuglini"
+);
+
+foreach ($items as $key=>$value) {
+ if (strpos(strtolower($key), $q) !== false) {
+ echo "$key|$value\n";
+ }
+}
+
+?>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/jquery.autocomplete.css Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,48 @@
+.ac_results {
+ padding: 0px;
+ border: 1px solid #333333;
+ background-color: white;
+ overflow: hidden;
+ z-index: 99999;
+}
+
+.ac_results ul {
+ width: 100%;
+ list-style-position: outside;
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.ac_results li {
+ margin: 0px;
+ padding: 2px 5px;
+ cursor: default;
+ display: block;
+ /*
+ if width will be 100% horizontal scrollbar will apear
+ when scroll mode will be used
+ */
+ /*width: 100%;*/
+ font: menu;
+ font-size: 12px;
+ /*
+ it is very important, if line-height not setted or setted
+ in relative units scroll will be broken in firefox
+ */
+ line-height: 16px;
+ overflow: hidden;
+}
+
+.ac_loading {
+ /*background: white url('indicator.gif') right center no-repeat;*/
+}
+
+.ac_odd {
+ background-color: #666;
+}
+
+.ac_over {
+ background-color: #333;
+ color: white;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/jquery.autocomplete.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,808 @@
+/*
+ * jQuery Autocomplete plugin 1.1
+ *
+ * Copyright (c) 2009 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ */
+
+;(function($) {
+
+$.fn.extend({
+ autocomplete: function(urlOrData, options) {
+ var isUrl = typeof urlOrData == "string";
+ options = $.extend({}, $.Autocompleter.defaults, {
+ url: isUrl ? urlOrData : null,
+ data: isUrl ? null : urlOrData,
+ delay: isUrl ? $.Autocompleter.defaults.delay : 10,
+ max: options && !options.scroll ? 10 : 150
+ }, options);
+
+ // if highlight is set to false, replace it with a do-nothing function
+ options.highlight = options.highlight || function(value) { return value; };
+
+ // if the formatMatch option is not specified, then use formatItem for backwards compatibility
+ options.formatMatch = options.formatMatch || options.formatItem;
+
+ return this.each(function() {
+ new $.Autocompleter(this, options);
+ });
+ },
+ result: function(handler) {
+ return this.bind("result", handler);
+ },
+ search: function(handler) {
+ return this.trigger("search", [handler]);
+ },
+ flushCache: function() {
+ return this.trigger("flushCache");
+ },
+ setOptions: function(options){
+ return this.trigger("setOptions", [options]);
+ },
+ unautocomplete: function() {
+ return this.trigger("unautocomplete");
+ }
+});
+
+$.Autocompleter = function(input, options) {
+
+ var KEY = {
+ UP: 38,
+ DOWN: 40,
+ DEL: 46,
+ TAB: 9,
+ RETURN: 13,
+ ESC: 27,
+ COMMA: 188,
+ PAGEUP: 33,
+ PAGEDOWN: 34,
+ BACKSPACE: 8
+ };
+
+ // Create $ object for input element
+ var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
+
+ var timeout;
+ var previousValue = "";
+ var cache = $.Autocompleter.Cache(options);
+ var hasFocus = 0;
+ var lastKeyPressCode;
+ var config = {
+ mouseDownOnSelect: false
+ };
+ var select = $.Autocompleter.Select(options, input, selectCurrent, config);
+
+ var blockSubmit;
+
+ // prevent form submit in opera when selecting with return key
+ $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
+ if (blockSubmit) {
+ blockSubmit = false;
+ return false;
+ }
+ });
+
+ // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
+ $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
+ // a keypress means the input has focus
+ // avoids issue where input had focus before the autocomplete was applied
+ hasFocus = 1;
+ // track last key pressed
+ lastKeyPressCode = event.keyCode;
+ switch(event.keyCode) {
+
+ case KEY.UP:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.prev();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.DOWN:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.next();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.PAGEUP:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.pageUp();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.PAGEDOWN:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.pageDown();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ // matches also semicolon
+ case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
+ case KEY.TAB:
+ case KEY.RETURN:
+ if( selectCurrent() ) {
+ // stop default to prevent a form submit, Opera needs special handling
+ event.preventDefault();
+ blockSubmit = true;
+ return false;
+ }
+ break;
+
+ case KEY.ESC:
+ select.hide();
+ break;
+
+ default:
+ clearTimeout(timeout);
+ timeout = setTimeout(onChange, options.delay);
+ break;
+ }
+ }).focus(function(){
+ // track whether the field has focus, we shouldn't process any
+ // results if the field no longer has focus
+ hasFocus++;
+ }).blur(function() {
+ hasFocus = 0;
+ if (!config.mouseDownOnSelect) {
+ hideResults();
+ }
+ }).click(function() {
+ // show select when clicking in a focused field
+ if ( hasFocus++ > 1 && !select.visible() ) {
+ onChange(0, true);
+ }
+ }).bind("search", function() {
+ // TODO why not just specifying both arguments?
+ var fn = (arguments.length > 1) ? arguments[1] : null;
+ function findValueCallback(q, data) {
+ var result;
+ if( data && data.length ) {
+ for (var i=0; i < data.length; i++) {
+ if( data[i].result.toLowerCase() == q.toLowerCase() ) {
+ result = data[i];
+ break;
+ }
+ }
+ }
+ if( typeof fn == "function" ) fn(result);
+ else $input.trigger("result", result && [result.data, result.value]);
+ }
+ $.each(trimWords($input.val()), function(i, value) {
+ request(value, findValueCallback, findValueCallback);
+ });
+ }).bind("flushCache", function() {
+ cache.flush();
+ }).bind("setOptions", function() {
+ $.extend(options, arguments[1]);
+ // if we've updated the data, repopulate
+ if ( "data" in arguments[1] )
+ cache.populate();
+ }).bind("unautocomplete", function() {
+ select.unbind();
+ $input.unbind();
+ $(input.form).unbind(".autocomplete");
+ });
+
+
+ function selectCurrent() {
+ var selected = select.selected();
+ if( !selected )
+ return false;
+
+ var v = selected.result;
+ previousValue = v;
+
+ if ( options.multiple ) {
+ var words = trimWords($input.val());
+ if ( words.length > 1 ) {
+ var seperator = options.multipleSeparator.length;
+ var cursorAt = $(input).selection().start;
+ var wordAt, progress = 0;
+ $.each(words, function(i, word) {
+ progress += word.length;
+ if (cursorAt <= progress) {
+ wordAt = i;
+ return false;
+ }
+ progress += seperator;
+ });
+ words[wordAt] = v;
+ // TODO this should set the cursor to the right position, but it gets overriden somewhere
+ //$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
+ v = words.join( options.multipleSeparator );
+ }
+ v += options.multipleSeparator;
+ }
+
+ $input.val(v);
+ hideResultsNow();
+ $input.trigger("result", [selected.data, selected.value]);
+ return true;
+ }
+
+ function onChange(crap, skipPrevCheck) {
+ if( lastKeyPressCode == KEY.DEL ) {
+ select.hide();
+ return;
+ }
+
+ var currentValue = $input.val();
+
+ if ( !skipPrevCheck && currentValue == previousValue )
+ return;
+
+ previousValue = currentValue;
+
+ currentValue = lastWord(currentValue);
+ if ( currentValue.length >= options.minChars) {
+ $input.addClass(options.loadingClass);
+ if (!options.matchCase)
+ currentValue = currentValue.toLowerCase();
+ request(currentValue, receiveData, hideResultsNow);
+ } else {
+ stopLoading();
+ select.hide();
+ }
+ };
+
+ function trimWords(value) {
+ if (!value)
+ return [""];
+ if (!options.multiple)
+ return [$.trim(value)];
+ return $.map(value.split(options.multipleSeparator), function(word) {
+ return $.trim(value).length ? $.trim(word) : null;
+ });
+ }
+
+ function lastWord(value) {
+ if ( !options.multiple )
+ return value;
+ var words = trimWords(value);
+ if (words.length == 1)
+ return words[0];
+ var cursorAt = $(input).selection().start;
+ if (cursorAt == value.length) {
+ words = trimWords(value)
+ } else {
+ words = trimWords(value.replace(value.substring(cursorAt), ""));
+ }
+ return words[words.length - 1];
+ }
+
+ // fills in the input box w/the first match (assumed to be the best match)
+ // q: the term entered
+ // sValue: the first matching result
+ function autoFill(q, sValue){
+ // autofill in the complete box w/the first match as long as the user hasn't entered in more data
+ // if the last user key pressed was backspace, don't autofill
+ if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
+ // fill in the value (keep the case the user has typed)
+ $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
+ // select the portion of the value not typed by the user (so the next character will erase)
+ $(input).selection(previousValue.length, previousValue.length + sValue.length);
+ }
+ };
+
+ function hideResults() {
+ clearTimeout(timeout);
+ timeout = setTimeout(hideResultsNow, 200);
+ };
+
+ function hideResultsNow() {
+ var wasVisible = select.visible();
+ select.hide();
+ clearTimeout(timeout);
+ stopLoading();
+ if (options.mustMatch) {
+ // call search and run callback
+ $input.search(
+ function (result){
+ // if no value found, clear the input box
+ if( !result ) {
+ if (options.multiple) {
+ var words = trimWords($input.val()).slice(0, -1);
+ $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
+ }
+ else {
+ $input.val( "" );
+ $input.trigger("result", null);
+ }
+ }
+ }
+ );
+ }
+ };
+
+ function receiveData(q, data) {
+ if ( data && data.length && hasFocus ) {
+ stopLoading();
+ select.display(data, q);
+ autoFill(q, data[0].value);
+ select.show();
+ } else {
+ hideResultsNow();
+ }
+ };
+
+ function request(term, success, failure) {
+ if (!options.matchCase)
+ term = term.toLowerCase();
+ var data = cache.load(term);
+ // recieve the cached data
+ if (data && data.length) {
+ success(term, data);
+ // if an AJAX url has been supplied, try loading the data now
+ } else if( (typeof options.url == "string") && (options.url.length > 0) ){
+
+ var extraParams = {
+ timestamp: +new Date()
+ };
+ $.each(options.extraParams, function(key, param) {
+ extraParams[key] = typeof param == "function" ? param() : param;
+ });
+
+ $.ajax({
+ // try to leverage ajaxQueue plugin to abort previous requests
+ mode: "abort",
+ // limit abortion to this input
+ port: "autocomplete" + input.name,
+ dataType: options.dataType,
+ url: options.url,
+ data: $.extend({
+ q: lastWord(term),
+ limit: options.max
+ }, extraParams),
+ success: function(data) {
+ var parsed = options.parse && options.parse(data) || parse(data);
+ cache.add(term, parsed);
+ success(term, parsed);
+ }
+ });
+ } else {
+ // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
+ select.emptyList();
+ failure(term);
+ }
+ };
+
+ function parse(data) {
+ var parsed = [];
+ var rows = data.split("\n");
+ for (var i=0; i < rows.length; i++) {
+ var row = $.trim(rows[i]);
+ if (row) {
+ row = row.split("|");
+ parsed[parsed.length] = {
+ data: row,
+ value: row[0],
+ result: options.formatResult && options.formatResult(row, row[0]) || row[0]
+ };
+ }
+ }
+ return parsed;
+ };
+
+ function stopLoading() {
+ $input.removeClass(options.loadingClass);
+ };
+
+};
+
+$.Autocompleter.defaults = {
+ inputClass: "ac_input",
+ resultsClass: "ac_results",
+ loadingClass: "ac_loading",
+ minChars: 1,
+ delay: 400,
+ matchCase: false,
+ matchSubset: true,
+ matchContains: false,
+ cacheLength: 10,
+ max: 100,
+ mustMatch: false,
+ extraParams: {},
+ selectFirst: true,
+ formatItem: function(row) { return row[0]; },
+ formatMatch: null,
+ autoFill: false,
+ width: 0,
+ multiple: false,
+ multipleSeparator: ", ",
+ highlight: function(value, term) {
+ return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
+ },
+ scroll: true,
+ scrollHeight: 180
+};
+
+$.Autocompleter.Cache = function(options) {
+
+ var data = {};
+ var length = 0;
+
+ function matchSubset(s, sub) {
+ if (!options.matchCase)
+ s = s.toLowerCase();
+ var i = s.indexOf(sub);
+ if (options.matchContains == "word"){
+ i = s.toLowerCase().search("\\b" + sub.toLowerCase());
+ }
+ if (i == -1) return false;
+ return i == 0 || options.matchContains;
+ };
+
+ function add(q, value) {
+ if (length > options.cacheLength){
+ flush();
+ }
+ if (!data[q]){
+ length++;
+ }
+ data[q] = value;
+ }
+
+ function populate(){
+ if( !options.data ) return false;
+ // track the matches
+ var stMatchSets = {},
+ nullData = 0;
+
+ // no url was specified, we need to adjust the cache length to make sure it fits the local data store
+ if( !options.url ) options.cacheLength = 1;
+
+ // track all options for minChars = 0
+ stMatchSets[""] = [];
+
+ // loop through the array and create a lookup structure
+ for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
+ var rawValue = options.data[i];
+ // if rawValue is a string, make an array otherwise just reference the array
+ rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
+
+ var value = options.formatMatch(rawValue, i+1, options.data.length);
+ if ( value === false )
+ continue;
+
+ var firstChar = value.charAt(0).toLowerCase();
+ // if no lookup array for this character exists, look it up now
+ if( !stMatchSets[firstChar] )
+ stMatchSets[firstChar] = [];
+
+ // if the match is a string
+ var row = {
+ value: value,
+ data: rawValue,
+ result: options.formatResult && options.formatResult(rawValue) || value
+ };
+
+ // push the current match into the set list
+ stMatchSets[firstChar].push(row);
+
+ // keep track of minChars zero items
+ if ( nullData++ < options.max ) {
+ stMatchSets[""].push(row);
+ }
+ };
+
+ // add the data items to the cache
+ $.each(stMatchSets, function(i, value) {
+ // increase the cache size
+ options.cacheLength++;
+ // add to the cache
+ add(i, value);
+ });
+ }
+
+ // populate any existing data
+ setTimeout(populate, 25);
+
+ function flush(){
+ data = {};
+ length = 0;
+ }
+
+ return {
+ flush: flush,
+ add: add,
+ populate: populate,
+ load: function(q) {
+ if (!options.cacheLength || !length)
+ return null;
+ /*
+ * if dealing w/local data and matchContains than we must make sure
+ * to loop through all the data collections looking for matches
+ */
+ if( !options.url && options.matchContains ){
+ // track all matches
+ var csub = [];
+ // loop through all the data grids for matches
+ for( var k in data ){
+ // don't search through the stMatchSets[""] (minChars: 0) cache
+ // this prevents duplicates
+ if( k.length > 0 ){
+ var c = data[k];
+ $.each(c, function(i, x) {
+ // if we've got a match, add it to the array
+ if (matchSubset(x.value, q)) {
+ csub.push(x);
+ }
+ });
+ }
+ }
+ return csub;
+ } else
+ // if the exact item exists, use it
+ if (data[q]){
+ return data[q];
+ } else
+ if (options.matchSubset) {
+ for (var i = q.length - 1; i >= options.minChars; i--) {
+ var c = data[q.substr(0, i)];
+ if (c) {
+ var csub = [];
+ $.each(c, function(i, x) {
+ if (matchSubset(x.value, q)) {
+ csub[csub.length] = x;
+ }
+ });
+ return csub;
+ }
+ }
+ }
+ return null;
+ }
+ };
+};
+
+$.Autocompleter.Select = function (options, input, select, config) {
+ var CLASSES = {
+ ACTIVE: "ac_over"
+ };
+
+ var listItems,
+ active = -1,
+ data,
+ term = "",
+ needsInit = true,
+ element,
+ list;
+
+ // Create results
+ function init() {
+ if (!needsInit)
+ return;
+ element = $("<div/>")
+ .hide()
+ .addClass(options.resultsClass)
+ .css("position", "absolute")
+ .appendTo(document.body);
+
+ list = $("<ul/>").appendTo(element).mouseover( function(event) {
+ if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
+ active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
+ $(target(event)).addClass(CLASSES.ACTIVE);
+ }
+ }).click(function(event) {
+ $(target(event)).addClass(CLASSES.ACTIVE);
+ select();
+ // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
+ input.focus();
+ return false;
+ }).mousedown(function() {
+ config.mouseDownOnSelect = true;
+ }).mouseup(function() {
+ config.mouseDownOnSelect = false;
+ });
+
+ if( options.width > 0 )
+ element.css("width", options.width);
+
+ needsInit = false;
+ }
+
+ function target(event) {
+ var element = event.target;
+ while(element && element.tagName != "LI")
+ element = element.parentNode;
+ // more fun with IE, sometimes event.target is empty, just ignore it then
+ if(!element)
+ return [];
+ return element;
+ }
+
+ function moveSelect(step) {
+ listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
+ movePosition(step);
+ var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
+ if(options.scroll) {
+ var offset = 0;
+ listItems.slice(0, active).each(function() {
+ offset += this.offsetHeight;
+ });
+ if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
+ list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
+ } else if(offset < list.scrollTop()) {
+ list.scrollTop(offset);
+ }
+ }
+ };
+
+ function movePosition(step) {
+ active += step;
+ if (active < 0) {
+ active = listItems.size() - 1;
+ } else if (active >= listItems.size()) {
+ active = 0;
+ }
+ }
+
+ function limitNumberOfItems(available) {
+ return options.max && options.max < available
+ ? options.max
+ : available;
+ }
+
+ function fillList() {
+ list.empty();
+ var max = limitNumberOfItems(data.length);
+ for (var i=0; i < max; i++) {
+ if (!data[i])
+ continue;
+ var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
+ if ( formatted === false )
+ continue;
+ var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
+ $.data(li, "ac_data", data[i]);
+ }
+ listItems = list.find("li");
+ if ( options.selectFirst ) {
+ listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
+ active = 0;
+ }
+ // apply bgiframe if available
+ if ( $.fn.bgiframe )
+ list.bgiframe();
+ }
+
+ return {
+ display: function(d, q) {
+ init();
+ data = d;
+ term = q;
+ fillList();
+ },
+ next: function() {
+ moveSelect(1);
+ },
+ prev: function() {
+ moveSelect(-1);
+ },
+ pageUp: function() {
+ if (active != 0 && active - 8 < 0) {
+ moveSelect( -active );
+ } else {
+ moveSelect(-8);
+ }
+ },
+ pageDown: function() {
+ if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
+ moveSelect( listItems.size() - 1 - active );
+ } else {
+ moveSelect(8);
+ }
+ },
+ hide: function() {
+ element && element.hide();
+ listItems && listItems.removeClass(CLASSES.ACTIVE);
+ active = -1;
+ },
+ visible : function() {
+ return element && element.is(":visible");
+ },
+ current: function() {
+ return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
+ },
+ show: function() {
+ var offset = $(input).offset();
+ element.css({
+ width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
+ top: offset.top + input.offsetHeight,
+ left: offset.left
+ }).show();
+ if(options.scroll) {
+ list.scrollTop(0);
+ list.css({
+ maxHeight: options.scrollHeight,
+ overflow: 'auto'
+ });
+
+ if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
+ var listHeight = 0;
+ listItems.each(function() {
+ listHeight += this.offsetHeight;
+ });
+ var scrollbarsVisible = listHeight > options.scrollHeight;
+ list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
+ if (!scrollbarsVisible) {
+ // IE doesn't recalculate width when scrollbar disappears
+ listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
+ }
+ }
+
+ }
+ },
+ selected: function() {
+ var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
+ return selected && selected.length && $.data(selected[0], "ac_data");
+ },
+ emptyList: function (){
+ list && list.empty();
+ },
+ unbind: function() {
+ element && element.remove();
+ }
+ };
+};
+
+$.fn.selection = function(start, end) {
+ if (start !== undefined) {
+ return this.each(function() {
+ if( this.createTextRange ){
+ var selRange = this.createTextRange();
+ if (end === undefined || start == end) {
+ selRange.move("character", start);
+ selRange.select();
+ } else {
+ selRange.collapse(true);
+ selRange.moveStart("character", start);
+ selRange.moveEnd("character", end);
+ selRange.select();
+ }
+ } else if( this.setSelectionRange ){
+ this.setSelectionRange(start, end);
+ } else if( this.selectionStart ){
+ this.selectionStart = start;
+ this.selectionEnd = end;
+ }
+ });
+ }
+ var field = this[0];
+ if ( field.createTextRange ) {
+ var range = document.selection.createRange(),
+ orig = field.value,
+ teststring = "<->",
+ textLength = range.text.length;
+ range.text = teststring;
+ var caretAt = field.value.indexOf(teststring);
+ field.value = orig;
+ this.selection(caretAt, caretAt + textLength);
+ return {
+ start: caretAt,
+ end: caretAt + textLength
+ }
+ } else if( field.selectionStart !== undefined ){
+ return {
+ start: field.selectionStart,
+ end: field.selectionEnd
+ }
+ }
+};
+
+})(jQuery);
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/jquery.autocomplete.min.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,13 @@
+/*
+ * jQuery Autocomplete plugin 1.1
+ *
+ * Copyright (c) 2009 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ */;(function($){$.fn.extend({autocomplete:function(urlOrData,options){var isUrl=typeof urlOrData=="string";options=$.extend({},$.Autocompleter.defaults,{url:isUrl?urlOrData:null,data:isUrl?null:urlOrData,delay:isUrl?$.Autocompleter.defaults.delay:10,max:options&&!options.scroll?10:150},options);options.highlight=options.highlight||function(value){return value;};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new $.Autocompleter(this,options);});},result:function(handler){return this.bind("result",handler);},search:function(handler){return this.trigger("search",[handler]);},flushCache:function(){return this.trigger("flushCache");},setOptions:function(options){return this.trigger("setOptions",[options]);},unautocomplete:function(){return this.trigger("unautocomplete");}});$.Autocompleter=function(input,options){var KEY={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var $input=$(input).attr("autocomplete","off").addClass(options.inputClass);var timeout;var previousValue="";var cache=$.Autocompleter.Cache(options);var hasFocus=0;var lastKeyPressCode;var config={mouseDownOnSelect:false};var select=$.Autocompleter.Select(options,input,selectCurrent,config);var blockSubmit;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){hasFocus=1;lastKeyPressCode=event.keyCode;switch(event.keyCode){case KEY.UP:event.preventDefault();if(select.visible()){select.prev();}else{onChange(0,true);}break;case KEY.DOWN:event.preventDefault();if(select.visible()){select.next();}else{onChange(0,true);}break;case KEY.PAGEUP:event.preventDefault();if(select.visible()){select.pageUp();}else{onChange(0,true);}break;case KEY.PAGEDOWN:event.preventDefault();if(select.visible()){select.pageDown();}else{onChange(0,true);}break;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i<data.length;i++){if(data[i].result.toLowerCase()==q.toLowerCase()){result=data[i];break;}}}if(typeof fn=="function")fn(result);else $input.trigger("result",result&&[result.data,result.value]);}$.each(trimWords($input.val()),function(i,value){request(value,findValueCallback,findValueCallback);});}).bind("flushCache",function(){cache.flush();}).bind("setOptions",function(){$.extend(options,arguments[1]);if("data"in arguments[1])cache.populate();}).bind("unautocomplete",function(){select.unbind();$input.unbind();$(input.form).unbind(".autocomplete");});function selectCurrent(){var selected=select.selected();if(!selected)return false;var v=selected.result;previousValue=v;if(options.multiple){var words=trimWords($input.val());if(words.length>1){var seperator=options.multipleSeparator.length;var cursorAt=$(input).selection().start;var wordAt,progress=0;$.each(words,function(i,word){progress+=word.length;if(cursorAt<=progress){wordAt=i;return false;}progress+=seperator;});words[wordAt]=v;v=words.join(options.multipleSeparator);}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&¤tValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value)return[""];if(!options.multiple)return[$.trim(value)];return $.map(value.split(options.multipleSeparator),function(word){return $.trim(value).length?$.trim(word):null;});}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);if(words.length==1)return words[0];var cursorAt=$(input).selection().start;if(cursorAt==value.length){words=trimWords(value)}else{words=trimWords(value.replace(value.substring(cursorAt),""));}return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$(input).selection(previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else{$input.val("");$input.trigger("result",null);}}});}};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i<rows.length;i++){var row=$.trim(rows[i]);if(row){row=row.split("|");parsed[parsed.length]={data:row,value:row[0],result:options.formatResult&&options.formatResult(row,row[0])||row[0]};}}return parsed;};function stopLoading(){$input.removeClass(options.loadingClass);};};$.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(row){return row[0];},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(value,term){return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(options.matchContains=="word"){i=s.toLowerCase().search("\\b"+sub.toLowerCase());}if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];rawValue=(typeof rawValue=="string")?[rawValue]:rawValue;var value=options.formatMatch(rawValue,i+1,options.data.length);if(value===false)continue;var firstChar=value.charAt(0).toLowerCase();if(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}setTimeout(populate,25);function flush(){data={};length=0;}return{flush:flush,add:add,populate:populate,load:function(q){if(!options.cacheLength||!length)return null;if(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
+if(data[q]){return data[q];}else
+if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("<div/>").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("<ul/>").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset<list.scrollTop()){list.scrollTop(offset);}}};function movePosition(step){active+=step;if(active<0){active=listItems.size()-1;}else if(active>=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max<available?options.max:available;}function fillList(){list.empty();var max=limitNumberOfItems(data.length);for(var i=0;i<max;i++){if(!data[i])continue;var formatted=options.formatItem(data[i].data,i+1,max,data[i].value,term);if(formatted===false)continue;var li=$("<li/>").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.fn.selection=function(start,end){if(start!==undefined){return this.each(function(){if(this.createTextRange){var selRange=this.createTextRange();if(end===undefined||start==end){selRange.move("character",start);selRange.select();}else{selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}}else if(this.setSelectionRange){this.setSelectionRange(start,end);}else if(this.selectionStart){this.selectionStart=start;this.selectionEnd=end;}});}var field=this[0];if(field.createTextRange){var range=document.selection.createRange(),orig=field.value,teststring="<->",textLength=range.text.length;range.text=teststring;var caretAt=field.value.indexOf(teststring);field.value=orig;this.selection(caretAt,caretAt+textLength);return{start:caretAt,end:caretAt+textLength}}else if(field.selectionStart!==undefined){return{start:field.selectionStart,end:field.selectionEnd}}};})(jQuery);
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/jquery.autocomplete.pack.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,12 @@
+/*
+ * jQuery Autocomplete plugin 1.1
+ *
+ * Copyright (c) 2009 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ */
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(3($){$.2e.1u({19:3(b,d){5 c=W b=="1B";d=$.1u({},$.M.1T,{Y:c?b:P,y:c?P:b,1J:c?$.M.1T.1J:10,X:d&&!d.1D?10:48},d);d.1y=d.1y||3(a){6 a};d.1v=d.1v||d.1R;6 A.I(3(){1M $.M(A,d)})},L:3(a){6 A.11("L",a)},1k:3(a){6 A.14("1k",[a])},2b:3(){6 A.14("2b")},28:3(a){6 A.14("28",[a])},24:3(){6 A.14("24")}});$.M=3(o,r){5 t={2Y:38,2S:40,2N:46,2I:9,2E:13,2B:27,2x:3I,2v:33,2p:34,2n:8};5 u=$(o).3r("19","3o").Q(r.2Q);5 p;5 m="";5 n=$.M.3c(r);5 s=0;5 k;5 h={1F:C};5 l=$.M.32(r,o,1Z,h);5 j;$.1Y.2X&&$(o.2U).11("45.19",3(){4(j){j=C;6 C}});u.11(($.1Y.2X?"43":"42")+".19",3(a){s=1;k=a.2M;3V(a.2M){O t.2Y:a.1d();4(l.N()){l.30()}w{12(0,D)}R;O t.2S:a.1d();4(l.N()){l.2D()}w{12(0,D)}R;O t.2v:a.1d();4(l.N()){l.2C()}w{12(0,D)}R;O t.2p:a.1d();4(l.N()){l.2A()}w{12(0,D)}R;O r.17&&$.1c(r.S)==","&&t.2x:O t.2I:O t.2E:4(1Z()){a.1d();j=D;6 C}R;O t.2B:l.Z();R;3J:1P(p);p=1O(12,r.1J);R}}).2t(3(){s++}).3E(3(){s=0;4(!h.1F){2r()}}).2q(3(){4(s++>1&&!l.N()){12(0,D)}}).11("1k",3(){5 c=(1r.7>1)?1r[1]:P;3 1N(q,a){5 b;4(a&&a.7){16(5 i=0;i<a.7;i++){4(a[i].L.J()==q.J()){b=a[i];R}}}4(W c=="3")c(b);w u.14("L",b&&[b.y,b.F])}$.I(15(u.K()),3(i,a){21(a,1N,1N)})}).11("2b",3(){n.1o()}).11("28",3(){$.1u(r,1r[1]);4("y"2h 1r[1])n.1e()}).11("24",3(){l.1p();u.1p();$(o.2U).1p(".19")});3 1Z(){5 e=l.2g();4(!e)6 C;5 v=e.L;m=v;4(r.17){5 b=15(u.K());4(b.7>1){5 f=r.S.7;5 c=$(o).18().1I;5 d,1H=0;$.I(b,3(i,a){1H+=a.7;4(c<=1H){d=i;6 C}1H+=f});b[d]=v;v=b.3f(r.S)}v+=r.S}u.K(v);1l();u.14("L",[e.y,e.F]);6 D}3 12(b,c){4(k==t.2N){l.Z();6}5 a=u.K();4(!c&&a==m)6;m=a;a=1m(a);4(a.7>=r.29){u.Q(r.26);4(!r.1s)a=a.J();21(a,3a,1l)}w{1q();l.Z()}};3 15(b){4(!b)6[""];4(!r.17)6[$.1c(b)];6 $.4h(b.23(r.S),3(a){6 $.1c(b).7?$.1c(a):P})}3 1m(a){4(!r.17)6 a;5 c=15(a);4(c.7==1)6 c[0];5 b=$(o).18().1I;4(b==a.7){c=15(a)}w{c=15(a.22(a.37(b),""))}6 c[c.7-1]}3 1G(q,a){4(r.1G&&(1m(u.K()).J()==q.J())&&k!=t.2n){u.K(u.K()+a.37(1m(m).7));$(o).18(m.7,m.7+a.7)}};3 2r(){1P(p);p=1O(1l,4g)};3 1l(){5 c=l.N();l.Z();1P(p);1q();4(r.36){u.1k(3(a){4(!a){4(r.17){5 b=15(u.K()).1n(0,-1);u.K(b.3f(r.S)+(b.7?r.S:""))}w{u.K("");u.14("L",P)}}})}};3 3a(q,a){4(a&&a.7&&s){1q();l.35(a,q);1G(q,a[0].F);l.20()}w{1l()}};3 21(f,d,g){4(!r.1s)f=f.J();5 e=n.31(f);4(e&&e.7){d(f,e)}w 4((W r.Y=="1B")&&(r.Y.7>0)){5 c={4f:+1M 4e()};$.I(r.2Z,3(a,b){c[a]=W b=="3"?b():b});$.4d({4c:"4b",4a:"19"+o.49,2V:r.2V,Y:r.Y,y:$.1u({q:1m(f),47:r.X},c),44:3(a){5 b=r.1A&&r.1A(a)||1A(a);n.1i(f,b);d(f,b)}})}w{l.2T();g(f)}};3 1A(c){5 d=[];5 b=c.23("\\n");16(5 i=0;i<b.7;i++){5 a=$.1c(b[i]);4(a){a=a.23("|");d[d.7]={y:a,F:a[0],L:r.1z&&r.1z(a,a[0])||a[0]}}}6 d};3 1q(){u.1h(r.26)}};$.M.1T={2Q:"41",2P:"3Z",26:"3Y",29:1,1J:3W,1s:C,1f:D,1w:C,1g:10,X:3U,36:C,2Z:{},1X:D,1R:3(a){6 a[0]},1v:P,1G:C,E:0,17:C,S:", ",1y:3(b,a){6 b.22(1M 3T("(?![^&;]+;)(?!<[^<>]*)("+a.22(/([\\^\\$\\(\\)\\[\\]\\{\\}\\*\\.\\+\\?\\|\\\\])/2K,"\\\\$1")+")(?![^<>]*>)(?![^&;]+;)","2K"),"<2J>$1</2J>")},1D:D,1E:3S};$.M.3c=3(g){5 h={};5 j=0;3 1f(s,a){4(!g.1s)s=s.J();5 i=s.2H(a);4(g.1w=="3R"){i=s.J().1k("\\\\b"+a.J())}4(i==-1)6 C;6 i==0||g.1w};3 1i(q,a){4(j>g.1g){1o()}4(!h[q]){j++}h[q]=a}3 1e(){4(!g.y)6 C;5 f={},2G=0;4(!g.Y)g.1g=1;f[""]=[];16(5 i=0,2F=g.y.7;i<2F;i++){5 c=g.y[i];c=(W c=="1B")?[c]:c;5 d=g.1v(c,i+1,g.y.7);4(d===C)1V;5 e=d.3Q(0).J();4(!f[e])f[e]=[];5 b={F:d,y:c,L:g.1z&&g.1z(c)||d};f[e].1U(b);4(2G++<g.X){f[""].1U(b)}};$.I(f,3(i,a){g.1g++;1i(i,a)})}1O(1e,25);3 1o(){h={};j=0}6{1o:1o,1i:1i,1e:1e,31:3(q){4(!g.1g||!j)6 P;4(!g.Y&&g.1w){5 a=[];16(5 k 2h h){4(k.7>0){5 c=h[k];$.I(c,3(i,x){4(1f(x.F,q)){a.1U(x)}})}}6 a}w 4(h[q]){6 h[q]}w 4(g.1f){16(5 i=q.7-1;i>=g.29;i--){5 c=h[q.3O(0,i)];4(c){5 a=[];$.I(c,3(i,x){4(1f(x.F,q)){a[a.7]=x}});6 a}}}6 P}}};$.M.32=3(e,g,f,k){5 h={H:"3N"};5 j,z=-1,y,1t="",1S=D,G,B;3 2y(){4(!1S)6;G=$("<3M/>").Z().Q(e.2P).T("3L","3K").1Q(1K.2w);B=$("<3H/>").1Q(G).3G(3(a){4(U(a).2u&&U(a).2u.3F()==\'2s\'){z=$("1L",B).1h(h.H).3D(U(a));$(U(a)).Q(h.H)}}).2q(3(a){$(U(a)).Q(h.H);f();g.2t();6 C}).3C(3(){k.1F=D}).3B(3(){k.1F=C});4(e.E>0)G.T("E",e.E);1S=C}3 U(a){5 b=a.U;3A(b&&b.3z!="2s")b=b.3y;4(!b)6[];6 b}3 V(b){j.1n(z,z+1).1h(h.H);2o(b);5 a=j.1n(z,z+1).Q(h.H);4(e.1D){5 c=0;j.1n(0,z).I(3(){c+=A.1a});4((c+a[0].1a-B.1b())>B[0].3x){B.1b(c+a[0].1a-B.3w())}w 4(c<B.1b()){B.1b(c)}}};3 2o(a){z+=a;4(z<0){z=j.1j()-1}w 4(z>=j.1j()){z=0}}3 2m(a){6 e.X&&e.X<a?e.X:a}3 2l(){B.2z();5 b=2m(y.7);16(5 i=0;i<b;i++){4(!y[i])1V;5 a=e.1R(y[i].y,i+1,b,y[i].F,1t);4(a===C)1V;5 c=$("<1L/>").3v(e.1y(a,1t)).Q(i%2==0?"3u":"3P").1Q(B)[0];$.y(c,"2k",y[i])}j=B.3t("1L");4(e.1X){j.1n(0,1).Q(h.H);z=0}4($.2e.2W)B.2W()}6{35:3(d,q){2y();y=d;1t=q;2l()},2D:3(){V(1)},30:3(){V(-1)},2C:3(){4(z!=0&&z-8<0){V(-z)}w{V(-8)}},2A:3(){4(z!=j.1j()-1&&z+8>j.1j()){V(j.1j()-1-z)}w{V(8)}},Z:3(){G&&G.Z();j&&j.1h(h.H);z=-1},N:3(){6 G&&G.3s(":N")},3q:3(){6 A.N()&&(j.2j("."+h.H)[0]||e.1X&&j[0])},20:3(){5 a=$(g).3p();G.T({E:W e.E=="1B"||e.E>0?e.E:$(g).E(),2i:a.2i+g.1a,1W:a.1W}).20();4(e.1D){B.1b(0);B.T({2L:e.1E,3n:\'3X\'});4($.1Y.3m&&W 1K.2w.3l.2L==="1x"){5 c=0;j.I(3(){c+=A.1a});5 b=c>e.1E;B.T(\'3k\',b?e.1E:c);4(!b){j.E(B.E()-2R(j.T("2O-1W"))-2R(j.T("2O-3j")))}}}},2g:3(){5 a=j&&j.2j("."+h.H).1h(h.H);6 a&&a.7&&$.y(a[0],"2k")},2T:3(){B&&B.2z()},1p:3(){G&&G.3i()}}};$.2e.18=3(b,f){4(b!==1x){6 A.I(3(){4(A.2d){5 a=A.2d();4(f===1x||b==f){a.4n("2c",b);a.3h()}w{a.4m(D);a.4l("2c",b);a.4k("2c",f);a.3h()}}w 4(A.3g){A.3g(b,f)}w 4(A.1C){A.1C=b;A.3e=f}})}5 c=A[0];4(c.2d){5 e=1K.18.4j(),3d=c.F,2a="<->",2f=e.3b.7;e.3b=2a;5 d=c.F.2H(2a);c.F=3d;A.18(d,d+2f);6{1I:d,39:d+2f}}w 4(c.1C!==1x){6{1I:c.1C,39:c.3e}}}})(4i);',62,272,'|||function|if|var|return|length|||||||||||||||||||||||||else||data|active|this|list|false|true|width|value|element|ACTIVE|each|toLowerCase|val|result|Autocompleter|visible|case|null|addClass|break|multipleSeparator|css|target|moveSelect|typeof|max|url|hide||bind|onChange||trigger|trimWords|for|multiple|selection|autocomplete|offsetHeight|scrollTop|trim|preventDefault|populate|matchSubset|cacheLength|removeClass|add|size|search|hideResultsNow|lastWord|slice|flush|unbind|stopLoading|arguments|matchCase|term|extend|formatMatch|matchContains|undefined|highlight|formatResult|parse|string|selectionStart|scroll|scrollHeight|mouseDownOnSelect|autoFill|progress|start|delay|document|li|new|findValueCallback|setTimeout|clearTimeout|appendTo|formatItem|needsInit|defaults|push|continue|left|selectFirst|browser|selectCurrent|show|request|replace|split|unautocomplete||loadingClass||setOptions|minChars|teststring|flushCache|character|createTextRange|fn|textLength|selected|in|top|filter|ac_data|fillList|limitNumberOfItems|BACKSPACE|movePosition|PAGEDOWN|click|hideResults|LI|focus|nodeName|PAGEUP|body|COMMA|init|empty|pageDown|ESC|pageUp|next|RETURN|ol|nullData|indexOf|TAB|strong|gi|maxHeight|keyCode|DEL|padding|resultsClass|inputClass|parseInt|DOWN|emptyList|form|dataType|bgiframe|opera|UP|extraParams|prev|load|Select|||display|mustMatch|substring||end|receiveData|text|Cache|orig|selectionEnd|join|setSelectionRange|select|remove|right|height|style|msie|overflow|off|offset|current|attr|is|find|ac_even|html|innerHeight|clientHeight|parentNode|tagName|while|mouseup|mousedown|index|blur|toUpperCase|mouseover|ul|188|default|absolute|position|div|ac_over|substr|ac_odd|charAt|word|180|RegExp|100|switch|400|auto|ac_loading|ac_results||ac_input|keydown|keypress|success|submit||limit|150|name|port|abort|mode|ajax|Date|timestamp|200|map|jQuery|createRange|moveEnd|moveStart|collapse|move'.split('|'),0,{}))
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/lib/jquery.ajaxQueue.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,116 @@
+/**
+ * Ajax Queue Plugin
+ *
+ * Homepage: http://jquery.com/plugins/project/ajaxqueue
+ * Documentation: http://docs.jquery.com/AjaxQueue
+ */
+
+/**
+
+<script>
+$(function(){
+ jQuery.ajaxQueue({
+ url: "test.php",
+ success: function(html){ jQuery("ul").append(html); }
+ });
+ jQuery.ajaxQueue({
+ url: "test.php",
+ success: function(html){ jQuery("ul").append(html); }
+ });
+ jQuery.ajaxSync({
+ url: "test.php",
+ success: function(html){ jQuery("ul").append("<b>"+html+"</b>"); }
+ });
+ jQuery.ajaxSync({
+ url: "test.php",
+ success: function(html){ jQuery("ul").append("<b>"+html+"</b>"); }
+ });
+});
+</script>
+<ul style="position: absolute; top: 5px; right: 5px;"></ul>
+
+ */
+/*
+ * Queued Ajax requests.
+ * A new Ajax request won't be started until the previous queued
+ * request has finished.
+ */
+
+/*
+ * Synced Ajax requests.
+ * The Ajax request will happen as soon as you call this method, but
+ * the callbacks (success/error/complete) won't fire until all previous
+ * synced requests have been completed.
+ */
+
+
+(function($) {
+
+ var ajax = $.ajax;
+
+ var pendingRequests = {};
+
+ var synced = [];
+ var syncedData = [];
+
+ $.ajax = function(settings) {
+ // create settings for compatibility with ajaxSetup
+ settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings));
+
+ var port = settings.port;
+
+ switch(settings.mode) {
+ case "abort":
+ if ( pendingRequests[port] ) {
+ pendingRequests[port].abort();
+ }
+ return pendingRequests[port] = ajax.apply(this, arguments);
+ case "queue":
+ var _old = settings.complete;
+ settings.complete = function(){
+ if ( _old )
+ _old.apply( this, arguments );
+ jQuery([ajax]).dequeue("ajax" + port );;
+ };
+
+ jQuery([ ajax ]).queue("ajax" + port, function(){
+ ajax( settings );
+ });
+ return;
+ case "sync":
+ var pos = synced.length;
+
+ synced[ pos ] = {
+ error: settings.error,
+ success: settings.success,
+ complete: settings.complete,
+ done: false
+ };
+
+ syncedData[ pos ] = {
+ error: [],
+ success: [],
+ complete: []
+ };
+
+ settings.error = function(){ syncedData[ pos ].error = arguments; };
+ settings.success = function(){ syncedData[ pos ].success = arguments; };
+ settings.complete = function(){
+ syncedData[ pos ].complete = arguments;
+ synced[ pos ].done = true;
+
+ if ( pos == 0 || !synced[ pos-1 ] )
+ for ( var i = pos; i < synced.length && synced[i].done; i++ ) {
+ if ( synced[i].error ) synced[i].error.apply( jQuery, syncedData[i].error );
+ if ( synced[i].success ) synced[i].success.apply( jQuery, syncedData[i].success );
+ if ( synced[i].complete ) synced[i].complete.apply( jQuery, syncedData[i].complete );
+
+ synced[i] = null;
+ syncedData[i] = null;
+ }
+ };
+ }
+ return ajax.apply(this, arguments);
+ };
+
+})(jQuery);
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/lib/jquery.bgiframe.min.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,10 @@
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-07-22 01:45:56 +0200 (Son, 22 Jul 2007) $
+ * $Rev: 2447 $
+ *
+ * Version 2.1.1
+ */
+(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&/6.0/.test(navigator.userAgent)){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};})(jQuery);
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/lib/jquery.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,3558 @@
+(function(){
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-27 21:17:26 +0200 (Di, 27 Mai 2008) $
+ * $Rev: 5700 $
+ */
+
+// Map over jQuery in case of overwrite
+var _jQuery = window.jQuery,
+// Map over the $ in case of overwrite
+ _$ = window.$;
+
+var jQuery = window.jQuery = window.$ = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context );
+};
+
+// A simple way to check for HTML strings or ID strings
+// (both of which we optimize for)
+var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,
+
+// Is it a simple selector
+ isSimple = /^.[^:#\[\.]*$/,
+
+// Will speed up references to undefined, and allows munging its name.
+ undefined;
+
+jQuery.fn = jQuery.prototype = {
+ init: function( selector, context ) {
+ // Make sure that a selection was provided
+ selector = selector || document;
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+ // Handle HTML strings
+ if ( typeof selector == "string" ) {
+ // Are we dealing with HTML string or an ID?
+ var match = quickExpr.exec( selector );
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] )
+ selector = jQuery.clean( [ match[1] ], context );
+
+ // HANDLE: $("#id")
+ else {
+ var elem = document.getElementById( match[3] );
+
+ // Make sure an element was located
+ if ( elem ){
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id != match[3] )
+ return jQuery().find( selector );
+
+ // Otherwise, we inject the element directly into the jQuery object
+ return jQuery( elem );
+ }
+ selector = [];
+ }
+
+ // HANDLE: $(expr, [context])
+ // (which is just equivalent to: $(content).find(expr)
+ } else
+ return jQuery( context ).find( selector );
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) )
+ return jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
+
+ return this.setArray(jQuery.makeArray(selector));
+ },
+
+ // The current version of jQuery being used
+ jquery: "1.2.6",
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ // The number of elements contained in the matched element set
+ length: 0,
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == undefined ?
+
+ // Return a 'clean' array
+ jQuery.makeArray( this ) :
+
+ // Return just the object
+ this[ num ];
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+ // Build a new jQuery matched element set
+ var ret = jQuery( elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Force the current matched set of elements to become
+ // the specified array of elements (destroying the stack in the process)
+ // You should use pushStack() in order to do this, but maintain the stack
+ setArray: function( elems ) {
+ // Resetting the length to 0, then using the native Array push
+ // is a super-fast way to populate an object with array-like properties
+ this.length = 0;
+ Array.prototype.push.apply( this, elems );
+
+ return this;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+ var ret = -1;
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem && elem.jquery ? elem[0] : elem
+ , this );
+ },
+
+ attr: function( name, value, type ) {
+ var options = name;
+
+ // Look for the case where we're accessing a style value
+ if ( name.constructor == String )
+ if ( value === undefined )
+ return this[0] && jQuery[ type || "attr" ]( this[0], name );
+
+ else {
+ options = {};
+ options[ name ] = value;
+ }
+
+ // Check to see if we're setting style values
+ return this.each(function(i){
+ // Set all the styles
+ for ( name in options )
+ jQuery.attr(
+ type ?
+ this.style :
+ this,
+ name, jQuery.prop( this, options[ name ], type, i, name )
+ );
+ });
+ },
+
+ css: function( key, value ) {
+ // ignore negative width and height values
+ if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
+ value = undefined;
+ return this.attr( key, value, "curCSS" );
+ },
+
+ text: function( text ) {
+ if ( typeof text != "object" && text != null )
+ return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+
+ var ret = "";
+
+ jQuery.each( text || this, function(){
+ jQuery.each( this.childNodes, function(){
+ if ( this.nodeType != 8 )
+ ret += this.nodeType != 1 ?
+ this.nodeValue :
+ jQuery.fn.text( [ this ] );
+ });
+ });
+
+ return ret;
+ },
+
+ wrapAll: function( html ) {
+ if ( this[0] )
+ // The elements to wrap the target around
+ jQuery( html, this[0].ownerDocument )
+ .clone()
+ .insertBefore( this[0] )
+ .map(function(){
+ var elem = this;
+
+ while ( elem.firstChild )
+ elem = elem.firstChild;
+
+ return elem;
+ })
+ .append(this);
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ return this.each(function(){
+ jQuery( this ).contents().wrapAll( html );
+ });
+ },
+
+ wrap: function( html ) {
+ return this.each(function(){
+ jQuery( this ).wrapAll( html );
+ });
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, false, function(elem){
+ if (this.nodeType == 1)
+ this.appendChild( elem );
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, true, function(elem){
+ if (this.nodeType == 1)
+ this.insertBefore( elem, this.firstChild );
+ });
+ },
+
+ before: function() {
+ return this.domManip(arguments, false, false, function(elem){
+ this.parentNode.insertBefore( elem, this );
+ });
+ },
+
+ after: function() {
+ return this.domManip(arguments, false, true, function(elem){
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ },
+
+ end: function() {
+ return this.prevObject || jQuery( [] );
+ },
+
+ find: function( selector ) {
+ var elems = jQuery.map(this, function(elem){
+ return jQuery.find( selector, elem );
+ });
+
+ return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
+ jQuery.unique( elems ) :
+ elems );
+ },
+
+ clone: function( events ) {
+ // Do the clone
+ var ret = this.map(function(){
+ if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {
+ // IE copies events bound via attachEvent when
+ // using cloneNode. Calling detachEvent on the
+ // clone will also remove the events from the orignal
+ // In order to get around this, we use innerHTML.
+ // Unfortunately, this means some modifications to
+ // attributes in IE that are actually only stored
+ // as properties will not be copied (such as the
+ // the name attribute on an input).
+ var clone = this.cloneNode(true),
+ container = document.createElement("div");
+ container.appendChild(clone);
+ return jQuery.clean([container.innerHTML])[0];
+ } else
+ return this.cloneNode(true);
+ });
+
+ // Need to set the expando to null on the cloned set if it exists
+ // removeData doesn't work here, IE removes it from the original as well
+ // this is primarily for IE but the data expando shouldn't be copied over in any browser
+ var clone = ret.find("*").andSelf().each(function(){
+ if ( this[ expando ] != undefined )
+ this[ expando ] = null;
+ });
+
+ // Copy the events from the original to the clone
+ if ( events === true )
+ this.find("*").andSelf().each(function(i){
+ if (this.nodeType == 3)
+ return;
+ var events = jQuery.data( this, "events" );
+
+ for ( var type in events )
+ for ( var handler in events[ type ] )
+ jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
+ });
+
+ // Return the cloned set
+ return ret;
+ },
+
+ filter: function( selector ) {
+ return this.pushStack(
+ jQuery.isFunction( selector ) &&
+ jQuery.grep(this, function(elem, i){
+ return selector.call( elem, i );
+ }) ||
+
+ jQuery.multiFilter( selector, this ) );
+ },
+
+ not: function( selector ) {
+ if ( selector.constructor == String )
+ // test special case where just one selector is passed in
+ if ( isSimple.test( selector ) )
+ return this.pushStack( jQuery.multiFilter( selector, this, true ) );
+ else
+ selector = jQuery.multiFilter( selector, this );
+
+ var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
+ return this.filter(function() {
+ return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
+ });
+ },
+
+ add: function( selector ) {
+ return this.pushStack( jQuery.unique( jQuery.merge(
+ this.get(),
+ typeof selector == 'string' ?
+ jQuery( selector ) :
+ jQuery.makeArray( selector )
+ )));
+ },
+
+ is: function( selector ) {
+ return !!selector && jQuery.multiFilter( selector, this ).length > 0;
+ },
+
+ hasClass: function( selector ) {
+ return this.is( "." + selector );
+ },
+
+ val: function( value ) {
+ if ( value == undefined ) {
+
+ if ( this.length ) {
+ var elem = this[0];
+
+ // We need to handle select boxes special
+ if ( jQuery.nodeName( elem, "select" ) ) {
+ var index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type == "select-one";
+
+ // Nothing was selected
+ if ( index < 0 )
+ return null;
+
+ // Loop through all the selected options
+ for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+ var option = options[ i ];
+
+ if ( option.selected ) {
+ // Get the specifc value for the option
+ value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;
+
+ // We don't need an array for one selects
+ if ( one )
+ return value;
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+
+ // Everything else, we just grab the value
+ } else
+ return (this[0].value || "").replace(/\r/g, "");
+
+ }
+
+ return undefined;
+ }
+
+ if( value.constructor == Number )
+ value += '';
+
+ return this.each(function(){
+ if ( this.nodeType != 1 )
+ return;
+
+ if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
+ this.checked = (jQuery.inArray(this.value, value) >= 0 ||
+ jQuery.inArray(this.name, value) >= 0);
+
+ else if ( jQuery.nodeName( this, "select" ) ) {
+ var values = jQuery.makeArray(value);
+
+ jQuery( "option", this ).each(function(){
+ this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
+ jQuery.inArray( this.text, values ) >= 0);
+ });
+
+ if ( !values.length )
+ this.selectedIndex = -1;
+
+ } else
+ this.value = value;
+ });
+ },
+
+ html: function( value ) {
+ return value == undefined ?
+ (this[0] ?
+ this[0].innerHTML :
+ null) :
+ this.empty().append( value );
+ },
+
+ replaceWith: function( value ) {
+ return this.after( value ).remove();
+ },
+
+ eq: function( i ) {
+ return this.slice( i, i + 1 );
+ },
+
+ slice: function() {
+ return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function(elem, i){
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ },
+
+ data: function( key, value ){
+ var parts = key.split(".");
+ parts[1] = parts[1] ? "." + parts[1] : "";
+
+ if ( value === undefined ) {
+ var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+ if ( data === undefined && this.length )
+ data = jQuery.data( this[0], key );
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ } else
+ return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
+ jQuery.data( this, key, value );
+ });
+ },
+
+ removeData: function( key ){
+ return this.each(function(){
+ jQuery.removeData( this, key );
+ });
+ },
+
+ domManip: function( args, table, reverse, callback ) {
+ var clone = this.length > 1, elems;
+
+ return this.each(function(){
+ if ( !elems ) {
+ elems = jQuery.clean( args, this.ownerDocument );
+
+ if ( reverse )
+ elems.reverse();
+ }
+
+ var obj = this;
+
+ if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
+ obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
+
+ var scripts = jQuery( [] );
+
+ jQuery.each(elems, function(){
+ var elem = clone ?
+ jQuery( this ).clone( true )[0] :
+ this;
+
+ // execute all scripts after the elements have been injected
+ if ( jQuery.nodeName( elem, "script" ) )
+ scripts = scripts.add( elem );
+ else {
+ // Remove any inner scripts for later evaluation
+ if ( elem.nodeType == 1 )
+ scripts = scripts.add( jQuery( "script", elem ).remove() );
+
+ // Inject the elements into the document
+ callback.call( obj, elem );
+ }
+ });
+
+ scripts.each( evalScript );
+ });
+ }
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+function evalScript( i, elem ) {
+ if ( elem.src )
+ jQuery.ajax({
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+
+ else
+ jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+
+ if ( elem.parentNode )
+ elem.parentNode.removeChild( elem );
+}
+
+function now(){
+ return +new Date;
+}
+
+jQuery.extend = jQuery.fn.extend = function() {
+ // copy reference to target object
+ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+
+ // Handle a deep copy situation
+ if ( target.constructor == Boolean ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target != "object" && typeof target != "function" )
+ target = {};
+
+ // extend jQuery itself if only one argument is passed
+ if ( length == i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ )
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null )
+ // Extend the base object
+ for ( var name in options ) {
+ var src = target[ name ], copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy )
+ continue;
+
+ // Recurse if we're merging object values
+ if ( deep && copy && typeof copy == "object" && !copy.nodeType )
+ target[ name ] = jQuery.extend( deep,
+ // Never move original objects, clone them
+ src || ( copy.length != null ? [ ] : { } )
+ , copy );
+
+ // Don't bring in undefined values
+ else if ( copy !== undefined )
+ target[ name ] = copy;
+
+ }
+
+ // Return the modified object
+ return target;
+};
+
+var expando = "jQuery" + now(), uuid = 0, windowData = {},
+ // exclude the following css properties to add px
+ exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
+ // cache defaultView
+ defaultView = document.defaultView || {};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ window.$ = _$;
+
+ if ( deep )
+ window.jQuery = _jQuery;
+
+ return jQuery;
+ },
+
+ // See test/unit/core.js for details concerning this function.
+ isFunction: function( fn ) {
+ return !!fn && typeof fn != "string" && !fn.nodeName &&
+ fn.constructor != Array && /^[\s[]?function/.test( fn + "" );
+ },
+
+ // check if an element is in a (or is an) XML document
+ isXMLDoc: function( elem ) {
+ return elem.documentElement && !elem.body ||
+ elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
+ },
+
+ // Evalulates a script in a global context
+ globalEval: function( data ) {
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Inspired by code by Andrea Giammarchi
+ // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
+ var head = document.getElementsByTagName("head")[0] || document.documentElement,
+ script = document.createElement("script");
+
+ script.type = "text/javascript";
+ if ( jQuery.browser.msie )
+ script.text = data;
+ else
+ script.appendChild( document.createTextNode( data ) );
+
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709).
+ head.insertBefore( script, head.firstChild );
+ head.removeChild( script );
+ }
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
+ },
+
+ cache: {},
+
+ data: function( elem, name, data ) {
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ];
+
+ // Compute a unique ID for the element
+ if ( !id )
+ id = elem[ expando ] = ++uuid;
+
+ // Only generate the data cache if we're
+ // trying to access or manipulate it
+ if ( name && !jQuery.cache[ id ] )
+ jQuery.cache[ id ] = {};
+
+ // Prevent overriding the named cache with undefined values
+ if ( data !== undefined )
+ jQuery.cache[ id ][ name ] = data;
+
+ // Return the named cache data, or the ID for the element
+ return name ?
+ jQuery.cache[ id ][ name ] :
+ id;
+ },
+
+ removeData: function( elem, name ) {
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ];
+
+ // If we want to remove a specific section of the element's data
+ if ( name ) {
+ if ( jQuery.cache[ id ] ) {
+ // Remove the section of cache data
+ delete jQuery.cache[ id ][ name ];
+
+ // If we've removed all the data, remove the element's cache
+ name = "";
+
+ for ( name in jQuery.cache[ id ] )
+ break;
+
+ if ( !name )
+ jQuery.removeData( elem );
+ }
+
+ // Otherwise, we want to remove all of the element's data
+ } else {
+ // Clean up the element expando
+ try {
+ delete elem[ expando ];
+ } catch(e){
+ // IE has trouble directly removing the expando
+ // but it's ok with using removeAttribute
+ if ( elem.removeAttribute )
+ elem.removeAttribute( expando );
+ }
+
+ // Completely remove the data cache
+ delete jQuery.cache[ id ];
+ }
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ var name, i = 0, length = object.length;
+
+ if ( args ) {
+ if ( length == undefined ) {
+ for ( name in object )
+ if ( callback.apply( object[ name ], args ) === false )
+ break;
+ } else
+ for ( ; i < length; )
+ if ( callback.apply( object[ i++ ], args ) === false )
+ break;
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( length == undefined ) {
+ for ( name in object )
+ if ( callback.call( object[ name ], name, object[ name ] ) === false )
+ break;
+ } else
+ for ( var value = object[0];
+ i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
+ }
+
+ return object;
+ },
+
+ prop: function( elem, value, type, i, name ) {
+ // Handle executable functions
+ if ( jQuery.isFunction( value ) )
+ value = value.call( elem, i );
+
+ // Handle passing in a number to a CSS property
+ return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ?
+ value + "px" :
+ value;
+ },
+
+ className: {
+ // internal only, use addClass("class")
+ add: function( elem, classNames ) {
+ jQuery.each((classNames || "").split(/\s+/), function(i, className){
+ if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
+ elem.className += (elem.className ? " " : "") + className;
+ });
+ },
+
+ // internal only, use removeClass("class")
+ remove: function( elem, classNames ) {
+ if (elem.nodeType == 1)
+ elem.className = classNames != undefined ?
+ jQuery.grep(elem.className.split(/\s+/), function(className){
+ return !jQuery.className.has( classNames, className );
+ }).join(" ") :
+ "";
+ },
+
+ // internal only, use hasClass("class")
+ has: function( elem, className ) {
+ return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
+ }
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {};
+ // Remember the old values, and insert the new ones
+ for ( var name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ callback.call( elem );
+
+ // Revert the old values
+ for ( var name in options )
+ elem.style[ name ] = old[ name ];
+ },
+
+ css: function( elem, name, force ) {
+ if ( name == "width" || name == "height" ) {
+ var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
+
+ function getWH() {
+ val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
+ var padding = 0, border = 0;
+ jQuery.each( which, function() {
+ padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+ border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+ });
+ val -= Math.round(padding + border);
+ }
+
+ if ( jQuery(elem).is(":visible") )
+ getWH();
+ else
+ jQuery.swap( elem, props, getWH );
+
+ return Math.max(0, val);
+ }
+
+ return jQuery.curCSS( elem, name, force );
+ },
+
+ curCSS: function( elem, name, force ) {
+ var ret, style = elem.style;
+
+ // A helper method for determining if an element's values are broken
+ function color( elem ) {
+ if ( !jQuery.browser.safari )
+ return false;
+
+ // defaultView is cached
+ var ret = defaultView.getComputedStyle( elem, null );
+ return !ret || ret.getPropertyValue("color") == "";
+ }
+
+ // We need to handle opacity special in IE
+ if ( name == "opacity" && jQuery.browser.msie ) {
+ ret = jQuery.attr( style, "opacity" );
+
+ return ret == "" ?
+ "1" :
+ ret;
+ }
+ // Opera sometimes will give the wrong display answer, this fixes it, see #2037
+ if ( jQuery.browser.opera && name == "display" ) {
+ var save = style.outline;
+ style.outline = "0 solid black";
+ style.outline = save;
+ }
+
+ // Make sure we're using the right name for getting the float value
+ if ( name.match( /float/i ) )
+ name = styleFloat;
+
+ if ( !force && style && style[ name ] )
+ ret = style[ name ];
+
+ else if ( defaultView.getComputedStyle ) {
+
+ // Only "float" is needed here
+ if ( name.match( /float/i ) )
+ name = "float";
+
+ name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
+
+ var computedStyle = defaultView.getComputedStyle( elem, null );
+
+ if ( computedStyle && !color( elem ) )
+ ret = computedStyle.getPropertyValue( name );
+
+ // If the element isn't reporting its values properly in Safari
+ // then some display: none elements are involved
+ else {
+ var swap = [], stack = [], a = elem, i = 0;
+
+ // Locate all of the parent display: none elements
+ for ( ; a && color(a); a = a.parentNode )
+ stack.unshift(a);
+
+ // Go through and make them visible, but in reverse
+ // (It would be better if we knew the exact display type that they had)
+ for ( ; i < stack.length; i++ )
+ if ( color( stack[ i ] ) ) {
+ swap[ i ] = stack[ i ].style.display;
+ stack[ i ].style.display = "block";
+ }
+
+ // Since we flip the display style, we have to handle that
+ // one special, otherwise get the value
+ ret = name == "display" && swap[ stack.length - 1 ] != null ?
+ "none" :
+ ( computedStyle && computedStyle.getPropertyValue( name ) ) || "";
+
+ // Finally, revert the display styles back
+ for ( i = 0; i < swap.length; i++ )
+ if ( swap[ i ] != null )
+ stack[ i ].style.display = swap[ i ];
+ }
+
+ // We should always get a number back from opacity
+ if ( name == "opacity" && ret == "" )
+ ret = "1";
+
+ } else if ( elem.currentStyle ) {
+ var camelCase = name.replace(/\-(\w)/g, function(all, letter){
+ return letter.toUpperCase();
+ });
+
+ ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
+ // Remember the original values
+ var left = style.left, rsLeft = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ style.left = ret || 0;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret;
+ },
+
+ clean: function( elems, context ) {
+ var ret = [];
+ context = context || document;
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if (typeof context.createElement == 'undefined')
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+
+ jQuery.each(elems, function(i, elem){
+ if ( !elem )
+ return;
+
+ if ( elem.constructor == Number )
+ elem += '';
+
+ // Convert html string into DOM nodes
+ if ( typeof elem == "string" ) {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
+ return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
+ all :
+ front + "></" + tag + ">";
+ });
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
+
+ var wrap =
+ // option or optgroup
+ !tags.indexOf("<opt") &&
+ [ 1, "<select multiple='multiple'>", "</select>" ] ||
+
+ !tags.indexOf("<leg") &&
+ [ 1, "<fieldset>", "</fieldset>" ] ||
+
+ tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
+ [ 1, "<table>", "</table>" ] ||
+
+ !tags.indexOf("<tr") &&
+ [ 2, "<table><tbody>", "</tbody></table>" ] ||
+
+ // <thead> matched above
+ (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
+ [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
+
+ !tags.indexOf("<col") &&
+ [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
+
+ // IE can't serialize <link> and <script> tags normally
+ jQuery.browser.msie &&
+ [ 1, "div<div>", "</div>" ] ||
+
+ [ 0, "", "" ];
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( wrap[0]-- )
+ div = div.lastChild;
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( jQuery.browser.msie ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
+ div.childNodes :
+ [];
+
+ for ( var j = tbody.length - 1; j >= 0 ; --j )
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( /^\s/.test( elem ) )
+ div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
+
+ }
+
+ elem = jQuery.makeArray( div.childNodes );
+ }
+
+ if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
+ return;
+
+ if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
+ ret.push( elem );
+
+ else
+ ret = jQuery.merge( ret, elem );
+
+ });
+
+ return ret;
+ },
+
+ attr: function( elem, name, value ) {
+ // don't set attributes on text and comment nodes
+ if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
+ return undefined;
+
+ var notxml = !jQuery.isXMLDoc( elem ),
+ // Whether we are setting (or getting)
+ set = value !== undefined,
+ msie = jQuery.browser.msie;
+
+ // Try to normalize/fix the name
+ name = notxml && jQuery.props[ name ] || name;
+
+ // Only do all the following if this is a node (faster for style)
+ // IE elem.getAttribute passes even for style
+ if ( elem.tagName ) {
+
+ // These attributes require special treatment
+ var special = /href|src|style/.test( name );
+
+ // Safari mis-reports the default selected property of a hidden option
+ // Accessing the parent's selectedIndex property fixes it
+ if ( name == "selected" && jQuery.browser.safari )
+ elem.parentNode.selectedIndex;
+
+ // If applicable, access the attribute via the DOM 0 way
+ if ( name in elem && notxml && !special ) {
+ if ( set ){
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
+ throw "type property can't be changed";
+
+ elem[ name ] = value;
+ }
+
+ // browsers index elements by id/name on forms, give priority to attributes.
+ if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
+ return elem.getAttributeNode( name ).nodeValue;
+
+ return elem[ name ];
+ }
+
+ if ( msie && notxml && name == "style" )
+ return jQuery.attr( elem.style, "cssText", value );
+
+ if ( set )
+ // convert the value to a string (all browsers do this but IE) see #1070
+ elem.setAttribute( name, "" + value );
+
+ var attr = msie && notxml && special
+ // Some attributes require a special call on IE
+ ? elem.getAttribute( name, 2 )
+ : elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return attr === null ? undefined : attr;
+ }
+
+ // elem is actually elem.style ... set the style
+
+ // IE uses filters for opacity
+ if ( msie && name == "opacity" ) {
+ if ( set ) {
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ elem.zoom = 1;
+
+ // Set the alpha filter to set the opacity
+ elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
+ (parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
+ }
+
+ return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
+ (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
+ "";
+ }
+
+ name = name.replace(/-([a-z])/ig, function(all, letter){
+ return letter.toUpperCase();
+ });
+
+ if ( set )
+ elem[ name ] = value;
+
+ return elem[ name ];
+ },
+
+ trim: function( text ) {
+ return (text || "").replace( /^\s+|\s+$/g, "" );
+ },
+
+ makeArray: function( array ) {
+ var ret = [];
+
+ if( array != null ){
+ var i = array.length;
+ //the window, strings and functions also have 'length'
+ if( i == null || array.split || array.setInterval || array.call )
+ ret[0] = array;
+ else
+ while( i )
+ ret[--i] = array[i];
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, array ) {
+ for ( var i = 0, length = array.length; i < length; i++ )
+ // Use === because on IE, window == document
+ if ( array[ i ] === elem )
+ return i;
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ // We have to loop this way because IE & Opera overwrite the length
+ // expando of getElementsByTagName
+ var i = 0, elem, pos = first.length;
+ // Also, we need to make sure that the correct elements are being returned
+ // (IE returns comment nodes in a '*' query)
+ if ( jQuery.browser.msie ) {
+ while ( elem = second[ i++ ] )
+ if ( elem.nodeType != 8 )
+ first[ pos++ ] = elem;
+
+ } else
+ while ( elem = second[ i++ ] )
+ first[ pos++ ] = elem;
+
+ return first;
+ },
+
+ unique: function( array ) {
+ var ret = [], done = {};
+
+ try {
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ var id = jQuery.data( array[ i ] );
+
+ if ( !done[ id ] ) {
+ done[ id ] = true;
+ ret.push( array[ i ] );
+ }
+ }
+
+ } catch( e ) {
+ ret = array;
+ }
+
+ return ret;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [];
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ )
+ if ( !inv != !callback( elems[ i ], i ) )
+ ret.push( elems[ i ] );
+
+ return ret;
+ },
+
+ map: function( elems, callback ) {
+ var ret = [];
+
+ // Go through the array, translating each of the items to their
+ // new value (or values).
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ var value = callback( elems[ i ], i );
+
+ if ( value != null )
+ ret[ ret.length ] = value;
+ }
+
+ return ret.concat.apply( [], ret );
+ }
+});
+
+var userAgent = navigator.userAgent.toLowerCase();
+
+// Figure out what browser is being used
+jQuery.browser = {
+ version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
+ safari: /webkit/.test( userAgent ),
+ opera: /opera/.test( userAgent ),
+ msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
+ mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
+};
+
+var styleFloat = jQuery.browser.msie ?
+ "styleFloat" :
+ "cssFloat";
+
+jQuery.extend({
+ // Check to see if the W3C box model is being used
+ boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
+
+ props: {
+ "for": "htmlFor",
+ "class": "className",
+ "float": styleFloat,
+ cssFloat: styleFloat,
+ styleFloat: styleFloat,
+ readonly: "readOnly",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ rowspan: "rowSpan"
+ }
+});
+
+jQuery.each({
+ parent: function(elem){return elem.parentNode;},
+ parents: function(elem){return jQuery.dir(elem,"parentNode");},
+ next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
+ prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
+ nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
+ prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
+ siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
+ children: function(elem){return jQuery.sibling(elem.firstChild);},
+ contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
+}, function(name, fn){
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = jQuery.map( this, fn );
+
+ if ( selector && typeof selector == "string" )
+ ret = jQuery.multiFilter( selector, ret );
+
+ return this.pushStack( jQuery.unique( ret ) );
+ };
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function(name, original){
+ jQuery.fn[ name ] = function() {
+ var args = arguments;
+
+ return this.each(function(){
+ for ( var i = 0, length = args.length; i < length; i++ )
+ jQuery( args[ i ] )[ original ]( this );
+ });
+ };
+});
+
+jQuery.each({
+ removeAttr: function( name ) {
+ jQuery.attr( this, name, "" );
+ if (this.nodeType == 1)
+ this.removeAttribute( name );
+ },
+
+ addClass: function( classNames ) {
+ jQuery.className.add( this, classNames );
+ },
+
+ removeClass: function( classNames ) {
+ jQuery.className.remove( this, classNames );
+ },
+
+ toggleClass: function( classNames ) {
+ jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
+ },
+
+ remove: function( selector ) {
+ if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
+ // Prevent memory leaks
+ jQuery( "*", this ).add(this).each(function(){
+ jQuery.event.remove(this);
+ jQuery.removeData(this);
+ });
+ if (this.parentNode)
+ this.parentNode.removeChild( this );
+ }
+ },
+
+ empty: function() {
+ // Remove element nodes and prevent memory leaks
+ jQuery( ">*", this ).remove();
+
+ // Remove any remaining nodes
+ while ( this.firstChild )
+ this.removeChild( this.firstChild );
+ }
+}, function(name, fn){
+ jQuery.fn[ name ] = function(){
+ return this.each( fn, arguments );
+ };
+});
+
+jQuery.each([ "Height", "Width" ], function(i, name){
+ var type = name.toLowerCase();
+
+ jQuery.fn[ type ] = function( size ) {
+ // Get window width or height
+ return this[0] == window ?
+ // Opera reports document.body.client[Width/Height] properly in both quirks and standards
+ jQuery.browser.opera && document.body[ "client" + name ] ||
+
+ // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
+ jQuery.browser.safari && window[ "inner" + name ] ||
+
+ // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+ document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :
+
+ // Get document width or height
+ this[0] == document ?
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ Math.max(
+ Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
+ Math.max(document.body["offset" + name], document.documentElement["offset" + name])
+ ) :
+
+ // Get or set width or height on the element
+ size == undefined ?
+ // Get width or height on the element
+ (this.length ? jQuery.css( this[0], type ) : null) :
+
+ // Set the width or height on the element (default to pixels if value is unitless)
+ this.css( type, size.constructor == String ? size : size + "px" );
+ };
+});
+
+// Helper function used by the dimensions and offset modules
+function num(elem, prop) {
+ return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
+}var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
+ "(?:[\\w*_-]|\\\\.)" :
+ "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
+ quickChild = new RegExp("^>\\s*(" + chars + "+)"),
+ quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
+ quickClass = new RegExp("^([#.]?)(" + chars + "*)");
+
+jQuery.extend({
+ expr: {
+ "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
+ "#": function(a,i,m){return a.getAttribute("id")==m[2];},
+ ":": {
+ // Position Checks
+ lt: function(a,i,m){return i<m[3]-0;},
+ gt: function(a,i,m){return i>m[3]-0;},
+ nth: function(a,i,m){return m[3]-0==i;},
+ eq: function(a,i,m){return m[3]-0==i;},
+ first: function(a,i){return i==0;},
+ last: function(a,i,m,r){return i==r.length-1;},
+ even: function(a,i){return i%2==0;},
+ odd: function(a,i){return i%2;},
+
+ // Child Checks
+ "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
+ "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
+ "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},
+
+ // Parent Checks
+ parent: function(a){return a.firstChild;},
+ empty: function(a){return !a.firstChild;},
+
+ // Text Check
+ contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},
+
+ // Visibility
+ visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
+ hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},
+
+ // Form attributes
+ enabled: function(a){return !a.disabled;},
+ disabled: function(a){return a.disabled;},
+ checked: function(a){return a.checked;},
+ selected: function(a){return a.selected||jQuery.attr(a,"selected");},
+
+ // Form elements
+ text: function(a){return "text"==a.type;},
+ radio: function(a){return "radio"==a.type;},
+ checkbox: function(a){return "checkbox"==a.type;},
+ file: function(a){return "file"==a.type;},
+ password: function(a){return "password"==a.type;},
+ submit: function(a){return "submit"==a.type;},
+ image: function(a){return "image"==a.type;},
+ reset: function(a){return "reset"==a.type;},
+ button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
+ input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},
+
+ // :has()
+ has: function(a,i,m){return jQuery.find(m[3],a).length;},
+
+ // :header
+ header: function(a){return /h\d/i.test(a.nodeName);},
+
+ // :animated
+ animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
+ }
+ },
+
+ // The regular expressions that power the parsing engine
+ parse: [
+ // Match: [@value='test'], [@foo]
+ /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
+
+ // Match: :contains('foo')
+ /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
+
+ // Match: :even, :last-child, #id, .class
+ new RegExp("^([:.#]*)(" + chars + "+)")
+ ],
+
+ multiFilter: function( expr, elems, not ) {
+ var old, cur = [];
+
+ while ( expr && expr != old ) {
+ old = expr;
+ var f = jQuery.filter( expr, elems, not );
+ expr = f.t.replace(/^\s*,\s*/, "" );
+ cur = not ? elems = f.r : jQuery.merge( cur, f.r );
+ }
+
+ return cur;
+ },
+
+ find: function( t, context ) {
+ // Quickly handle non-string expressions
+ if ( typeof t != "string" )
+ return [ t ];
+
+ // check to make sure context is a DOM element or a document
+ if ( context && context.nodeType != 1 && context.nodeType != 9)
+ return [ ];
+
+ // Set the correct context (if none is provided)
+ context = context || document;
+
+ // Initialize the search
+ var ret = [context], done = [], last, nodeName;
+
+ // Continue while a selector expression exists, and while
+ // we're no longer looping upon ourselves
+ while ( t && last != t ) {
+ var r = [];
+ last = t;
+
+ t = jQuery.trim(t);
+
+ var foundToken = false,
+
+ // An attempt at speeding up child selectors that
+ // point to a specific element tag
+ re = quickChild,
+
+ m = re.exec(t);
+
+ if ( m ) {
+ nodeName = m[1].toUpperCase();
+
+ // Perform our own iteration and filter
+ for ( var i = 0; ret[i]; i++ )
+ for ( var c = ret[i].firstChild; c; c = c.nextSibling )
+ if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
+ r.push( c );
+
+ ret = r;
+ t = t.replace( re, "" );
+ if ( t.indexOf(" ") == 0 ) continue;
+ foundToken = true;
+ } else {
+ re = /^([>+~])\s*(\w*)/i;
+
+ if ( (m = re.exec(t)) != null ) {
+ r = [];
+
+ var merge = {};
+ nodeName = m[2].toUpperCase();
+ m = m[1];
+
+ for ( var j = 0, rl = ret.length; j < rl; j++ ) {
+ var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
+ for ( ; n; n = n.nextSibling )
+ if ( n.nodeType == 1 ) {
+ var id = jQuery.data(n);
+
+ if ( m == "~" && merge[id] ) break;
+
+ if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
+ if ( m == "~" ) merge[id] = true;
+ r.push( n );
+ }
+
+ if ( m == "+" ) break;
+ }
+ }
+
+ ret = r;
+
+ // And remove the token
+ t = jQuery.trim( t.replace( re, "" ) );
+ foundToken = true;
+ }
+ }
+
+ // See if there's still an expression, and that we haven't already
+ // matched a token
+ if ( t && !foundToken ) {
+ // Handle multiple expressions
+ if ( !t.indexOf(",") ) {
+ // Clean the result set
+ if ( context == ret[0] ) ret.shift();
+
+ // Merge the result sets
+ done = jQuery.merge( done, ret );
+
+ // Reset the context
+ r = ret = [context];
+
+ // Touch up the selector string
+ t = " " + t.substr(1,t.length);
+
+ } else {
+ // Optimize for the case nodeName#idName
+ var re2 = quickID;
+ var m = re2.exec(t);
+
+ // Re-organize the results, so that they're consistent
+ if ( m ) {
+ m = [ 0, m[2], m[3], m[1] ];
+
+ } else {
+ // Otherwise, do a traditional filter check for
+ // ID, class, and element selectors
+ re2 = quickClass;
+ m = re2.exec(t);
+ }
+
+ m[2] = m[2].replace(/\\/g, "");
+
+ var elem = ret[ret.length-1];
+
+ // Try to do a global search by ID, where we can
+ if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
+ // Optimization for HTML document case
+ var oid = elem.getElementById(m[2]);
+
+ // Do a quick check for the existence of the actual ID attribute
+ // to avoid selecting by the name attribute in IE
+ // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
+ if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
+ oid = jQuery('[@id="'+m[2]+'"]', elem)[0];
+
+ // Do a quick check for node name (where applicable) so
+ // that div#foo searches will be really fast
+ ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];
+ } else {
+ // We need to find all descendant elements
+ for ( var i = 0; ret[i]; i++ ) {
+ // Grab the tag name being searched for
+ var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];
+
+ // Handle IE7 being really dumb about <object>s
+ if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
+ tag = "param";
+
+ r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
+ }
+
+ // It's faster to filter by class and be done with it
+ if ( m[1] == "." )
+ r = jQuery.classFilter( r, m[2] );
+
+ // Same with ID filtering
+ if ( m[1] == "#" ) {
+ var tmp = [];
+
+ // Try to find the element with the ID
+ for ( var i = 0; r[i]; i++ )
+ if ( r[i].getAttribute("id") == m[2] ) {
+ tmp = [ r[i] ];
+ break;
+ }
+
+ r = tmp;
+ }
+
+ ret = r;
+ }
+
+ t = t.replace( re2, "" );
+ }
+
+ }
+
+ // If a selector string still exists
+ if ( t ) {
+ // Attempt to filter it
+ var val = jQuery.filter(t,r);
+ ret = r = val.r;
+ t = jQuery.trim(val.t);
+ }
+ }
+
+ // An error occurred with the selector;
+ // just return an empty set instead
+ if ( t )
+ ret = [];
+
+ // Remove the root context
+ if ( ret && context == ret[0] )
+ ret.shift();
+
+ // And combine the results
+ done = jQuery.merge( done, ret );
+
+ return done;
+ },
+
+ classFilter: function(r,m,not){
+ m = " " + m + " ";
+ var tmp = [];
+ for ( var i = 0; r[i]; i++ ) {
+ var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
+ if ( !not && pass || not && !pass )
+ tmp.push( r[i] );
+ }
+ return tmp;
+ },
+
+ filter: function(t,r,not) {
+ var last;
+
+ // Look for common filter expressions
+ while ( t && t != last ) {
+ last = t;
+
+ var p = jQuery.parse, m;
+
+ for ( var i = 0; p[i]; i++ ) {
+ m = p[i].exec( t );
+
+ if ( m ) {
+ // Remove what we just matched
+ t = t.substring( m[0].length );
+
+ m[2] = m[2].replace(/\\/g, "");
+ break;
+ }
+ }
+
+ if ( !m )
+ break;
+
+ // :not() is a special case that can be optimized by
+ // keeping it out of the expression list
+ if ( m[1] == ":" && m[2] == "not" )
+ // optimize if only one selector found (most common case)
+ r = isSimple.test( m[3] ) ?
+ jQuery.filter(m[3], r, true).r :
+ jQuery( r ).not( m[3] );
+
+ // We can get a big speed boost by filtering by class here
+ else if ( m[1] == "." )
+ r = jQuery.classFilter(r, m[2], not);
+
+ else if ( m[1] == "[" ) {
+ var tmp = [], type = m[3];
+
+ for ( var i = 0, rl = r.length; i < rl; i++ ) {
+ var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
+
+ if ( z == null || /href|src|selected/.test(m[2]) )
+ z = jQuery.attr(a,m[2]) || '';
+
+ if ( (type == "" && !!z ||
+ type == "=" && z == m[5] ||
+ type == "!=" && z != m[5] ||
+ type == "^=" && z && !z.indexOf(m[5]) ||
+ type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
+ (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
+ tmp.push( a );
+ }
+
+ r = tmp;
+
+ // We can get a speed boost by handling nth-child here
+ } else if ( m[1] == ":" && m[2] == "nth-child" ) {
+ var merge = {}, tmp = [],
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+ m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
+ !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
+ // calculate the numbers (first)n+(last) including if they are negative
+ first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
+
+ // loop through all the elements left in the jQuery object
+ for ( var i = 0, rl = r.length; i < rl; i++ ) {
+ var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
+
+ if ( !merge[id] ) {
+ var c = 1;
+
+ for ( var n = parentNode.firstChild; n; n = n.nextSibling )
+ if ( n.nodeType == 1 )
+ n.nodeIndex = c++;
+
+ merge[id] = true;
+ }
+
+ var add = false;
+
+ if ( first == 0 ) {
+ if ( node.nodeIndex == last )
+ add = true;
+ } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
+ add = true;
+
+ if ( add ^ not )
+ tmp.push( node );
+ }
+
+ r = tmp;
+
+ // Otherwise, find the expression to execute
+ } else {
+ var fn = jQuery.expr[ m[1] ];
+ if ( typeof fn == "object" )
+ fn = fn[ m[2] ];
+
+ if ( typeof fn == "string" )
+ fn = eval("false||function(a,i){return " + fn + ";}");
+
+ // Execute it against the current filter
+ r = jQuery.grep( r, function(elem, i){
+ return fn(elem, i, m, r);
+ }, not );
+ }
+ }
+
+ // Return an array of filtered elements (r)
+ // and the modified expression string (t)
+ return { r: r, t: t };
+ },
+
+ dir: function( elem, dir ){
+ var matched = [],
+ cur = elem[dir];
+ while ( cur && cur != document ) {
+ if ( cur.nodeType == 1 )
+ matched.push( cur );
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function(cur,result,dir,elem){
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] )
+ if ( cur.nodeType == 1 && ++num == result )
+ break;
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType == 1 && n != elem )
+ r.push( n );
+ }
+
+ return r;
+ }
+});
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code orignated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+ // Bind an event to an element
+ // Original by Dean Edwards
+ add: function(elem, types, handler, data) {
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return;
+
+ // For whatever reason, IE has trouble passing the window object
+ // around, causing it to be cloned in the process
+ if ( jQuery.browser.msie && elem.setInterval )
+ elem = window;
+
+ // Make sure that the function being executed has a unique ID
+ if ( !handler.guid )
+ handler.guid = this.guid++;
+
+ // if data is passed, bind to handler
+ if( data != undefined ) {
+ // Create temporary function pointer to original handler
+ var fn = handler;
+
+ // Create unique handler function, wrapped around original handler
+ handler = this.proxy( fn, function() {
+ // Pass arguments and context to original handler
+ return fn.apply(this, arguments);
+ });
+
+ // Store data in unique handler
+ handler.data = data;
+ }
+
+ // Init the element's event structure
+ var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
+ handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
+ // Handle the second event of a trigger and when
+ // an event is called after a page has unloaded
+ if ( typeof jQuery != "undefined" && !jQuery.event.triggered )
+ return jQuery.event.handle.apply(arguments.callee.elem, arguments);
+ });
+ // Add elem as a property of the handle function
+ // This is to prevent a memory leak with non-native
+ // event in IE.
+ handle.elem = elem;
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ jQuery.each(types.split(/\s+/), function(index, type) {
+ // Namespaced event handlers
+ var parts = type.split(".");
+ type = parts[0];
+ handler.type = parts[1];
+
+ // Get the current list of functions bound to this event
+ var handlers = events[type];
+
+ // Init the event handler queue
+ if (!handlers) {
+ handlers = events[type] = {};
+
+ // Check for a special event handler
+ // Only use addEventListener/attachEvent if the special
+ // events handler returns false
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
+ // Bind the global event handler to the element
+ if (elem.addEventListener)
+ elem.addEventListener(type, handle, false);
+ else if (elem.attachEvent)
+ elem.attachEvent("on" + type, handle);
+ }
+ }
+
+ // Add the function to the element's handler list
+ handlers[handler.guid] = handler;
+
+ // Keep track of which events have been used, for global triggering
+ jQuery.event.global[type] = true;
+ });
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ guid: 1,
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function(elem, types, handler) {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return;
+
+ var events = jQuery.data(elem, "events"), ret, index;
+
+ if ( events ) {
+ // Unbind all events for the element
+ if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
+ for ( var type in events )
+ this.remove( elem, type + (types || "") );
+ else {
+ // types is actually an event object here
+ if ( types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Handle multiple events seperated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ jQuery.each(types.split(/\s+/), function(index, type){
+ // Namespaced event handlers
+ var parts = type.split(".");
+ type = parts[0];
+
+ if ( events[type] ) {
+ // remove the given handler for the given type
+ if ( handler )
+ delete events[type][handler.guid];
+
+ // remove all handlers for the given type
+ else
+ for ( handler in events[type] )
+ // Handle the removal of namespaced events
+ if ( !parts[1] || events[type][handler].type == parts[1] )
+ delete events[type][handler];
+
+ // remove generic event handler if no more handlers exist
+ for ( ret in events[type] ) break;
+ if ( !ret ) {
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
+ if (elem.removeEventListener)
+ elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
+ else if (elem.detachEvent)
+ elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
+ }
+ ret = null;
+ delete events[type];
+ }
+ }
+ });
+ }
+
+ // Remove the expando if it's no longer used
+ for ( ret in events ) break;
+ if ( !ret ) {
+ var handle = jQuery.data( elem, "handle" );
+ if ( handle ) handle.elem = null;
+ jQuery.removeData( elem, "events" );
+ jQuery.removeData( elem, "handle" );
+ }
+ }
+ },
+
+ trigger: function(type, data, elem, donative, extra) {
+ // Clone the incoming data, if any
+ data = jQuery.makeArray(data);
+
+ if ( type.indexOf("!") >= 0 ) {
+ type = type.slice(0, -1);
+ var exclusive = true;
+ }
+
+ // Handle a global trigger
+ if ( !elem ) {
+ // Only trigger if we've ever bound an event for it
+ if ( this.global[type] )
+ jQuery("*").add([window, document]).trigger(type, data);
+
+ // Handle triggering a single element
+ } else {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return undefined;
+
+ var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
+ // Check to see if we need to provide a fake event, or not
+ event = !data[0] || !data[0].preventDefault;
+
+ // Pass along a fake event
+ if ( event ) {
+ data.unshift({
+ type: type,
+ target: elem,
+ preventDefault: function(){},
+ stopPropagation: function(){},
+ timeStamp: now()
+ });
+ data[0][expando] = true; // no need to fix fake event
+ }
+
+ // Enforce the right trigger type
+ data[0].type = type;
+ if ( exclusive )
+ data[0].exclusive = true;
+
+ // Trigger the event, it is assumed that "handle" is a function
+ var handle = jQuery.data(elem, "handle");
+ if ( handle )
+ val = handle.apply( elem, data );
+
+ // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
+ if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
+ val = false;
+
+ // Extra functions don't get the custom event object
+ if ( event )
+ data.shift();
+
+ // Handle triggering of extra function
+ if ( extra && jQuery.isFunction( extra ) ) {
+ // call the extra function and tack the current return value on the end for possible inspection
+ ret = extra.apply( elem, val == null ? data : data.concat( val ) );
+ // if anything is returned, give it precedence and have it overwrite the previous value
+ if (ret !== undefined)
+ val = ret;
+ }
+
+ // Trigger the native events (except for clicks on links)
+ if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
+ this.triggered = true;
+ try {
+ elem[ type ]();
+ // prevent IE from throwing an error for some hidden elements
+ } catch (e) {}
+ }
+
+ this.triggered = false;
+ }
+
+ return val;
+ },
+
+ handle: function(event) {
+ // returned undefined or false
+ var val, ret, namespace, all, handlers;
+
+ event = arguments[0] = jQuery.event.fix( event || window.event );
+
+ // Namespaced event handlers
+ namespace = event.type.split(".");
+ event.type = namespace[0];
+ namespace = namespace[1];
+ // Cache this now, all = true means, any handler
+ all = !namespace && !event.exclusive;
+
+ handlers = ( jQuery.data(this, "events") || {} )[event.type];
+
+ for ( var j in handlers ) {
+ var handler = handlers[j];
+
+ // Filter the functions by class
+ if ( all || handler.type == namespace ) {
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handler;
+ event.data = handler.data;
+
+ ret = handler.apply( this, arguments );
+
+ if ( val !== false )
+ val = ret;
+
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+
+ return val;
+ },
+
+ props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" "),
+
+ fix: function(event) {
+ if ( event[expando] == true )
+ return event;
+
+ // store a copy of the original event object
+ // and "clone" to set read-only properties
+ var originalEvent = event;
+ event = { originalEvent: originalEvent };
+
+ for ( var i = this.props.length, prop; i; ){
+ prop = this.props[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Mark it as fixed
+ event[expando] = true;
+
+ // add preventDefault and stopPropagation since
+ // they will not work on the clone
+ event.preventDefault = function() {
+ // if preventDefault exists run it on the original event
+ if (originalEvent.preventDefault)
+ originalEvent.preventDefault();
+ // otherwise set the returnValue property of the original event to false (IE)
+ originalEvent.returnValue = false;
+ };
+ event.stopPropagation = function() {
+ // if stopPropagation exists run it on the original event
+ if (originalEvent.stopPropagation)
+ originalEvent.stopPropagation();
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ originalEvent.cancelBubble = true;
+ };
+
+ // Fix timeStamp
+ event.timeStamp = event.timeStamp || now();
+
+ // Fix target property, if necessary
+ if ( !event.target )
+ event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+
+ // check if target is a textnode (safari)
+ if ( event.target.nodeType == 3 )
+ event.target = event.target.parentNode;
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && event.fromElement )
+ event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && event.clientX != null ) {
+ var doc = document.documentElement, body = document.body;
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
+ }
+
+ // Add which for key events
+ if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
+ event.which = event.charCode || event.keyCode;
+
+ // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+ if ( !event.metaKey && event.ctrlKey )
+ event.metaKey = event.ctrlKey;
+
+ // Add which for click: 1 == left; 2 == middle; 3 == right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && event.button )
+ event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+
+ return event;
+ },
+
+ proxy: function( fn, proxy ){
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
+ // So proxy can be declared as an argument
+ return proxy;
+ },
+
+ special: {
+ ready: {
+ setup: function() {
+ // Make sure the ready event is setup
+ bindReady();
+ return;
+ },
+
+ teardown: function() { return; }
+ },
+
+ mouseenter: {
+ setup: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
+ return true;
+ },
+
+ teardown: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
+ return true;
+ },
+
+ handler: function(event) {
+ // If we actually just moused on to a sub-element, ignore it
+ if ( withinElement(event, this) ) return true;
+ // Execute the right handlers by setting the event type to mouseenter
+ event.type = "mouseenter";
+ return jQuery.event.handle.apply(this, arguments);
+ }
+ },
+
+ mouseleave: {
+ setup: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
+ return true;
+ },
+
+ teardown: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
+ return true;
+ },
+
+ handler: function(event) {
+ // If we actually just moused on to a sub-element, ignore it
+ if ( withinElement(event, this) ) return true;
+ // Execute the right handlers by setting the event type to mouseleave
+ event.type = "mouseleave";
+ return jQuery.event.handle.apply(this, arguments);
+ }
+ }
+ }
+};
+
+jQuery.fn.extend({
+ bind: function( type, data, fn ) {
+ return type == "unload" ? this.one(type, data, fn) : this.each(function(){
+ jQuery.event.add( this, type, fn || data, fn && data );
+ });
+ },
+
+ one: function( type, data, fn ) {
+ var one = jQuery.event.proxy( fn || data, function(event) {
+ jQuery(this).unbind(event, one);
+ return (fn || data).apply( this, arguments );
+ });
+ return this.each(function(){
+ jQuery.event.add( this, type, one, fn && data);
+ });
+ },
+
+ unbind: function( type, fn ) {
+ return this.each(function(){
+ jQuery.event.remove( this, type, fn );
+ });
+ },
+
+ trigger: function( type, data, fn ) {
+ return this.each(function(){
+ jQuery.event.trigger( type, data, this, true, fn );
+ });
+ },
+
+ triggerHandler: function( type, data, fn ) {
+ return this[0] && jQuery.event.trigger( type, data, this[0], false, fn );
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments, i = 1;
+
+ // link all the functions, so any of them can unbind this click handler
+ while( i < args.length )
+ jQuery.event.proxy( fn, args[i++] );
+
+ return this.click( jQuery.event.proxy( fn, function(event) {
+ // Figure out which function to execute
+ this.lastToggle = ( this.lastToggle || 0 ) % i;
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ this.lastToggle++ ].apply( this, arguments ) || false;
+ }));
+ },
+
+ hover: function(fnOver, fnOut) {
+ return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
+ },
+
+ ready: function(fn) {
+ // Attach the listeners
+ bindReady();
+
+ // If the DOM is already ready
+ if ( jQuery.isReady )
+ // Execute the function immediately
+ fn.call( document, jQuery );
+
+ // Otherwise, remember the function for later
+ else
+ // Add the function to the wait list
+ jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
+
+ return this;
+ }
+});
+
+jQuery.extend({
+ isReady: false,
+ readyList: [],
+ // Handle when the DOM is ready
+ ready: function() {
+ // Make sure that the DOM is not already loaded
+ if ( !jQuery.isReady ) {
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If there are functions bound, to execute
+ if ( jQuery.readyList ) {
+ // Execute all of them
+ jQuery.each( jQuery.readyList, function(){
+ this.call( document );
+ });
+
+ // Reset the list of functions
+ jQuery.readyList = null;
+ }
+
+ // Trigger any bound ready events
+ jQuery(document).triggerHandler("ready");
+ }
+ }
+});
+
+var readyBound = false;
+
+function bindReady(){
+ if ( readyBound ) return;
+ readyBound = true;
+
+ // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
+ if ( document.addEventListener && !jQuery.browser.opera)
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
+
+ // If IE is used and is not in a frame
+ // Continually check to see if the document is ready
+ if ( jQuery.browser.msie && window == top ) (function(){
+ if (jQuery.isReady) return;
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch( error ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ })();
+
+ if ( jQuery.browser.opera )
+ document.addEventListener( "DOMContentLoaded", function () {
+ if (jQuery.isReady) return;
+ for (var i = 0; i < document.styleSheets.length; i++)
+ if (document.styleSheets[i].disabled) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ }, false);
+
+ if ( jQuery.browser.safari ) {
+ var numStyles;
+ (function(){
+ if (jQuery.isReady) return;
+ if ( document.readyState != "loaded" && document.readyState != "complete" ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ if ( numStyles === undefined )
+ numStyles = jQuery("style, link[rel=stylesheet]").length;
+ if ( document.styleSheets.length != numStyles ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ })();
+ }
+
+ // A fallback to window.onload, that will always work
+ jQuery.event.add( window, "load", jQuery.ready );
+}
+
+jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
+ "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
+ "submit,keydown,keypress,keyup,error").split(","), function(i, name){
+
+ // Handle event binding
+ jQuery.fn[name] = function(fn){
+ return fn ? this.bind(name, fn) : this.trigger(name);
+ };
+});
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function(event, elem) {
+ // Check if mouse(over|out) are still within the same parent element
+ var parent = event.relatedTarget;
+ // Traverse up the tree
+ while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
+ // Return true if we actually just moused on to a sub-element
+ return parent == elem;
+};
+
+// Prevent memory leaks in IE
+// And prevent errors on refresh with events like mouseover in other browsers
+// Window isn't included so as not to unbind existing unload events
+jQuery(window).bind("unload", function() {
+ jQuery("*").add(document).unbind();
+});
+jQuery.fn.extend({
+ // Keep a copy of the old load
+ _load: jQuery.fn.load,
+
+ load: function( url, params, callback ) {
+ if ( typeof url != 'string' )
+ return this._load( url );
+
+ var off = url.indexOf(" ");
+ if ( off >= 0 ) {
+ var selector = url.slice(off, url.length);
+ url = url.slice(0, off);
+ }
+
+ callback = callback || function(){};
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params )
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = null;
+
+ // Otherwise, build a param string
+ } else if( typeof params == 'object' ) {
+ params = jQuery.param( params );
+ type = "POST";
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ complete: function(res, status){
+ // If successful, inject the HTML into all the matched elements
+ if ( status == "success" || status == "notmodified" )
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div/>")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ res.responseText );
+
+ self.each( callback, [res.responseText, status, res] );
+ }
+ });
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param(this.serializeArray());
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ return jQuery.nodeName(this, "form") ?
+ jQuery.makeArray(this.elements) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ (this.checked || /select|textarea/i.test(this.nodeName) ||
+ /text|hidden|password/i.test(this.type));
+ })
+ .map(function(i, elem){
+ var val = jQuery(this).val();
+ return val == null ? null :
+ val.constructor == Array ?
+ jQuery.map( val, function(val, i){
+ return {name: elem.name, value: val};
+ }) :
+ {name: elem.name, value: val};
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
+ jQuery.fn[o] = function(f){
+ return this.bind(o, f);
+ };
+});
+
+var jsc = now();
+
+jQuery.extend({
+ get: function( url, data, callback, type ) {
+ // shift arguments if data argument was ommited
+ if ( jQuery.isFunction( data ) ) {
+ callback = data;
+ data = null;
+ }
+
+ return jQuery.ajax({
+ type: "GET",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get(url, null, callback, "script");
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get(url, data, callback, "json");
+ },
+
+ post: function( url, data, callback, type ) {
+ if ( jQuery.isFunction( data ) ) {
+ callback = data;
+ data = {};
+ }
+
+ return jQuery.ajax({
+ type: "POST",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ ajaxSetup: function( settings ) {
+ jQuery.extend( jQuery.ajaxSettings, settings );
+ },
+
+ ajaxSettings: {
+ url: location.href,
+ global: true,
+ type: "GET",
+ timeout: 0,
+ contentType: "application/x-www-form-urlencoded",
+ processData: true,
+ async: true,
+ data: null,
+ username: null,
+ password: null,
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ script: "text/javascript, application/javascript",
+ json: "application/json, text/javascript",
+ text: "text/plain",
+ _default: "*/*"
+ }
+ },
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+
+ ajax: function( s ) {
+ // Extend the settings, but re-extend 's' so that it can be
+ // checked again later (in the test suite, specifically)
+ s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
+
+ var jsonp, jsre = /=\?(&|$)/g, status, data,
+ type = s.type.toUpperCase();
+
+ // convert data if not already a string
+ if ( s.data && s.processData && typeof s.data != "string" )
+ s.data = jQuery.param(s.data);
+
+ // Handle JSONP Parameter Callbacks
+ if ( s.dataType == "jsonp" ) {
+ if ( type == "GET" ) {
+ if ( !s.url.match(jsre) )
+ s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+ } else if ( !s.data || !s.data.match(jsre) )
+ s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+ s.dataType = "json";
+ }
+
+ // Build temporary JSONP function
+ if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
+ jsonp = "jsonp" + jsc++;
+
+ // Replace the =? sequence both in the query string and the data
+ if ( s.data )
+ s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+ s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+
+ // We need to make sure
+ // that a JSONP style response is executed properly
+ s.dataType = "script";
+
+ // Handle JSONP-style loading
+ window[ jsonp ] = function(tmp){
+ data = tmp;
+ success();
+ complete();
+ // Garbage collect
+ window[ jsonp ] = undefined;
+ try{ delete window[ jsonp ]; } catch(e){}
+ if ( head )
+ head.removeChild( script );
+ };
+ }
+
+ if ( s.dataType == "script" && s.cache == null )
+ s.cache = false;
+
+ if ( s.cache === false && type == "GET" ) {
+ var ts = now();
+ // try replacing _= if it is there
+ var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
+ }
+
+ // If data is available, append data to url for get requests
+ if ( s.data && type == "GET" ) {
+ s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
+
+ // IE likes to send both get and post data, prevent this
+ s.data = null;
+ }
+
+ // Watch for a new set of requests
+ if ( s.global && ! jQuery.active++ )
+ jQuery.event.trigger( "ajaxStart" );
+
+ // Matches an absolute URL, and saves the domain
+ var remote = /^(?:\w+:)?\/\/([^\/?#]+)/;
+
+ // If we're requesting a remote document
+ // and trying to load JSON or Script with a GET
+ if ( s.dataType == "script" && type == "GET"
+ && remote.test(s.url) && remote.exec(s.url)[1] != location.host ){
+ var head = document.getElementsByTagName("head")[0];
+ var script = document.createElement("script");
+ script.src = s.url;
+ if (s.scriptCharset)
+ script.charset = s.scriptCharset;
+
+ // Handle Script loading
+ if ( !jsonp ) {
+ var done = false;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function(){
+ if ( !done && (!this.readyState ||
+ this.readyState == "loaded" || this.readyState == "complete") ) {
+ done = true;
+ success();
+ complete();
+ head.removeChild( script );
+ }
+ };
+ }
+
+ head.appendChild(script);
+
+ // We handle everything using the script element injection
+ return undefined;
+ }
+
+ var requestDone = false;
+
+ // Create the request object; Microsoft failed to properly
+ // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
+ var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if( s.username )
+ xhr.open(type, s.url, s.async, s.username, s.password);
+ else
+ xhr.open(type, s.url, s.async);
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ // Set the correct header, if data is being sent
+ if ( s.data )
+ xhr.setRequestHeader("Content-Type", s.contentType);
+
+ // Set the If-Modified-Since header, if ifModified mode.
+ if ( s.ifModified )
+ xhr.setRequestHeader("If-Modified-Since",
+ jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
+
+ // Set header so the called script knows that it's an XMLHttpRequest
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+
+ // Set the Accepts header for the server, depending on the dataType
+ xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
+ s.accepts[ s.dataType ] + ", */*" :
+ s.accepts._default );
+ } catch(e){}
+
+ // Allow custom headers/mimetypes
+ if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
+ // cleanup active request counter
+ s.global && jQuery.active--;
+ // close opended socket
+ xhr.abort();
+ return false;
+ }
+
+ if ( s.global )
+ jQuery.event.trigger("ajaxSend", [xhr, s]);
+
+ // Wait for a response to come back
+ var onreadystatechange = function(isTimeout){
+ // The transfer is complete and the data is available, or the request timed out
+ if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
+ requestDone = true;
+
+ // clear poll interval
+ if (ival) {
+ clearInterval(ival);
+ ival = null;
+ }
+
+ status = isTimeout == "timeout" ? "timeout" :
+ !jQuery.httpSuccess( xhr ) ? "error" :
+ s.ifModified && jQuery.httpNotModified( xhr, s.url ) ? "notmodified" :
+ "success";
+
+ if ( status == "success" ) {
+ // Watch for, and catch, XML document parse errors
+ try {
+ // process the data (runs the xml through httpData regardless of callback)
+ data = jQuery.httpData( xhr, s.dataType, s.dataFilter );
+ } catch(e) {
+ status = "parsererror";
+ }
+ }
+
+ // Make sure that the request was successful or notmodified
+ if ( status == "success" ) {
+ // Cache Last-Modified header, if ifModified mode.
+ var modRes;
+ try {
+ modRes = xhr.getResponseHeader("Last-Modified");
+ } catch(e) {} // swallow exception thrown by FF if header is not available
+
+ if ( s.ifModified && modRes )
+ jQuery.lastModified[s.url] = modRes;
+
+ // JSONP handles its own success callback
+ if ( !jsonp )
+ success();
+ } else
+ jQuery.handleError(s, xhr, status);
+
+ // Fire the complete handlers
+ complete();
+
+ // Stop memory leaks
+ if ( s.async )
+ xhr = null;
+ }
+ };
+
+ if ( s.async ) {
+ // don't attach the handler to the request, just poll it instead
+ var ival = setInterval(onreadystatechange, 13);
+
+ // Timeout checker
+ if ( s.timeout > 0 )
+ setTimeout(function(){
+ // Check to see if the request is still happening
+ if ( xhr ) {
+ // Cancel the request
+ xhr.abort();
+
+ if( !requestDone )
+ onreadystatechange( "timeout" );
+ }
+ }, s.timeout);
+ }
+
+ // Send the data
+ try {
+ xhr.send(s.data);
+ } catch(e) {
+ jQuery.handleError(s, xhr, null, e);
+ }
+
+ // firefox 1.5 doesn't fire statechange for sync requests
+ if ( !s.async )
+ onreadystatechange();
+
+ function success(){
+ // If a local callback was specified, fire it and pass it the data
+ if ( s.success )
+ s.success( data, status );
+
+ // Fire the global callback
+ if ( s.global )
+ jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
+ }
+
+ function complete(){
+ // Process result
+ if ( s.complete )
+ s.complete(xhr, status);
+
+ // The request was completed
+ if ( s.global )
+ jQuery.event.trigger( "ajaxComplete", [xhr, s] );
+
+ // Handle the global AJAX counter
+ if ( s.global && ! --jQuery.active )
+ jQuery.event.trigger( "ajaxStop" );
+ }
+
+ // return XMLHttpRequest to allow aborting the request etc.
+ return xhr;
+ },
+
+ handleError: function( s, xhr, status, e ) {
+ // If a local callback was specified, fire it
+ if ( s.error ) s.error( xhr, status, e );
+
+ // Fire the global callback
+ if ( s.global )
+ jQuery.event.trigger( "ajaxError", [xhr, s, e] );
+ },
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Determines if an XMLHttpRequest was successful or not
+ httpSuccess: function( xhr ) {
+ try {
+ // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+ return !xhr.status && location.protocol == "file:" ||
+ ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223 ||
+ jQuery.browser.safari && xhr.status == undefined;
+ } catch(e){}
+ return false;
+ },
+
+ // Determines if an XMLHttpRequest returns NotModified
+ httpNotModified: function( xhr, url ) {
+ try {
+ var xhrRes = xhr.getResponseHeader("Last-Modified");
+
+ // Firefox always returns 200. check Last-Modified date
+ return xhr.status == 304 || xhrRes == jQuery.lastModified[url] ||
+ jQuery.browser.safari && xhr.status == undefined;
+ } catch(e){}
+ return false;
+ },
+
+ httpData: function( xhr, type, filter ) {
+ var ct = xhr.getResponseHeader("content-type"),
+ xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if ( xml && data.documentElement.tagName == "parsererror" )
+ throw "parsererror";
+
+ // Allow a pre-filtering function to sanitize the response
+ if( filter )
+ data = filter( data, type );
+
+ // If the type is "script", eval it in global context
+ if ( type == "script" )
+ jQuery.globalEval( data );
+
+ // Get the JavaScript object, if JSON is used.
+ if ( type == "json" )
+ data = eval("(" + data + ")");
+
+ return data;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a ) {
+ var s = [ ];
+
+ function add( key, value ){
+ s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
+ };
+
+ // If an array was passed in, assume that it is an array
+ // of form elements
+ if ( a.constructor == Array || a.jquery )
+ // Serialize the form elements
+ jQuery.each( a, function(){
+ add( this.name, this.value );
+ });
+
+ // Otherwise, assume that it's an object of key/value pairs
+ else
+ // Serialize the key/values
+ for ( var j in a )
+ // If the value is an array then the key names need to be repeated
+ if ( a[j] && a[j].constructor == Array )
+ jQuery.each( a[j], function(){
+ add( j, this );
+ });
+ else
+ add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
+
+ // Return the resulting serialization
+ return s.join("&").replace(/%20/g, "+");
+ }
+
+});
+jQuery.fn.extend({
+ show: function(speed,callback){
+ return speed ?
+ this.animate({
+ height: "show", width: "show", opacity: "show"
+ }, speed, callback) :
+
+ this.filter(":hidden").each(function(){
+ this.style.display = this.oldblock || "";
+ if ( jQuery.css(this,"display") == "none" ) {
+ var elem = jQuery("<" + this.tagName + " />").appendTo("body");
+ this.style.display = elem.css("display");
+ // handle an edge condition where css is - div { display:none; } or similar
+ if (this.style.display == "none")
+ this.style.display = "block";
+ elem.remove();
+ }
+ }).end();
+ },
+
+ hide: function(speed,callback){
+ return speed ?
+ this.animate({
+ height: "hide", width: "hide", opacity: "hide"
+ }, speed, callback) :
+
+ this.filter(":visible").each(function(){
+ this.oldblock = this.oldblock || jQuery.css(this,"display");
+ this.style.display = "none";
+ }).end();
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2 ){
+ return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
+ this._toggle.apply( this, arguments ) :
+ fn ?
+ this.animate({
+ height: "toggle", width: "toggle", opacity: "toggle"
+ }, fn, fn2) :
+ this.each(function(){
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+ });
+ },
+
+ slideDown: function(speed,callback){
+ return this.animate({height: "show"}, speed, callback);
+ },
+
+ slideUp: function(speed,callback){
+ return this.animate({height: "hide"}, speed, callback);
+ },
+
+ slideToggle: function(speed, callback){
+ return this.animate({height: "toggle"}, speed, callback);
+ },
+
+ fadeIn: function(speed, callback){
+ return this.animate({opacity: "show"}, speed, callback);
+ },
+
+ fadeOut: function(speed, callback){
+ return this.animate({opacity: "hide"}, speed, callback);
+ },
+
+ fadeTo: function(speed,to,callback){
+ return this.animate({opacity: to}, speed, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed(speed, easing, callback);
+
+ return this[ optall.queue === false ? "each" : "queue" ](function(){
+ if ( this.nodeType != 1)
+ return false;
+
+ var opt = jQuery.extend({}, optall), p,
+ hidden = jQuery(this).is(":hidden"), self = this;
+
+ for ( p in prop ) {
+ if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
+ return opt.complete.call(this);
+
+ if ( p == "height" || p == "width" ) {
+ // Store display property
+ opt.display = jQuery.css(this, "display");
+
+ // Make sure that nothing sneaks out
+ opt.overflow = this.style.overflow;
+ }
+ }
+
+ if ( opt.overflow != null )
+ this.style.overflow = "hidden";
+
+ opt.curAnim = jQuery.extend({}, prop);
+
+ jQuery.each( prop, function(name, val){
+ var e = new jQuery.fx( self, opt, name );
+
+ if ( /toggle|show|hide/.test(val) )
+ e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
+ else {
+ var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
+ start = e.cur(true) || 0;
+
+ if ( parts ) {
+ var end = parseFloat(parts[2]),
+ unit = parts[3] || "px";
+
+ // We need to compute starting value
+ if ( unit != "px" ) {
+ self.style[ name ] = (end || 1) + unit;
+ start = ((end || 1) / e.cur(true)) * start;
+ self.style[ name ] = start + unit;
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] )
+ end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
+
+ e.custom( start, end, unit );
+ } else
+ e.custom( start, val, "" );
+ }
+ });
+
+ // For JS strict compliance
+ return true;
+ });
+ },
+
+ queue: function(type, fn){
+ if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
+ fn = type;
+ type = "fx";
+ }
+
+ if ( !type || (typeof type == "string" && !fn) )
+ return queue( this[0], type );
+
+ return this.each(function(){
+ if ( fn.constructor == Array )
+ queue(this, type, fn);
+ else {
+ queue(this, type).push( fn );
+
+ if ( queue(this, type).length == 1 )
+ fn.call(this);
+ }
+ });
+ },
+
+ stop: function(clearQueue, gotoEnd){
+ var timers = jQuery.timers;
+
+ if (clearQueue)
+ this.queue([]);
+
+ this.each(function(){
+ // go in reverse order so anything added to the queue during the loop is ignored
+ for ( var i = timers.length - 1; i >= 0; i-- )
+ if ( timers[i].elem == this ) {
+ if (gotoEnd)
+ // force the next step to be the last
+ timers[i](true);
+ timers.splice(i, 1);
+ }
+ });
+
+ // start the next in the queue if the last step wasn't forced
+ if (!gotoEnd)
+ this.dequeue();
+
+ return this;
+ }
+
+});
+
+var queue = function( elem, type, array ) {
+ if ( elem ){
+
+ type = type || "fx";
+
+ var q = jQuery.data( elem, type + "queue" );
+
+ if ( !q || array )
+ q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );
+
+ }
+ return q;
+};
+
+jQuery.fn.dequeue = function(type){
+ type = type || "fx";
+
+ return this.each(function(){
+ var q = queue(this, type);
+
+ q.shift();
+
+ if ( q.length )
+ q[0].call( this );
+ });
+};
+
+jQuery.extend({
+
+ speed: function(speed, easing, fn) {
+ var opt = speed && speed.constructor == Object ? speed : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && easing.constructor != Function && easing
+ };
+
+ opt.duration = (opt.duration && opt.duration.constructor == Number ?
+ opt.duration :
+ jQuery.fx.speeds[opt.duration]) || jQuery.fx.speeds.def;
+
+ // Queueing
+ opt.old = opt.complete;
+ opt.complete = function(){
+ if ( opt.queue !== false )
+ jQuery(this).dequeue();
+ if ( jQuery.isFunction( opt.old ) )
+ opt.old.call( this );
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p, n, firstNum, diff ) {
+ return firstNum + diff * p;
+ },
+ swing: function( p, n, firstNum, diff ) {
+ return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+ }
+ },
+
+ timers: [],
+ timerId: null,
+
+ fx: function( elem, options, prop ){
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ if ( !options.orig )
+ options.orig = {};
+ }
+
+});
+
+jQuery.fx.prototype = {
+
+ // Simple function for setting a style value
+ update: function(){
+ if ( this.options.step )
+ this.options.step.call( this.elem, this.now, this );
+
+ (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+
+ // Set display property to block for height/width animations
+ if ( this.prop == "height" || this.prop == "width" )
+ this.elem.style.display = "block";
+ },
+
+ // Get the current size
+ cur: function(force){
+ if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null )
+ return this.elem[ this.prop ];
+
+ var r = parseFloat(jQuery.css(this.elem, this.prop, force));
+ return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+ },
+
+ // Start an animation from one number to another
+ custom: function(from, to, unit){
+ this.startTime = now();
+ this.start = from;
+ this.end = to;
+ this.unit = unit || this.unit || "px";
+ this.now = this.start;
+ this.pos = this.state = 0;
+ this.update();
+
+ var self = this;
+ function t(gotoEnd){
+ return self.step(gotoEnd);
+ }
+
+ t.elem = this.elem;
+
+ jQuery.timers.push(t);
+
+ if ( jQuery.timerId == null ) {
+ jQuery.timerId = setInterval(function(){
+ var timers = jQuery.timers;
+
+ for ( var i = 0; i < timers.length; i++ )
+ if ( !timers[i]() )
+ timers.splice(i--, 1);
+
+ if ( !timers.length ) {
+ clearInterval( jQuery.timerId );
+ jQuery.timerId = null;
+ }
+ }, 13);
+ }
+ },
+
+ // Simple 'show' function
+ show: function(){
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ this.custom(0, this.cur());
+
+ // Make sure that we start at a small width/height to avoid any
+ // flash of content
+ if ( this.prop == "width" || this.prop == "height" )
+ this.elem.style[this.prop] = "1px";
+
+ // Start by showing the element
+ jQuery(this.elem).show();
+ },
+
+ // Simple 'hide' function
+ hide: function(){
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom(this.cur(), 0);
+ },
+
+ // Each step of an animation
+ step: function(gotoEnd){
+ var t = now();
+
+ if ( gotoEnd || t > this.options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ this.options.curAnim[ this.prop ] = true;
+
+ var done = true;
+ for ( var i in this.options.curAnim )
+ if ( this.options.curAnim[i] !== true )
+ done = false;
+
+ if ( done ) {
+ if ( this.options.display != null ) {
+ // Reset the overflow
+ this.elem.style.overflow = this.options.overflow;
+
+ // Reset the display
+ this.elem.style.display = this.options.display;
+ if ( jQuery.css(this.elem, "display") == "none" )
+ this.elem.style.display = "block";
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( this.options.hide )
+ this.elem.style.display = "none";
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( this.options.hide || this.options.show )
+ for ( var p in this.options.curAnim )
+ jQuery.attr(this.elem.style, p, this.options.orig[p]);
+ }
+
+ if ( done )
+ // Execute the complete function
+ this.options.complete.call( this.elem );
+
+ return false;
+ } else {
+ var n = t - this.startTime;
+ this.state = n / this.options.duration;
+
+ // Perform the easing function, defaults to swing
+ this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
+ this.now = this.start + ((this.end - this.start) * this.pos);
+
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+
+};
+
+jQuery.extend( jQuery.fx, {
+ speeds:{
+ slow: 600,
+ fast: 200,
+ // Default speed
+ def: 400
+ },
+ step: {
+ scrollLeft: function(fx){
+ fx.elem.scrollLeft = fx.now;
+ },
+
+ scrollTop: function(fx){
+ fx.elem.scrollTop = fx.now;
+ },
+
+ opacity: function(fx){
+ jQuery.attr(fx.elem.style, "opacity", fx.now);
+ },
+
+ _default: function(fx){
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+ }
+ }
+});
+// The Offset Method
+// Originally By Brandon Aaron, part of the Dimension Plugin
+// http://jquery.com/plugins/project/dimensions
+jQuery.fn.offset = function() {
+ var left = 0, top = 0, elem = this[0], results;
+
+ if ( elem ) with ( jQuery.browser ) {
+ var parent = elem.parentNode,
+ offsetChild = elem,
+ offsetParent = elem.offsetParent,
+ doc = elem.ownerDocument,
+ safari2 = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
+ css = jQuery.curCSS,
+ fixed = css(elem, "position") == "fixed";
+
+ // Use getBoundingClientRect if available
+ if ( !(mozilla && elem == document.body) && elem.getBoundingClientRect ) {
+ var box = elem.getBoundingClientRect();
+
+ // Add the document scroll offsets
+ add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+ box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
+
+ // IE adds the HTML element's border, by default it is medium which is 2px
+ // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
+ // IE 7 standards mode, the border is always 2px
+ // This border/offset is typically represented by the clientLeft and clientTop properties
+ // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
+ // Therefore this method will be off by 2px in IE while in quirksmode
+ add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
+
+ // Otherwise loop through the offsetParents and parentNodes
+ } else {
+
+ // Initial element offsets
+ add( elem.offsetLeft, elem.offsetTop );
+
+ // Get parent offsets
+ while ( offsetParent ) {
+ // Add offsetParent offsets
+ add( offsetParent.offsetLeft, offsetParent.offsetTop );
+
+ // Mozilla and Safari > 2 does not include the border on offset parents
+ // However Mozilla adds the border for table or table cells
+ if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
+ border( offsetParent );
+
+ // Add the document scroll offsets if position is fixed on any offsetParent
+ if ( !fixed && css(offsetParent, "position") == "fixed" )
+ fixed = true;
+
+ // Set offsetChild to previous offsetParent unless it is the body element
+ offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
+ // Get next offsetParent
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ // Get parent scroll offsets
+ while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
+ // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
+ if ( !/^inline|table.*$/i.test(css(parent, "display")) )
+ // Subtract parent scroll offsets
+ add( -parent.scrollLeft, -parent.scrollTop );
+
+ // Mozilla does not add the border for a parent that has overflow != visible
+ if ( mozilla && css(parent, "overflow") != "visible" )
+ border( parent );
+
+ // Get next parent
+ parent = parent.parentNode;
+ }
+
+ // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
+ // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
+ if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
+ (mozilla && css(offsetChild, "position") != "absolute") )
+ add( -doc.body.offsetLeft, -doc.body.offsetTop );
+
+ // Add the document scroll offsets if position is fixed
+ if ( fixed )
+ add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+ Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
+ }
+
+ // Return an object with top and left properties
+ results = { top: top, left: left };
+ }
+
+ function border(elem) {
+ add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
+ }
+
+ function add(l, t) {
+ left += parseInt(l, 10) || 0;
+ top += parseInt(t, 10) || 0;
+ }
+
+ return results;
+};
+
+
+jQuery.fn.extend({
+ position: function() {
+ var left = 0, top = 0, results;
+
+ if ( this[0] ) {
+ // Get *real* offsetParent
+ var offsetParent = this.offsetParent(),
+
+ // Get correct offsets
+ offset = this.offset(),
+ parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+ // Subtract element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ offset.top -= num( this, 'marginTop' );
+ offset.left -= num( this, 'marginLeft' );
+
+ // Add offsetParent borders
+ parentOffset.top += num( offsetParent, 'borderTopWidth' );
+ parentOffset.left += num( offsetParent, 'borderLeftWidth' );
+
+ // Subtract the two offsets
+ results = {
+ top: offset.top - parentOffset.top,
+ left: offset.left - parentOffset.left
+ };
+ }
+
+ return results;
+ },
+
+ offsetParent: function() {
+ var offsetParent = this[0].offsetParent;
+ while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
+ offsetParent = offsetParent.offsetParent;
+ return jQuery(offsetParent);
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ['Left', 'Top'], function(i, name) {
+ var method = 'scroll' + name;
+
+ jQuery.fn[ method ] = function(val) {
+ if (!this[0]) return;
+
+ return val != undefined ?
+
+ // Set the scroll offset
+ this.each(function() {
+ this == window || this == document ?
+ window.scrollTo(
+ !i ? val : jQuery(window).scrollLeft(),
+ i ? val : jQuery(window).scrollTop()
+ ) :
+ this[ method ] = val;
+ }) :
+
+ // Return the scroll offset
+ this[0] == window || this[0] == document ?
+ self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
+ jQuery.boxModel && document.documentElement[ method ] ||
+ document.body[ method ] :
+ this[0][ method ];
+ };
+});
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function(i, name){
+
+ var tl = i ? "Left" : "Top", // top or left
+ br = i ? "Right" : "Bottom"; // bottom or right
+
+ // innerHeight and innerWidth
+ jQuery.fn["inner" + name] = function(){
+ return this[ name.toLowerCase() ]() +
+ num(this, "padding" + tl) +
+ num(this, "padding" + br);
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn["outer" + name] = function(margin) {
+ return this["inner" + name]() +
+ num(this, "border" + tl + "Width") +
+ num(this, "border" + br + "Width") +
+ (margin ?
+ num(this, "margin" + tl) + num(this, "margin" + br) : 0);
+ };
+
+});})();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/lib/thickbox-compressed.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,10 @@
+/*
+ * Thickbox 3 - One Box To Rule Them All.
+ * By Cody Lindley (http://www.codylindley.com)
+ * Copyright (c) 2007 cody lindley
+ * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+var tb_pathToImage = "images/loadingAnimation.gif";
+
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$(o).2S(9(){1u(\'a.18, 3n.18, 3i.18\');1w=1p 1t();1w.L=2H});9 1u(b){$(b).s(9(){6 t=X.Q||X.1v||M;6 a=X.u||X.23;6 g=X.1N||P;19(t,a,g);X.2E();H P})}9 19(d,f,g){3m{3(2t o.v.J.2i==="2g"){$("v","11").r({A:"28%",z:"28%"});$("11").r("22","2Z");3(o.1Y("1F")===M){$("v").q("<U 5=\'1F\'></U><4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}n{3(o.1Y("B")===M){$("v").q("<4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}3(1K()){$("#B").1J("2B")}n{$("#B").1J("2z")}3(d===M){d=""}$("v").q("<4 5=\'K\'><1I L=\'"+1w.L+"\' /></4>");$(\'#K\').2y();6 h;3(f.O("?")!==-1){h=f.3l(0,f.O("?"))}n{h=f}6 i=/\\.2s$|\\.2q$|\\.2m$|\\.2l$|\\.2k$/;6 j=h.1C().2h(i);3(j==\'.2s\'||j==\'.2q\'||j==\'.2m\'||j==\'.2l\'||j==\'.2k\'){1D="";1G="";14="";1z="";1x="";R="";1n="";1r=P;3(g){E=$("a[@1N="+g+"]").36();25(D=0;((D<E.1c)&&(R===""));D++){6 k=E[D].u.1C().2h(i);3(!(E[D].u==f)){3(1r){1z=E[D].Q;1x=E[D].u;R="<1e 5=\'1X\'>&1d;&1d;<a u=\'#\'>2T &2R;</a></1e>"}n{1D=E[D].Q;1G=E[D].u;14="<1e 5=\'1U\'>&1d;&1d;<a u=\'#\'>&2O; 2N</a></1e>"}}n{1r=1b;1n="1t "+(D+1)+" 2L "+(E.1c)}}}S=1p 1t();S.1g=9(){S.1g=M;6 a=2x();6 x=a[0]-1M;6 y=a[1]-1M;6 b=S.z;6 c=S.A;3(b>x){c=c*(x/b);b=x;3(c>y){b=b*(y/c);c=y}}n 3(c>y){b=b*(y/c);c=y;3(b>x){c=c*(x/b);b=x}}13=b+30;1a=c+2G;$("#8").q("<a u=\'\' 5=\'1L\' Q=\'1o\'><1I 5=\'2F\' L=\'"+f+"\' z=\'"+b+"\' A=\'"+c+"\' 23=\'"+d+"\'/></a>"+"<4 5=\'2D\'>"+d+"<4 5=\'2C\'>"+1n+14+R+"</4></4><4 5=\'2A\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4>");$("#Z").s(G);3(!(14==="")){9 12(){3($(o).N("s",12)){$(o).N("s",12)}$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1D,1G,g);H P}$("#1U").s(12)}3(!(R==="")){9 1i(){$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1z,1x,g);H P}$("#1X").s(1i)}o.1h=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}n 3(I==3k){3(!(R=="")){o.1h="";1i()}}n 3(I==3j){3(!(14=="")){o.1h="";12()}}};16();$("#K").C();$("#1L").s(G);$("#8").r({Y:"T"})};S.L=f}n{6 l=f.2r(/^[^\\?]+\\??/,\'\');6 m=2p(l);13=(m[\'z\']*1)+30||3h;1a=(m[\'A\']*1)+3g||3f;W=13-30;V=1a-3e;3(f.O(\'2j\')!=-1){1E=f.1B(\'3d\');$("#15").C();3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4></4><U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\' > </U>")}n{$("#B").N();$("#8").q("<U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\'> </U>")}}n{3($("#8").r("Y")!="T"){3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\'>1l</a> 1k 1j 1s</4></4><4 5=\'F\' J=\'z:"+W+"p;A:"+V+"p\'></4>")}n{$("#B").N();$("#8").q("<4 5=\'F\' 3c=\'3b\' J=\'z:"+W+"p;A:"+V+"p;\'></4>")}}n{$("#F")[0].J.z=W+"p";$("#F")[0].J.A=V+"p";$("#F")[0].3a=0;$("#1H").11(d)}}$("#Z").s(G);3(f.O(\'37\')!=-1){$("#F").q($(\'#\'+m[\'26\']).1T());$("#8").24(9(){$(\'#\'+m[\'26\']).q($("#F").1T())});16();$("#K").C();$("#8").r({Y:"T"})}n 3(f.O(\'2j\')!=-1){16();3($.1q.35){$("#K").C();$("#8").r({Y:"T"})}}n{$("#F").34(f+="&1y="+(1p 33().32()),9(){16();$("#K").C();1u("#F a.18");$("#8").r({Y:"T"})})}}3(!m[\'1A\']){o.21=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}}}}31(e){}}9 1m(){$("#K").C();$("#8").r({Y:"T"})}9 G(){$("#2Y").N("s");$("#Z").N("s");$("#8").2X("2W",9(){$(\'#8,#B,#1F\').2V("24").N().C()});$("#K").C();3(2t o.v.J.2i=="2g"){$("v","11").r({A:"1Z",z:"1Z"});$("11").r("22","")}o.1h="";o.21="";H P}9 16(){$("#8").r({2U:\'-\'+20((13/2),10)+\'p\',z:13+\'p\'});3(!(1V.1q.2Q&&1V.1q.2P<7)){$("#8").r({38:\'-\'+20((1a/2),10)+\'p\'})}}9 2p(a){6 b={};3(!a){H b}6 c=a.1B(/[;&]/);25(6 i=0;i<c.1c;i++){6 d=c[i].1B(\'=\');3(!d||d.1c!=2){39}6 e=2a(d[0]);6 f=2a(d[1]);f=f.2r(/\\+/g,\' \');b[e]=f}H b}9 2x(){6 a=o.2M;6 w=1S.2o||1R.2o||(a&&a.1Q)||o.v.1Q;6 h=1S.1P||1R.1P||(a&&a.2n)||o.v.2n;1O=[w,h];H 1O}9 1K(){6 a=2K.2J.1C();3(a.O(\'2I\')!=-1&&a.O(\'3o\')!=-1){H 1b}}',62,211,'|||if|div|id|var||TB_window|function||||||||||||||else|document|px|append|css|click||href|body||||width|height|TB_overlay|remove|TB_Counter|TB_TempArray|TB_ajaxContent|tb_remove|return|keycode|style|TB_load|src|null|unbind|indexOf|false|title|TB_NextHTML|imgPreloader|block|iframe|ajaxContentH|ajaxContentW|this|display|TB_closeWindowButton||html|goPrev|TB_WIDTH|TB_PrevHTML|TB_iframeContent|tb_position||thickbox|tb_show|TB_HEIGHT|true|length|nbsp|span|Math|onload|onkeydown|goNext|Esc|or|close|tb_showIframe|TB_imageCount|Close|new|browser|TB_FoundURL|Key|Image|tb_init|name|imgLoader|TB_NextURL|random|TB_NextCaption|modal|split|toLowerCase|TB_PrevCaption|urlNoQuery|TB_HideSelect|TB_PrevURL|TB_ajaxWindowTitle|img|addClass|tb_detectMacXFF|TB_ImageOff|150|rel|arrayPageSize|innerHeight|clientWidth|self|window|children|TB_prev|jQuery|frameborder|TB_next|getElementById|auto|parseInt|onkeyup|overflow|alt|unload|for|inlineId||100||unescape|1000|round|hspace|TB_closeAjaxWindow|TB_title|undefined|match|maxHeight|TB_iframe|bmp|gif|png|clientHeight|innerWidth|tb_parseQuery|jpeg|replace|jpg|typeof|which|keyCode|event|tb_getPageSize|show|TB_overlayBG|TB_closeWindow|TB_overlayMacFFBGHack|TB_secondLine|TB_caption|blur|TB_Image|60|tb_pathToImage|mac|userAgent|navigator|of|documentElement|Prev|lt|version|msie|gt|ready|Next|marginLeft|trigger|fast|fadeOut|TB_imageOff|hidden||catch|getTime|Date|load|safari|get|TB_inline|marginTop|continue|scrollTop|TB_modal|class|TB_|45|440|40|630|input|188|190|substr|try|area|firefox'.split('|'),0,{}))
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/lib/thickbox.css Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,163 @@
+/* ----------------------------------------------------------------------------------------------------------------*/
+/* ---------->>> global settings needed for thickbox <<<-----------------------------------------------------------*/
+/* ----------------------------------------------------------------------------------------------------------------*/
+*{padding: 0; margin: 0;}
+
+/* ----------------------------------------------------------------------------------------------------------------*/
+/* ---------->>> thickbox specific link and font settings <<<------------------------------------------------------*/
+/* ----------------------------------------------------------------------------------------------------------------*/
+#TB_window {
+ font: 12px Arial, Helvetica, sans-serif;
+ color: #333333;
+}
+
+#TB_secondLine {
+ font: 10px Arial, Helvetica, sans-serif;
+ color:#666666;
+}
+
+#TB_window a:link {color: #666666;}
+#TB_window a:visited {color: #666666;}
+#TB_window a:hover {color: #000;}
+#TB_window a:active {color: #666666;}
+#TB_window a:focus{color: #666666;}
+
+/* ----------------------------------------------------------------------------------------------------------------*/
+/* ---------->>> thickbox settings <<<-----------------------------------------------------------------------------*/
+/* ----------------------------------------------------------------------------------------------------------------*/
+#TB_overlay {
+ position: fixed;
+ z-index:100;
+ top: 0px;
+ left: 0px;
+ height:100%;
+ width:100%;
+}
+
+.TB_overlayMacFFBGHack {background: url(macFFBgHack.png) repeat;}
+.TB_overlayBG {
+ background-color:#000;
+ filter:alpha(opacity=75);
+ -moz-opacity: 0.75;
+ opacity: 0.75;
+}
+
+* html #TB_overlay { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_window {
+ position: fixed;
+ background: #ffffff;
+ z-index: 102;
+ color:#000000;
+ display:none;
+ border: 4px solid #525252;
+ text-align:left;
+ top:50%;
+ left:50%;
+}
+
+* html #TB_window { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_window img#TB_Image {
+ display:block;
+ margin: 15px 0 0 15px;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ border-top: 1px solid #666;
+ border-left: 1px solid #666;
+}
+
+#TB_caption{
+ height:25px;
+ padding:7px 30px 10px 25px;
+ float:left;
+}
+
+#TB_closeWindow{
+ height:25px;
+ padding:11px 25px 10px 0;
+ float:right;
+}
+
+#TB_closeAjaxWindow{
+ padding:7px 10px 5px 0;
+ margin-bottom:1px;
+ text-align:right;
+ float:right;
+}
+
+#TB_ajaxWindowTitle{
+ float:left;
+ padding:7px 0 5px 10px;
+ margin-bottom:1px;
+}
+
+#TB_title{
+ background-color:#e8e8e8;
+ height:27px;
+}
+
+#TB_ajaxContent{
+ clear:both;
+ padding:2px 15px 15px 15px;
+ overflow:auto;
+ text-align:left;
+ line-height:1.4em;
+}
+
+#TB_ajaxContent.TB_modal{
+ padding:15px;
+}
+
+#TB_ajaxContent p{
+ padding:5px 0px 5px 0px;
+}
+
+#TB_load{
+ position: fixed;
+ display:none;
+ height:13px;
+ width:208px;
+ z-index:103;
+ top: 50%;
+ left: 50%;
+ margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */
+}
+
+* html #TB_load { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_HideSelect{
+ z-index:99;
+ position:fixed;
+ top: 0;
+ left: 0;
+ background-color:#fff;
+ border:none;
+ filter:alpha(opacity=0);
+ -moz-opacity: 0;
+ opacity: 0;
+ height:100%;
+ width:100%;
+}
+
+* html #TB_HideSelect { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_iframeContent{
+ clear:both;
+ border:none;
+ margin-bottom:-1px;
+ margin-top:1px;
+ _margin-bottom:1px;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-autocomplete/todo Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,166 @@
+TODO
+
+- test formatItem implementation that returns (clickable) anchors
+- bug: handle del key; eg. type a letter, remove it using del, type same letter again: nothing happens
+- handle up/down keys in textarea (prevent default while select is open?)
+- docs: max:0 works, too, "removing" it(??)
+- fix ac_loading/options.loadingClass
+- support/enable request urls like foo/bar/10 instead of foo/q=10
+- urlencode request term before passing to $.ajax/data; evaluate why $.ajax doesn't handle that itself, if at all; try with umlauts, russian/danish/chinese characeters (see validate)
+- test what happens when an element gets focused programmatically (maybe even before then autcomplete is applied)
+- check if blur on selecting can be removed
+- fix keyhandling to ignore metakeys, eg. shift; especially important for chinese characters that need more then one key
+- enhance mustMatch: provide event/callback when a value gets deleted
+- handle tab key different then enter, eg. don't blur field or prevent default, just let it move on; in any case, no need to blur the field when selecting a value via tab, unlike return
+- prevent redundant requests on
+ - superstring returned no result, no need to query again for substring, eg. pete returned nothing, peter won't either
+ - previous query mustn't be requested again, eg. pete returns 10 lines, peter nothing, backspace to pete should get the 10 lines from cache (may need TimeToLive setting for cache to invalidate it)
+- incorporate improvements and suggestions by Hector: http://beta.winserver.com/public/test/MultiSuggestTest.wct
+- json support: An optional JSON format, that assumes a certain JSON format as default and just looks for a dataType "json" to be activated; [records], where each record is { id:String, label:String, moreOptionalValues... }
+- accept callback as first argument to let users implement their own dynamic data (no caching) - consider async API
+- allow users to keep their incomplete value when pressing tab, just mimic the default-browser-autocomplete: tab doesn't select any proposed value -> tab closes the select and works normal otherwise
+- small bug in your autocomplete, When setting autoFill:true I would expect formatResult to be called on autofill, it seems not to be the case.
+- add a callback to allow decoding the response
+- allow modification of not-last value in multiple-fields
+@option Number size Limit the number of items to show at once. Default:
+@option Function parse - TEST AND DOCUMENT ME
+- add option to display selectbox on focus
+
+$input.bind("show", function() {
+ if ( !select.visible() ) {
+ onChange(0, true);
+ }
+});
+
+- reference: http://capxous.com/
+ - add "try ..." hints to demo
+ - check out demos
+- reference: http://createwebapp.com/demo/
+
+- add option to hide selectbox when no match is found - see comment by Ian on plugin page (14. Juli 2007 04:31)
+- add example for reinitializing an autocomplete using unbind()
+
+- Add option to pass through additional arguments to $.ajax, like type to use POST instead of GET
+
+ - I found out that the problem with UTF-8 not being correctly sent can be solved on the server side by applying (PHP) rawurldecode() function, which decodes the Unicode characters sent by GET method and therefore URL-encoded.
+-> add that hint to docs and examples
+
+But I am trying this with these three values: “foo barâ€, “foo fooâ€, and “foo farâ€, and if I enter “b†(or “baâ€) nothing matches, if I enter “f†all three do match, and if I enter “fa†the last one matches.
+The problem seems to be that the cache is implemented with a first-character hashtable, so only after matching the first character, the latter ones are searched for.
+
+xml example:
+<script type="text/javascript">
+ function parseXML(data) {
+ var results = [];
+ var branches = $(data).find('item');
+ $(branches).each(function() {
+ var text = $.trim($(this).find('text').text());
+ var value = $.trim($(this).find('value').text());
+ //console.log(text);
+ //console.log(value);
+ results[results.length] = {'data': this, 'result': value, 'value': text};
+ });
+ $(results).each(function() {
+ //console.log('value', this.value);
+ //console.log('text', this.text);
+ });
+ //console.log(results);
+ return results;
+ };
+ $(YourOojHere).autocomplete(SERVER_AJAX_URL, {parse: parseXML});
+ </script>
+<?xml version="1.0"?>
+<ajaxresponse>
+ <item>
+ <text>
+ <![CDATA[<b>FreeNode:</b> irc.freenode.net:6667]]>
+ </text>
+ <value><![CDATA[irc.freenode.net:6667]]></value>
+ </item><item>
+ <text>
+ <![CDATA[<b>irc.oftc.net</b>:6667]]>
+ </text>
+ <value><![CDATA[irc.oftc.net:6667]]></value>
+ </item><item>
+ <text>
+ <![CDATA[<b>irc.undernet.org</b>:6667]]>
+ </text>
+ <value><![CDATA[irc.undernet.org:6667]]></value>
+ </item>
+</ajaxresponse>
+
+
+
+Hi all,
+
+I use Autocomplete 1.0 Alpha mostly for form inputs bound to foreign
+key columns. For instance I have a user_position table with two
+columns: user_id and position_id. On new appointment form I have two
+autocomplete text inputs with the following code:
+
+ <input type="text" id="user_id" class="ac_input" tabindex="1" />
+ <input type="text" id="position_id" class="ac_input" tabindex="2" />
+
+As you can see the inputs do not have a name attribute, and when the
+form is submitted their values are not sent, which is all right since
+they will contain strings like:
+
+ 'John Doe'
+ 'Sales Manager'
+
+whereas our backend expects something like:
+
+ 23
+ 14
+
+which are the user_id for John Doe and position_id for Sales Manager.
+To send these values I have two hidden inputs in the form like this:
+
+ <input type="hidden" name="user_id" value="">
+ <input type="hidden" name="position_id" value="">
+
+Also I have the following code in the $().ready function:
+
+ $("#user_id").result(function(event, data, formatted) {
+ $("input[@name=user_id]").val(data[1]);
+ });
+ $("#position_id").result(function(event, data, formatted) {
+ $("input[@name=position_id]").val(data[1]);
+ });
+
+As could be seen these functions stuff user_id and position_id values
+(in our example 23 and 14) into the hidden inputs, and when the form
+is submitted these values are sent:
+
+ user_id = 23
+ position_id = 14
+
+The backend script then takes care of adding a record to our
+user_position table containing those values.
+
+I wonder how could the plugin code be modified to simplify the setup
+by taking care of adding hidden inputs and updating the value of
+hidden inputs as default behavior. I have successfully attempted a
+simpler solution - writing a wrapper to perform these additional tasks
+and invoke autocomplete as well. I hope my intention is clear enough,
+if not, this is exactly the expected outcome:
+
+Before:
+
+ <script type="text/javascript"
+ src="jquery.autocomplete-modified.js"></script>
+ <input type="text" name="user_id" class="ac_input" tabindex="1" />
+
+After:
+
+ <input type="text" id="user_id" class="ac_input" tabindex="1" />
+ <input type="hidden" name="user_id" value="23">
+
+
+Last word, I know this looks like a tall order, and I do not hope
+someone will make a complete working mod for me, but rather would very
+much appreciate helpful advise and directions.
+
+Many thanks in advance
+Majid
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery-ui-1.8.16.custom.min.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,791 @@
+/*!
+ * jQuery UI 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI
+ */
+(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.16",
+keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({propAttr:c.fn.prop||c.fn.attr,_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=
+this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,
+"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":
+"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,
+outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a,
+"tabindex"),d=isNaN(b);return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&
+a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&
+c.ui.isOverAxis(b,e,i)}})}})(jQuery);
+;/*!
+ * jQuery UI Widget 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Widget
+ */
+(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)try{b(d).triggerHandler("remove")}catch(e){}k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(d){}});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=
+function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):
+d;if(e&&d.charAt(0)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=
+b.extend(true,{},this.options,this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+
+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",
+c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
+;/*!
+ * jQuery UI Mouse 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Mouse
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ */
+(function(b){var d=false;b(document).mouseup(function(){d=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+
+this.widgetName)},_mouseDown:function(a){if(!d){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,f=a.which==1,g=typeof this.options.cancel=="string"&&a.target.nodeName?b(a.target).closest(this.options.cancel).length:false;if(!f||g||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=
+this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(e){return c._mouseMove(e)};this._mouseUpDelegate=function(e){return c._mouseUp(e)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return d=true}},_mouseMove:function(a){if(b.browser.msie&&
+!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=
+false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
+;/*
+ * jQuery UI Position 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Position
+ */
+(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,
+left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=
+k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=
+m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
+d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=
+a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),
+g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
+;/*
+ * jQuery UI Draggable 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
+"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
+this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;if(b.iframeFix)d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;
+this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});
+this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true},
+_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=
+false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,
+10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||
+!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&
+a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=
+this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),
+10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),
+10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,
+(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!=
+"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),
+10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+
+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&
+!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.left<g[0])e=g[0]+this.offset.click.left;
+if(a.pageY-this.offset.click.top<g[1])h=g[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>g[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.top<g[1]||h-this.offset.click.top>g[3])?h:!(h-this.offset.click.top<g[1])?h-b.grid[1]:h+b.grid[1]:h;e=b.grid[0]?this.originalPageX+Math.round((e-this.originalPageX)/
+b.grid[0])*b.grid[0]:this.originalPageX;e=g?!(e-this.offset.click.left<g[0]||e-this.offset.click.left>g[2])?e:!(e-this.offset.click.left<g[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<
+526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,
+c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.16"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var h=d.data(this,"sortable");if(h&&!h.options.disabled){c.sortables.push({instance:h,shouldRevert:h.options.revert});
+h.refreshPositions();h._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=
+false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",true);
+this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;
+c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&
+this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=
+a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!=
+"x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<
+c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-
+c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,
+width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,h=b.offset.left,g=h+c.helperProportions.width,n=b.offset.top,o=n+c.helperProportions.height,i=c.snapElements.length-1;i>=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e<h&&h<l+e&&k-e<n&&n<m+e||j-e<h&&h<l+e&&k-e<o&&o<m+e||j-e<g&&g<l+e&&k-e<n&&n<m+e||j-e<g&&g<l+e&&k-e<o&&
+o<m+e){if(f.snapMode!="inner"){var p=Math.abs(k-o)<=e,q=Math.abs(m-n)<=e,r=Math.abs(j-g)<=e,s=Math.abs(l-h)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l}).left-c.margins.left}var t=
+p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(k-n)<=e;q=Math.abs(m-o)<=e;r=Math.abs(j-h)<=e;s=Math.abs(l-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[i].snapping&&
+(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=p||q||r||s||t}else{c.snapElements[i].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),
+10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
+;/*
+ * jQuery UI Droppable 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Droppables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.mouse.js
+ * jquery.ui.draggable.js
+ */
+(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);
+a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&
+this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
+this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
+d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",
+a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.16"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;
+switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=
+i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=
+"none";if(c[f].visible){e=="mousedown"&&c[f]._activate.call(c[f],b);c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight}}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||
+a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},dragStart:function(a,b){a.element.parents(":not(body,html)").bind("scroll.droppable",function(){a.options.refreshPositions||d.ui.ddmanager.prepareOffsets(a,b)})},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);
+if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})},dragStop:function(a,b){a.element.parents(":not(body,html)").unbind("scroll.droppable");
+a.options.refreshPositions||d.ui.ddmanager.prepareOffsets(a,b)}}})(jQuery);
+;/*
+ * jQuery UI Resizable 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
+_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
+top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
+this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
+nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
+String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
+this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){if(!a.disabled){e(this).removeClass("ui-resizable-autohide");b._handles.show()}},function(){if(!a.disabled)if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();
+var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=
+false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});
+this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff=
+{width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];
+if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},
+_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,
+{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(b){var a=this.options,c,d,f;a={minWidth:k(a.minWidth)?a.minWidth:0,maxWidth:k(a.maxWidth)?a.maxWidth:Infinity,minHeight:k(a.minHeight)?a.minHeight:0,maxHeight:k(a.maxHeight)?a.maxHeight:
+Infinity};if(this._aspectRatio||b){b=a.minHeight*this.aspectRatio;d=a.minWidth/this.aspectRatio;c=a.maxHeight*this.aspectRatio;f=a.maxWidth/this.aspectRatio;if(b>a.minWidth)a.minWidth=b;if(d>a.minHeight)a.minHeight=d;if(c<a.maxWidth)a.maxWidth=c;if(f<a.maxHeight)a.maxHeight=f}this._vBoundaries=a},_updateCache:function(b){this.offset=this.helper.offset();if(k(b.left))this.position.left=b.left;if(k(b.top))this.position.top=b.top;if(k(b.height))this.size.height=b.height;if(k(b.width))this.size.width=
+b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(k(b.height))b.width=b.height*this.aspectRatio;else if(k(b.width))b.height=b.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this._vBoundaries,c=this.axis,d=k(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=k(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=k(b.width)&&a.minWidth&&
+a.minWidth>b.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&l)b.left=i-a.minWidth;if(d&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=
+null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||
+0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+
+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+
+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);
+b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.16"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),
+10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-
+f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var l=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:l.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(l.css("position"))){c._revertToRelativePosition=true;l.css({position:"absolute",top:"auto",left:"auto"})}l.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?
+e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=
+e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,
+step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=
+e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;
+var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:
+a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-
+d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,
+f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,
+display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=
+e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=
+d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
+;/*
+ * jQuery UI Selectable 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),
+selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX,
+c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting",
+c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d=
+this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting");
+a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&&
+!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d=
+e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.16"})})(jQuery);
+;/*
+ * jQuery UI Sortable 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Sortables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable");
+this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a===
+"disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&
+!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,
+left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};
+this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=
+document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);
+return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<
+b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-
+b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,
+a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],
+e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();
+c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):
+this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,
+dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},
+toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||
+this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();
+var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},
+_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();
+if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),
+this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),
+this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&
+this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=
+this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=
+d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||
+0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",
+a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-
+f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=
+this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==
+""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=
+this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a=
+{top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),
+10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?
+document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),
+10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=
+this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&
+this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();
+var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-
+this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-
+this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],
+this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]=
+"";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",
+f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,
+this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",
+a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},
+_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.16"})})(jQuery);
+;/*
+ * jQuery UI Accordion 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");
+a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
+if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",
+function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a=
+this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex");
+this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();
+b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);
+a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+
+c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;
+if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
+if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(),
+e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight||
+e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",
+"aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.16",
+animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);
+f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",
+paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
+;/*
+ * jQuery UI Autocomplete 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ */
+(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.propAttr("readOnly"))){g=
+false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=
+a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};
+this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&&
+a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");
+d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&&
+b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source=
+this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();
+this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label||
+b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position));this.options.autoFocus&&this.menu.next(new d.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var g=this;
+d.each(b,function(c,f){g._renderItem(a,f)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,
+"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery);
+(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
+-1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");
+this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b,
+this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||
+this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||
+this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[d.fn.prop?"prop":"attr"]("scrollHeight")},select:function(e){this._trigger("selected",e,{item:this.active})}})})(jQuery);
+;/*
+ * jQuery UI Button 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function(b){var h,i,j,g,l=function(){var a=b(this).find(":ui-button");setTimeout(function(){a.button("refresh")},1)},k=function(a){var c=a.name,e=a.form,f=b([]);if(c)f=e?b(e).find("[name='"+c+"']"):b("[name='"+c+"']",a.ownerDocument).filter(function(){return!this.form});return f};b.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",l);if(typeof this.options.disabled!==
+"boolean")this.options.disabled=this.element.propAttr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var a=this,c=this.options,e=this.type==="checkbox"||this.type==="radio",f="ui-state-hover"+(!e?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",function(){if(!c.disabled){b(this).addClass("ui-state-hover");
+this===h&&b(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||b(this).removeClass(f)}).bind("click.button",function(d){if(c.disabled){d.preventDefault();d.stopImmediatePropagation()}});this.element.bind("focus.button",function(){a.buttonElement.addClass("ui-state-focus")}).bind("blur.button",function(){a.buttonElement.removeClass("ui-state-focus")});if(e){this.element.bind("change.button",function(){g||a.refresh()});this.buttonElement.bind("mousedown.button",function(d){if(!c.disabled){g=
+false;i=d.pageX;j=d.pageY}}).bind("mouseup.button",function(d){if(!c.disabled)if(i!==d.pageX||j!==d.pageY)g=true})}if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled||g)return false;b(this).toggleClass("ui-state-active");a.buttonElement.attr("aria-pressed",a.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled||g)return false;b(this).addClass("ui-state-active");a.buttonElement.attr("aria-pressed","true");
+var d=a.element[0];k(d).not(d).map(function(){return b(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;b(this).addClass("ui-state-active");h=this;b(document).one("mouseup",function(){h=null})}).bind("mouseup.button",function(){if(c.disabled)return false;b(this).removeClass("ui-state-active")}).bind("keydown.button",function(d){if(c.disabled)return false;if(d.keyCode==b.ui.keyCode.SPACE||
+d.keyCode==b.ui.keyCode.ENTER)b(this).addClass("ui-state-active")}).bind("keyup.button",function(){b(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(d){d.keyCode===b.ui.keyCode.SPACE&&b(this).click()})}this._setOption("disabled",c.disabled);this._resetButton()},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type===
+"radio"){var a=this.element.parents().filter(":last"),c="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(c);if(!this.buttonElement.length){a=a.length?a.siblings():this.element.siblings();this.buttonElement=a.filter(c);if(!this.buttonElement.length)this.buttonElement=a.find(c)}this.element.addClass("ui-helper-hidden-accessible");(a=this.element.is(":checked"))&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",a)}else this.buttonElement=this.element},
+widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||this.buttonElement.removeAttr("title");
+b.Widget.prototype.destroy.call(this)},_setOption:function(a,c){b.Widget.prototype._setOption.apply(this,arguments);if(a==="disabled")c?this.element.propAttr("disabled",true):this.element.propAttr("disabled",false);else this._resetButton()},refresh:function(){var a=this.element.is(":disabled");a!==this.options.disabled&&this._setOption("disabled",a);if(this.type==="radio")k(this.element[0]).each(function(){b(this).is(":checked")?b(this).button("widget").addClass("ui-state-active").attr("aria-pressed",
+"true"):b(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false")},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var a=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"),
+c=b("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(a.empty()).text(),e=this.options.icons,f=e.primary&&e.secondary,d=[];if(e.primary||e.secondary){if(this.options.text)d.push("ui-button-text-icon"+(f?"s":e.primary?"-primary":"-secondary"));e.primary&&a.prepend("<span class='ui-button-icon-primary ui-icon "+e.primary+"'></span>");e.secondary&&a.append("<span class='ui-button-icon-secondary ui-icon "+e.secondary+"'></span>");if(!this.options.text){d.push(f?"ui-button-icons-only":
+"ui-button-icon-only");this.hasTitle||a.attr("title",c)}}else d.push("ui-button-text-only");a.addClass(d.join(" "))}}});b.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(a,c){a==="disabled"&&this.buttons.button("option",a,c);b.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var a=this.element.css("direction")===
+"ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(a?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(a?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");
+b.Widget.prototype.destroy.call(this)}})})(jQuery);
+;/*
+ * jQuery UI Dialog 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.button.js
+ * jquery.ui.draggable.js
+ * jquery.ui.mouse.js
+ * jquery.ui.position.js
+ * jquery.ui.resizable.js
+ */
+(function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,
+position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+
+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&!i.isDefaultPrevented()&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),
+h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",
+e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");
+a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==
+b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()};c.ui.dialog.maxZ+=1;
+d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===
+f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,
+function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('<button type="button"></button>').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",
+handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,
+originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",
+f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):
+[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);
+if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):
+e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=
+this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-
+b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),
+create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&!d.isDefaultPrevented()&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||
+c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&
+c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+
+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
+;/*
+ * jQuery UI Slider 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var a=this,b=this.options,c=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f=b.values&&b.values.length||1,e=[];this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+
+this.orientation+" ui-widget ui-widget-content ui-corner-all"+(b.disabled?" ui-slider-disabled ui-disabled":""));this.range=d([]);if(b.range){if(b.range===true){if(!b.values)b.values=[this._valueMin(),this._valueMin()];if(b.values.length&&b.values.length!==2)b.values=[b.values[0],b.values[0]]}this.range=d("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(b.range==="min"||b.range==="max"?" ui-slider-range-"+b.range:""))}for(var j=c.length;j<f;j+=1)e.push("<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>");
+this.handles=c.add(d(e.join("")).appendTo(a.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle",
+g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!a.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");i=a._start(g,l);if(i===false)return}break}m=a.options.step;i=a.options.values&&a.options.values.length?
+(h=a.values(l)):(h=a.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=a._valueMin();break;case d.ui.keyCode.END:h=a._valueMax();break;case d.ui.keyCode.PAGE_UP:h=a._trimAlignValue(i+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=a._trimAlignValue(i-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===a._valueMax())return;h=a._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===a._valueMin())return;h=a._trimAlignValue(i-
+m);break}a._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(g,k);a._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy();
+return this},_mouseCapture:function(a){var b=this.options,c,f,e,j,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(b.range===true&&this.values(1)===b.min){g+=1;e=d(this.handles[g])}if(this._start(a,g)===false)return false;
+this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();b=e.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-e.width()/2,top:a.pageY-b.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b=
+this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b=
+this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);
+c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var f;if(this.options.values&&this.options.values.length){f=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>f||b===1&&c<f))c=f;if(c!==this.values(b)){f=this.values();f[b]=c;a=this._trigger("slide",a,{handle:this.handles[b],value:c,values:f});this.values(b?0:1);a!==false&&this.values(b,c,true)}}else if(c!==this.value()){a=this._trigger("slide",a,{handle:this.handles[b],value:c});
+a!==false&&this.value(c)}},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=
+this._trimAlignValue(a);this._refreshValue();this._change(null,0)}else return this._value()},values:function(a,b){var c,f,e;if(arguments.length>1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e<c.length;e+=1){c[e]=this._trimAlignValue(f[e]);this._change(null,e)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(a):
+this.value();else return this._values()},_setOption:function(a,b){var c,f=0;if(d.isArray(this.options.values))f=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(a){case "disabled":if(b){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.propAttr("disabled",true);this.element.addClass("ui-disabled")}else{this.handles.propAttr("disabled",false);this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();
+this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<f;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a)},_values:function(a){var b,c;if(arguments.length){b=this.options.values[a];
+return b=this._trimAlignValue(b)}else{b=this.options.values.slice();for(c=0;c<b.length;c+=1)b[c]=this._trimAlignValue(b[c]);return b}},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a=
+this.options.range,b=this.options,c=this,f=!this._animateOff?b.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({width:e-
+g+"%"},{queue:false,duration:b.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:b.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[f?"animate":"css"]({width:e+"%"},
+b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.16"})})(jQuery);
+;/*
+ * jQuery UI Tabs 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&&
+e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=
+d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]||
+(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
+this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected=
+this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
+if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));
+this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+
+g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",
+function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")};
+this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected=
+-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";
+d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=
+d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b,
+e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]);
+j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();
+if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null,
+this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this},
+load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c,
+"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},
+url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.16"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&&
+a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);
+;/*
+ * jQuery UI Datepicker 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker
+ *
+ * Depends:
+ * jquery.ui.core.js
+ */
+(function(d,C){function M(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=
+"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",
+"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",
+minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false,disabled:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=N(d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function N(a){return a.bind("mouseout",
+function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
+b.addClass("ui-state-hover");b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.16"}});var B=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},
+setDefaults:function(a){H(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,
+"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",
+function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b);b.settings.disabled&&this._disableDatepicker(a)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c==
+"focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():
+d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,
+b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.settings.disabled&&this._disableDatepicker(a);b.dpDiv.css("display","block")}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=
+1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/
+2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=
+d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=
+a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,
+"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==
+a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?
+d.extend({},e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true),i=this._getMinMaxDate(e,"min"),g=this._getMinMaxDate(e,"max");H(e.settings,f);if(i!==null&&f.dateFormat!==C&&f.minDate===C)e.settings.minDate=this._formatDate(e,i);if(g!==null&&f.dateFormat!==C&&f.maxDate===C)e.settings.maxDate=this._formatDate(e,g);this._attachments(d(a),e);this._autoSize(e);this._setDate(e,h);this._updateAlternate(e);
+this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");
+b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass+":not(."+d.datepicker._currentClass+")",b.dpDiv);c[0]&&d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]);if(a=d.datepicker._get(b,"onSelect")){c=d.datepicker._formatDate(b);a.apply(b.input?b.input[0]:null,[c,b])}else d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,
+a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=
+a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,
+"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));var c=String.fromCharCode(a.charCode==C?a.keyCode:a.charCode);
+return a.ctrlKey||a.metaKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input",
+a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c=d.datepicker._get(b,"beforeShow");c=c?c.apply(a,[a,b]):{};if(c!==false){H(b.settings,c);b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value=
+"";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);
+c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing=
+true;d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv);J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});
+a.dpDiv.find("."+this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&
+!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),
+h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=
+this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);
+this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},
+_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):
+0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e["selected"+(c=="M"?
+"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);
+this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");
+if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?
+b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=A+1<a.length&&a.charAt(A+1)==p)&&A++;return p},m=function(p){var D=
+o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"&&D?4:p=="o"?3:2)+"}");p=b.substring(q).match(p);if(!p)throw"Missing number at position "+q;q+=p[0].length;return parseInt(p[0],10)},n=function(p,D,K){p=d.map(o(p)?K:D,function(w,x){return[[x,w]]}).sort(function(w,x){return-(w[1].length-x[1].length)});var E=-1;d.each(p,function(w,x){w=x[1];if(b.substr(q,w.length).toLowerCase()==w.toLowerCase()){E=x[0];q+=w.length;return false}});if(E!=-1)return E+1;else throw"Unknown name at position "+q;},s=
+function(){if(b.charAt(q)!=a.charAt(A))throw"Unexpected literal at position "+q;q++},q=0,A=0;A<a.length;A++)if(k)if(a.charAt(A)=="'"&&!o("'"))k=false;else s();else switch(a.charAt(A)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":j=m("m");break;case "M":j=n("M",i,g);break;case "y":c=m("y");break;case "@":var v=new Date(m("@"));c=v.getFullYear();j=v.getMonth()+1;l=v.getDate();break;case "!":v=new Date((m("!")-this._ticksTo1970)/1E4);c=v.getFullYear();j=v.getMonth()+
+1;l=v.getDate();break;case "'":if(o("'"))s();else k=true;break;default:s()}if(q<b.length)throw"Extra/unparsed characters found in date: "+b.substring(q);if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd",
+COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:
+null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&a.charAt(k+1)==o)&&k++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},j=function(o,m,n,s){return i(o)?s[m]:n[m]},l="",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)=="'"&&!i("'"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=j("D",b.getDay(),e,f);break;case "o":l+=g("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-
+(new Date(b.getFullYear(),0,0)).getTime())/864E5),3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=j("M",b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=
+0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+="0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==C?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);
+var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;
+i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||"d"){case "d":case "D":g+=parseInt(k[1],10);break;case "w":case "W":g+=parseInt(k[1],10)*7;break;case "m":case "M":l+=parseInt(k[1],10);g=
+Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case "y":case "Y":j+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j,l,g)};if(b=(b=b==null||b===""?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>
+12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&
+a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?
+new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));
+n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+B+".datepicker._adjustDate('#"+a.id+"', -"+j+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m,
+g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+B+".datepicker._adjustDate('#"+a.id+"', +"+j+", 'M');\" title=\""+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&&
+a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+B+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,s)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+
+B+".datepicker._gotoToday('#"+a.id+"');\">"+j+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),A=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x<i[0];x++){var O=
+"";this.maxRows=4;for(var G=0;G<i[1];G++){var P=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",y="";if(l){y+='<div class="ui-datepicker-group';if(i[1]>1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&
+x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,A,v)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var z=j?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var r=(t+h)%7;z+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+s[r]+'">'+q[r]+"</span></th>"}y+=z+"</tr></thead><tbody>";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,
+z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q<z;Q++){y+="<tr>";var R=!j?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(r)+"</td>";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&r<k||o&&r>o;R+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(r.getTime()==
+P.getTime()&&g==a.selectedMonth&&a._keyEvent||E.getTime()==r.getTime()&&E.getTime()==P.getTime()?" "+this._dayOverClass:"")+(L?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!D?"":" "+I[1]+(r.getTime()==u.getTime()?" "+this._currentClass:"")+(r.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!F||D)&&I[2]?' title="'+I[2]+'"':"")+(L?"":' onclick="DP_jQuery_'+B+".datepicker._selectDay('#"+a.id+"',"+r.getMonth()+","+r.getFullYear()+', this);return false;"')+">"+(F&&!D?" ":L?'<span class="ui-state-default">'+
+r.getDate()+"</span>":'<a class="ui-state-default'+(r.getTime()==b.getTime()?" ui-state-highlight":"")+(r.getTime()==u.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+'" href="#">'+r.getDate()+"</a>")+"</td>";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+"</tr>"}g++;if(g>11){g=0;m++}y+="</tbody></table>"+(l?"</div>"+(i[0]>0&&G==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':
+"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='<div class="ui-datepicker-title">',o="";if(h||!j)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+B+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" >";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&
+(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b,
+e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+B+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" >";b<=g;b++)a.yearshtml+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";a.yearshtml+="</select>";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="</div>";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+
+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input?
+a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c,
+e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,
+"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this;
+if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a==
+"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.16";window["DP_jQuery_"+B]=d})(jQuery);
+;/*
+ * jQuery UI Progressbar 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");
+this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*
+this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.16"})})(jQuery);
+;/*
+ * jQuery UI Effects 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/
+ */
+jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
+16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
+a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
+a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor",
+"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,
+0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,
+211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,
+d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})};
+f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,
+[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.16",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b=
+0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),
+d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement;
+if(c.parent().is(".ui-effects-wrapper")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});
+return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,
+arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/
+2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,
+d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,
+a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,
+d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=
+0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;
+if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,
+a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);
+;/*
+ * jQuery UI Effects Blind 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Blind
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","bottom","left","right"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a,
+g);b.effects.removeWrapper(a);c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);
+;/*
+ * jQuery UI Effects Bounce 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Bounce
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","bottom","left","right"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/
+3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);
+b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery);
+;/*
+ * jQuery UI Effects Clip 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Clip
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","bottom","left","right","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position,
+c/2)}var h={};h[g.size]=f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Drop 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Drop
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e==
+"show"?1:0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Explode 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Explode
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=
+0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+
+e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery);
+;/*
+ * jQuery UI Effects Fade 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Fade
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Fold 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Fold
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],
+10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);
+;/*
+ * jQuery UI Effects Highlight 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Highlight
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&&
+this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Pulsate 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Pulsate
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,
+a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery);
+;/*
+ * jQuery UI Effects Scale 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Scale
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,
+b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity=
+1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","bottom","left","right","width","height","overflow","opacity"],g=["position","top","bottom","left","right","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],
+p=c.effects.setMode(a,b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};
+if(m=="box"||m=="both"){if(d.from.y!=d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);
+a.css("overflow","hidden").css(a.from);if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);
+child.to=c.effects.setTransition(child,f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a,
+n?e:g);c.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Shake 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Shake
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","bottom","left","right"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]=
+(h=="pos"?"-=":"+=")+e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery);
+;/*
+ * jQuery UI Effects Slide 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Slide
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right"],f=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var g=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var e=d.options.distance||(g=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f=="show")a.css(g,b=="pos"?isNaN(e)?"-"+e:-e:e);
+var i={};i[g]=(f=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Transfer 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Transfer
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);
+b.dequeue()})})}})(jQuery);
+;
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/jquery144min.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,153 @@
+(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h=
+h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"||
+h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
+"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
+e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
+"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
+s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
+j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
+toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
+-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
+if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;
+if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
+b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
+!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
+l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],
+z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,
+s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=
+s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)||
+[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u,
+false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
+k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
+scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
+1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
+"none"});a=function(r){var A=t.createElement("div"),C=A.wrappedJSObject||A;r="on"+r;isSupported=r in C;if(!isSupported){A.setAttribute(r,"return;");isSupported=typeof C[r]==="function"}return isSupported};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=
+a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];
+else if(a.removeAttribute)a.removeAttribute(c.expando);else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a===
+"object")return this.each(function(){c.data(this,a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,
+b,d){if(a){b=(b||"fx")+"queue";var e=c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&
+c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",
+readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=
+(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===
+1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "),l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d===
+"undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=
+b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=
+c(this),r=a;if(this.nodeType===1){if(k)r=a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,
+data:true,width:true,height:true,offset:true},attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;
+if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,
+Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!==
+"undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,
+h);if(!h.handler.guid)h.handler.guid=d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=
+f.split(".");f=o.shift();x=RegExp("(^|\\.)"+c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,
+r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,
+b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;
+e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k==="click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");
+a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},
+props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;
+if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;
+if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===
+b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();
+else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},
+wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&
+c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=
+a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=
+a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type==="file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},
+teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,
+e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],
+a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=
+(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d==="object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=
+e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
+function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;
+y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i,[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=
+D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||
+k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,
+i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=
+o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+
+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},
+leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=
+g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&
+g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g,"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=
+false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||
+"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},
+has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()===
+"button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||
+g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],
+u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):
+g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);
+o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=
+function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);
+return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"),i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,
+p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=
+n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,
+p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||
+g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===
+0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||
+g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,
+cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),
+"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>
+-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||
+!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},
+nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):
+f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,
+b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],
+td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||
+t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=
+c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&
+this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},
+remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,
+e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=
+a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=
+c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=
+l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):this[f]:this[f],f>0||e.cacheable||
+this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",
+insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||t;
+for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length-1;o>=0;--o)c.nodeName(k[o],
+"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
+d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
+jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
+zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
+h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
+if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
+d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
+e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===
+"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
+!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
+getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
+script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
+!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache=
+false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset;
+A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type",
+b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
+c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
+c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=
+encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",
+[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),
+e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});
+if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",
+3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",
+d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,
+d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===
+"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L||
+1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
+d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
+Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}
+var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
+this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
+this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
+c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
+b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
+h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;
+for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+=
+parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
+height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
+f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
+"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a,
+e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&
+c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
+c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+
+b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window);
Binary file src/main/resources/people/a_js/validator/css/screenshot.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/css/template.css Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,97 @@
+body {
+ background: #ececec;
+}
+
+form.formular {
+ font-family: tahoma, verdana, "sans-serif";
+ font-size: 12px;
+ padding: 20px;
+ border: 1px solid #A5A8B8;
+ width: 300px;
+ margin: 0 auto;
+}
+
+.formular fieldset {
+ margin-top: 20px;
+ padding: 15px;
+ border: 1px solid #B5B8C8;
+}
+
+.formular legend {
+ font-size: 12px;
+ color: #15428B;
+ font-weight: 900;
+}
+
+.formular fieldset label {
+ float: none;
+ text-align: inherit;
+ width: auto;
+}
+
+.formular label span {
+ color: #000;
+}
+
+.formular input,.formular select,.formular textarea {
+ display: block;
+ margin-bottom: 5px;
+}
+
+.formular .text-input {
+ width: 250px;
+ color: #555;
+ padding: 4px;
+ border: 1px solid #B5B8C8;
+ font-size: 14px;
+ margin-top: 4px;
+ background: #FFF repeat-x;
+}
+
+.formular textarea {
+ width: 250px;
+ height: 70px;
+ color: #555;
+ padding: 4px;
+ border: 1px solid #B5B8C8;
+ font-size: 14px;
+ margin-top: 4px;
+ background: #FFF repeat-x;
+}
+
+.formular .infos {
+ background: #FFF;
+ color: #333;
+ font-size: 12px;
+ padding: 10px;
+ margin-bottom: 10px;
+}
+
+.formular span.checkbox,.formular .checkbox {
+ display: inline;
+}
+
+.formular .submit {
+
+ border: 1px solid #AAA;
+ padding: 4px;
+ margin-top: 20px;
+ float: right;
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.formular hr {
+ clear: both;
+ visibility: hidden;
+}
+
+.formular .fc-error {
+ width: 350px;
+ color: 555;
+ padding: 4px;
+ border: 1px solid #B5B8C8;
+ font-size: 12px;
+ margin-bottom: 15px;
+ background: #FFEAEA;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/css/validationEngine.jquery.css Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,142 @@
+.inputContainer {
+ position: relative;
+ float: left;
+}
+
+.formError {
+ position: absolute;
+ top: 300px;
+ left: 300px;
+ display: block;
+ z-index: 5000;
+ cursor: pointer;
+}
+
+.ajaxSubmit {
+ padding: 20px;
+ background: #55ea55;
+ border: 1px solid #999;
+ display: none
+}
+
+.formError .formErrorContent {
+ width: 100%;
+ background: #ee0101;
+ position:relative;
+ z-index:5001;
+ color: #fff;
+ width: 150px;
+ font-family: tahoma;
+ font-size: 11px;
+ border: 2px solid #ddd;
+ box-shadow: 0 0 6px #000;
+ -moz-box-shadow: 0 0 6px #000;
+ -webkit-box-shadow: 0 0 6px #000;
+ padding: 4px 10px 4px 10px;
+ border-radius: 6px;
+ -moz-border-radius: 6px;
+ -webkit-border-radius: 6px;
+}
+
+.greenPopup .formErrorContent {
+ background: #33be40;
+}
+
+.blackPopup .formErrorContent {
+ background: #393939;
+ color: #FFF;
+}
+
+.formError .formErrorArrow {
+ width: 15px;
+ margin: -2px 0 0 13px;
+ position:relative;
+ z-index: 5006;
+}
+
+.formError .formErrorArrowBottom {
+ box-shadow: none;
+ -moz-box-shadow: none;
+ -webkit-box-shadow: none;
+ margin: 0px 0 0 12px;
+ top:2px;
+}
+
+.formError .formErrorArrow div {
+ border-left: 2px solid #ddd;
+ border-right: 2px solid #ddd;
+ box-shadow: 0 2px 3px #444;
+ -moz-box-shadow: 0 2px 3px #444;
+ -webkit-box-shadow: 0 2px 3px #444;
+ font-size: 0px;
+ height: 1px;
+ background: #ee0101;
+ margin: 0 auto;
+ line-height: 0;
+ font-size: 0;
+ display: block;
+}
+
+.formError .formErrorArrowBottom div {
+ box-shadow: none;
+ -moz-box-shadow: none;
+ -webkit-box-shadow: none;
+}
+
+.greenPopup .formErrorArrow div {
+ background: #33be40;
+}
+
+.blackPopup .formErrorArrow div {
+ background: #393939;
+ color: #FFF;
+}
+
+.formError .formErrorArrow .line10 {
+ width: 15px;
+ border: none;
+}
+
+.formError .formErrorArrow .line9 {
+ width: 13px;
+ border: none;
+}
+
+.formError .formErrorArrow .line8 {
+ width: 11px;
+}
+
+.formError .formErrorArrow .line7 {
+ width: 9px;
+}
+
+.formError .formErrorArrow .line6 {
+ width: 7px;
+}
+
+.formError .formErrorArrow .line5 {
+ width: 5px;
+}
+
+.formError .formErrorArrow .line4 {
+ width: 3px;
+}
+
+.formError .formErrorArrow .line3 {
+ width: 1px;
+ border-left: 2px solid #ddd;
+ border-right: 2px solid #ddd;
+ border-bottom: 0 solid #ddd;
+}
+
+.formError .formErrorArrow .line2 {
+ width: 3px;
+ border: none;
+ background: #ddd;
+}
+
+.formError .formErrorArrow .line1 {
+ width: 1px;
+ border: none;
+ background: #ddd;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery-1.4.4.min.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,167 @@
+/*!
+ * jQuery JavaScript Library v1.4.4
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu Nov 11 19:04:53 2010 -0500
+ */
+(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h=
+h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"||
+h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
+"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
+e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
+"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
+s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
+j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
+toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
+-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
+if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;
+if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
+b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
+!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
+l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],
+z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,
+s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=
+s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)||
+[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u,
+false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
+k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
+scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
+1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
+"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=
+c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);
+else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this,
+a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=
+c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
+a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",
+colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===
+1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "),
+l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,
+"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";
+if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=
+a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},
+attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&
+b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};
+c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,
+arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=
+d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+
+c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=
+w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
+8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k===
+"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+
+d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
+Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
+c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
+var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
+"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
+xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=
+B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type===
+"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===
+0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
+a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
+1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===
+"object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}});
+c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
+(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i,
+[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];
+break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,
+q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=
+l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*"));
+return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==
+B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
+POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===
+i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=
+i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g,
+"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,
+m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
+true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
+g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-
+0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===
+"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
+i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];
+if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,
+g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;
+for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"),
+i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);
+n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&
+function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||
+p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=
+t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?
+function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;
+c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},
+not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=
+h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):
+c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,
+2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,
+b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&
+e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1,
+"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;
+else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=
+c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a,
+b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):
+this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",
+prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||
+b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length-
+1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
+d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
+jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
+zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
+h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
+if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
+d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
+e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===
+"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
+!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
+getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
+script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
+!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache=
+false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset;
+A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type",
+b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
+c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
+c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=
+encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",
+[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),
+e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});
+if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",
+3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",
+d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,
+d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===
+"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L||
+1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
+d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
+Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}
+var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
+this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
+this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
+c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
+b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
+h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;
+for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+=
+parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
+height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
+f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
+"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a,
+e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&
+c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
+c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+
+b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window);
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-da.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,123 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* Dette felt kræves udfyldt",
+ "alertTextCheckboxMultiple": "* Vælg venligst en af mulighederne",
+ "alertTextCheckboxe": "* Dette felt er krævet"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* Minimum ",
+ "alertText2": " tegn tilladt"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* Maksimum ",
+ "alertText2": " tegn tilladt"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* Den mindste værdi er "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* Den maksimale værdi er "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Datoen skal være før "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Datoen skal være efter "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Antallet af valg overskredet"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Vælg venligst ",
+ "alertText2": " muligheder"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* Felterne er ikke ens"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Ikke gyldig telefonnummer"
+ },
+ "email": {
+ // Simplified, was not working in the Iphone browser
+ "regex": /^([A-Za-z0-9_\-\.\'])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,6})$/,
+ "alertText": "* Ikke gyldig e-mail"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Ikke et korrekt tal"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* Ugyldig decimaltal"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Ugyldig dato, skal være i formatet ÅÅÅÅ-MM-DD"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* Ugyldig IP adresse"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* Ugyldig URL"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Kun tal"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Kun bogstaver"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* Ingen specialtegn tilladt"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertText": "* Denne bruger er allerede taget",
+ "alertTextLoad": "* Kontrollere, vent venligst"
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* Dette navn er allerede taget",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* Dette navn er ledig",
+ // speaks by itself
+ "alertTextLoad": "* Kontrollere, vent venligst"
+ },
+ "validate2fields": {
+ "alertText": "* Indsæt venligst HELLO"
+ }
+ };
+
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-de.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,126 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* Dieses Feld ist ein Pflichtfeld",
+ "alertTextCheckboxMultiple": "* Bitte wählen Sie eine Option",
+ "alertTextCheckboxe": "* Dieses Feld ist ein Pflichtfeld"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* Mindestens ",
+ "alertText2": " Zeichen benötigt"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* Maximal ",
+ "alertText2": " Zeichen erlaubt"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* Mindeswert ist "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* Maximalwert ist "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Datum vor "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Datum nach "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Maximale Anzahl Markierungen überschritten"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Bitte wählen Sie ",
+ "alertText2": " Optionen"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* Felder stimmen nicht überein"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Ungültige Telefonnummer"
+ },
+ "email": {
+ // Simplified, was not working in the Iphone browser
+ "regex": /^([A-Za-z0-9_\-\.\'])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,6})$/,
+ "alertText": "* Ungültige E-Mail Adresse"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Keine gültige Ganzzahl"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* Keine gültige Fließkommazahl"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Ungültiges Datumsformat, erwartet wird das Format JJJJ-MM-TT"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* Ungültige IP Adresse"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* Ungültige URL"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Nur Zahlen erlaubt"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Nur Buchstaben erlaubt"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* Keine Sonderzeichen erlaubt"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertText": "* Dieser Benutzer ist bereits vergeben",
+ "alertTextLoad": "* Überprüfe Angaben, bitte warten"
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* Dieser Name ist bereits vergeben",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* Dieser Name ist verfügbar",
+ // speaks by itself
+ "alertTextLoad": "* Überprüfe Angaben, bitte warten"
+ },
+ "validate2fields": {
+ "alertText": "* Bitte HELLO eingeben"
+ }
+ };
+
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-en.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,130 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* This field is required",
+ "alertTextCheckboxMultiple": "* Please select an option",
+ "alertTextCheckboxe": "* This checkbox is required"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* Minimum ",
+ "alertText2": " characters allowed"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* Maximum ",
+ "alertText2": " characters allowed"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* Minimum value is "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* Maximum value is "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Date prior to "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Date past "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Checks allowed Exceeded"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Please select ",
+ "alertText2": " options"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* Fields do not match"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Invalid phone number"
+ },
+ "email": {
+ // Simplified, was not working in the Iphone browser
+ "regex": /^([A-Za-z0-9_\-\.\'])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,6})$/,
+ "alertText": "* Invalid email address"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Not a valid integer"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* Only numbers please."
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Invalid date, must be in YYYY-MM-DD format"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* Invalid IP address"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* Invalid URL"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Numbers only"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Letters only"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* No special characters allowed"
+ },
+ "textspecial": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* No special characters allowed"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertText": "* This user is already taken",
+ "alertTextLoad": "* Validating, please wait"
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* This name is already taken",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* This name is available",
+ // speaks by itself
+ "alertTextLoad": "* Validating, please wait"
+ },
+ "validate2fields": {
+ "alertText": "* Please input HELLO"
+ }
+ };
+
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-es.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,124 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* Este campo está requerido",
+ "alertTextCheckboxMultiple": "* Por favor selecciona una opción",
+ "alertTextCheckboxe": "* Este checkbox está requerido"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* MÃnimo de ",
+ "alertText2": " caracteres autorizados"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* Máximo de ",
+ "alertText2": " caracteres autorizados"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* Valor mÃnimo es "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* Valor máximo es "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Fecha anterior a "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Fecha posterior a "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Se ha excedido el número de opciones permitidas"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Por favor seleccione ",
+ "alertText2": " opciones"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* Los campos no coinciden"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Número de teléfono inválido"
+ },
+ "email": {
+ // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/
+ "regex": /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/,
+ "alertText": "* Correo inválido"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* No es un valor entero válido"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* No es un valor decimal válido"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Fecha inválida, por favor utilize el formato AAAA-MM-DD"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* Direccion IP inválida"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* URL Inválida"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Sólo números"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Sólo letras"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* No se permiten caracteres especiales"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertTextLoad": "* Cargando, espere por favor",
+ "alertText": "* Este nombre de usuario ya se encuentra usado"
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* Este nombre ya se encuentra usado",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* Este nombre está disponible",
+ // speaks by itself
+ "alertTextLoad": "* Cargando, espere por favor"
+ },
+ "validate2fields": {
+ "alertText": "* Por favor entrar HELLO"
+ }
+ };
+
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-fr.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,119 @@
+
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": {
+ "regex": "none",
+ "alertText": "* Ce champs est requis",
+ "alertTextCheckboxMultiple": "* Choisir une option",
+ "alertTextCheckboxe": "* Cette option est requise"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* Minimum ",
+ "alertText2": " caracteres requis"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* Maximum ",
+ "alertText2": " caracteres requis"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* Valeur minimum requise "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* Valeur maximum requise "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Date antérieure au "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Date postérieure au "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Nombre max de choix excédé"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Veuillez choisir ",
+ "alertText2": " options"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* Votre champs n'est pas identique"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Numéro de téléphone invalide"
+ },
+ "email": {
+ // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/
+ "regex": /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/,
+ "alertText": "* Adresse email invalide"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Nombre entier invalide"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* Nombre flottant invalide"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Date invalide, format YYYY-MM-DD requis"
+ },
+ "ipv4": {
+ "regex": /([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+/,
+ "alertText": "* Adresse IP invalide"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* URL invalide"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Seules les chiffres sont acceptées"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Seules les lettres sont acceptées"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* Aucun caractère spécial n'est accepté"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ "extraData": "name=eric",
+ "alertTextLoad": "* Chargement, veuillez attendre",
+ "alertText": "* Ce nom est déjà pris"
+ },
+ "ajaxNameCall": {
+ "url": "ajaxValidateFieldName",
+ "alertText": "* Ce nom est déjà pris",
+ "alertTextOk": "*Ce nom est disponible",
+ "alertTextLoad": "* Chargement, veuillez attendre"
+ },
+ "validate2fields": {
+ "alertText": "Veuillez taper le mot HELLO"
+ }
+ };
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-it.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,103 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* Campo richiesto",
+ "alertTextCheckboxMultiple": "* Per favore selezionare un'opzione",
+ "alertTextCheckboxe": "* E' richiesta la selezione della casella"
+ },
+ "length": {
+ "regex": "none",
+ "alertText": "* Fra ",
+ "alertText2": " e ",
+ "alertText3": " caratteri permessi"
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Numero di caselle da selezionare in eccesso"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Per favore selezionare ",
+ "alertText2": " opzioni"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* I campi non corrispondono"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Numero di telefono non corretto"
+ },
+ "email": {
+ // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/
+ "regex": /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/,
+ "alertText": "* Indirizzo non corretto"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Numero intero non corretto"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. Credit: bassistance
+ "regex": /^[\-\+]?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)$/,
+ "alertText": "* Numero decimale non corretto"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Data non corretta, re-inserire secondo formato AAAA-MM-GG"
+ },
+
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* IP non corretto"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* URL non corretta"
+ },
+ "onlyNumber": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Solo numeri"
+ },
+ "onlyLetter": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Solo lettere"
+ },
+ "validate2fields": {
+ "nname": "validate2fields",
+ "alertText": "* Occorre inserire nome e cognome"
+ },
+ "noSpecialCharacters": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* Caratteri speciali non permessi"
+ },
+ "ajaxUserCall": {
+ "file": "ajaxValidateFieldName",
+ "extraData": "name=eric",
+ "alertTextLoad": "* Caricamento, attendere per favore",
+ "alertText": "* Questo user giˆ stato utilizzato"
+ },
+ "ajaxNameCall": {
+ "file": "ajaxValidateFieldName",
+ "alertText": "* Questo nome giˆ stato utilizzato",
+ "alertTextOk": "* Questo nome disponibile",
+ "alertTextLoad": "* Caricamento, attendere per favore"
+ }
+
+ };
+
+ }
+ };
+})(jQuery);
+
+$(document).ready(function(){
+ $.validationEngineLanguage.newLang();
+});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-ja.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,136 @@
+;/*****************************************************************
+ * Japanese language file for jquery.validationEngine.js (ver2.0)
+ *
+ * Transrator: tomotomo ( Tomoyuki SUGITA )
+ * http://tomotomoSnippet.blogspot.com/
+ * Licenced under the MIT Licence
+ *******************************************************************/
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* å¿…é ˆé …ç›®ã§ã™",
+ "alertTextCheckboxMultiple": "* é¸æŠžã—ã¦ãã ã•ã„",
+ "alertTextCheckboxe": "* ãƒã‚§ãƒƒã‚¯ãƒœãƒƒã‚¯ã‚¹ã‚’ãƒã‚§ãƒƒã‚¯ã—ã¦ãã ã•ã„"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* ",
+ "alertText2": "æ–‡å—以上ã«ã—ã¦ãã ã•ã„"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* ",
+ "alertText2": "æ–‡å—以下ã«ã—ã¦ãã ã•ã„"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* ",
+ "alertText2": " 以上ã®æ•°å€¤ã«ã—ã¦ãã ã•ã„"
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* ",
+ "alertText2": " 以下ã®æ•°å€¤ã«ã—ã¦ãã ã•ã„"
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* ",
+ "alertText2": " よりéŽåŽ»ã®æ—¥ä»˜ã«ã—ã¦ãã ã•ã„"
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* ",
+ "alertText2": " より最近ã®æ—¥ä»˜ã«ã—ã¦ãã ã•ã„"
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* ãƒã‚§ãƒƒã‚¯ã—ã™ãŽã§ã™"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* ",
+ "alertText2": "ã¤ä»¥ä¸Šãƒã‚§ãƒƒã‚¯ã—ã¦ãã ã•ã„"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* 入力ã•ã‚ŒãŸå€¤ãŒä¸€è‡´ã—ã¾ã›ã‚“"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* 電話番å·ãŒæ£ã—ãã‚ã‚Šã¾ã›ã‚“"
+ },
+ "email": {
+ // Simplified, was not working in the Iphone browser
+ "regex": /^([A-Za-z0-9_\-\.\'])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,6})$/,
+ "alertText": "* メールアドレスãŒæ£ã—ãã‚ã‚Šã¾ã›ã‚“"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* æ•´æ•°ã‚’åŠè§’ã§å…¥åŠ›ã—ã¦ãã ã•ã„"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* 数値をåŠè§’ã§å…¥åŠ›ã—ã¦ãã ã•ã„"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* 日付ã¯åŠè§’㧠YYYY-MM-DD ã®å½¢å¼ã§å…¥åŠ›ã—ã¦ãã ã•ã„"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* IPアドレスãŒæ£ã—ãã‚ã‚Šã¾ã›ã‚“"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* URLãŒæ£ã—ãã‚ã‚Šã¾ã›ã‚“"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* åŠè§’æ•°å—ã§å…¥åŠ›ã—ã¦ãã ã•ã„"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* åŠè§’アルファベットã§å…¥åŠ›ã—ã¦ãã ã•ã„"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* åŠè§’英数ã§å…¥åŠ›ã—ã¦ãã ã•ã„"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertText": "* This user is already taken",
+ "alertTextLoad": "* Validating, please wait"
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* This name is already taken",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* This name is available",
+ // speaks by itself
+ "alertTextLoad": "* Validating, please wait"
+ },
+ "validate2fields": {
+ "alertText": "* 『HELLOã€ã¨å…¥åŠ›ã—ã¦ãã ã•ã„"
+ }
+ };
+
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-nl.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,124 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "geen",
+ "alertText": "* Dit veld is verplicht",
+ "alertTextCheckboxMultiple": "* Selecteer a.u.b. een optie",
+ "alertTextCheckboxe": "* Dit selectievakje is verplicht"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* Minimaal ",
+ "alertText2": " karakters toegestaan"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* Maximaal ",
+ "alertText2": " karakters toegestaan"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* Minimale waarde is "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* Maximale waarde is "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Datum voorafgaand aan "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Datum na "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Toegestane aantal vinkjes overschreden"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Selecteer a.u.b. ",
+ "alertText2": " opties"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* Velden komen niet overeen"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Ongeldig telefoonnummer"
+ },
+ "email": {
+ // Simplified, was not working in the Iphone browser
+ "regex": /^([A-Za-z0-9_\-\.\'])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,6})$/,
+ "alertText": "* Ongeldig e-mailadres"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Ongeldig geheel getal"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* Ongeldig drijvende comma getal"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Ongeldige datum, formaat moet JJJJ-MM-DD zijn"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* Ongeldig IP-adres"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* Ongeldige URL"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Alleen cijfers"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Alleen leestekens"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* Geen vreemde tekens toegestaan"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertText": "* Deze gebruiker bestaat al",
+ "alertTextLoad": "* Bezig met valideren, even geduld aub"
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* Deze naam bestaat al",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* Deze naam is beschikbaar",
+ // speaks by itself
+ "alertTextLoad": "* Bezig met valideren, even geduld aub"
+ },
+ "validate2fields": {
+ "alertText": "* Voer aub HELLO in"
+ }
+ };
+
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-pt.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,125 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* Campo obrigatório",
+ "alertTextCheckboxMultiple": "* Selecione uma opção",
+ "alertTextCheckboxe": "* Campo obrigatório"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* MÃnimo ",
+ "alertText2": " carateres permitidos"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* Máximo ",
+ "alertText2": " carateres permitidos"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* O valor mÃnimo é "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* O valor máximo é "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Data anterior a "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Data posterior a "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Foi ultrapassado o número máximo de escolhas"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Selecione ",
+ "alertText2": " opções"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* Os campos não correspondem"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Número de telefone inválido"
+ },
+ "email": {
+ // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/
+ "regex": /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/,
+ "alertText": "* Endereço de email inválido"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Não é um número inteiro"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* Não é um número decimal"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Data inválida, o formato deve de ser AAAA-MM-DD"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* Número IP inválido"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* URL inválido"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Só é permitido números"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Só é permitido letras"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* Só é permitido letras e números"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertText": "* Nome de utilizador não disponÃvel",
+ "alertTextLoad": "* A validar, por favor aguarde"
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* Nome não disponÃvel",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* Nome disponÃvel",
+ // speaks by itself
+ "alertTextLoad": "* A validar, por favor aguarde"
+ },
+ "validate2fields": {
+ "alertText": "* Escreva HELLO"
+ }
+ };
+
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-ro.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,126 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* Acest camp este obligatoriu",
+ "alertTextCheckboxMultiple": "* Selectati o optiune",
+ "alertTextCheckboxe": "* Aceasta optiune este obligatorie"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* Minim ",
+ "alertText2": " caractere permise"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* Maxim ",
+ "alertText2": " caractere permise"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* Valoarea minima este "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* Valoarea maxima este "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Data inainte de "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Data dupa "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* Limita maxima de optiuni a fost depasita"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* Selectati cel putin ",
+ "alertText2": " optiuni"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* Campurile nu coincid"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Numar de telefon eronat"
+ },
+ "email": {
+ // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/
+ "regex": /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/,
+ "alertText": "* Adresa de email eronata"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Numar intreg eronat"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* Numar zecimal eronat"
+ },
+ "date": {
+ // Date in ISO format. Credit: bassistance
+ "regex": /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ "alertText": "* Data eronata, formatul de introducere este: YYYY-MM-DD"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* Adresa IP eronata"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* URL eronat"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Doar numere"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\ \']+$/,
+ "alertText": "* Doar litere"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z]+$/,
+ "alertText": "* Caracterele speciale (',', '.', '-', etc) nu sunt permise"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertText": "* Acest nume de utilizator este deja folosit",
+ "alertTextLoad": "* Se valideaza, va rugam asteptati"
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* Acest nume este deja folosit",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* Acest nume este disponibil",
+ // speaks by itself
+ "alertTextLoad": "* Se valideaza, va rugam asteptati"
+ },
+ "validate2fields": {
+ "alertText": "* Introduceti: HELLO"
+ }
+ };
+
+ }
+ };
+})(jQuery);
+
+$(document).ready(function(){
+ $.validationEngineLanguage.newLang();
+});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine-ru.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,124 @@
+
+(function($){
+ $.fn.validationEngineLanguage = function(){
+ };
+ $.validationEngineLanguage = {
+ newLang: function(){
+ $.validationEngineLanguage.allRules = {
+ "required": { // Add your regex rules here, you can take telephone as an example
+ "regex": "none",
+ "alertText": "* Ðеобходимо заполнить",
+ "alertTextCheckboxMultiple": "* Вы должны выбрать вариант",
+ "alertTextCheckboxe": "* Ðеобходимо отметить"
+ },
+ "minSize": {
+ "regex": "none",
+ "alertText": "* Минимум ",
+ "alertText2": " Ñимвола(ов)"
+ },
+ "maxSize": {
+ "regex": "none",
+ "alertText": "* МакÑимум ",
+ "alertText2": " Ñимвола(ов)"
+ },
+ "min": {
+ "regex": "none",
+ "alertText": "* Минимальное значение "
+ },
+ "max": {
+ "regex": "none",
+ "alertText": "* МакÑимальное значение "
+ },
+ "past": {
+ "regex": "none",
+ "alertText": "* Дата до "
+ },
+ "future": {
+ "regex": "none",
+ "alertText": "* Дата от "
+ },
+ "maxCheckbox": {
+ "regex": "none",
+ "alertText": "* ÐÐµÐ»ÑŒÐ·Ñ Ð²Ñ‹Ð±Ñ€Ð°Ñ‚ÑŒ Ñтолько вариантов"
+ },
+ "minCheckbox": {
+ "regex": "none",
+ "alertText": "* ПожалуйÑта, выберите ",
+ "alertText2": " опцию(ии)"
+ },
+ "equals": {
+ "regex": "none",
+ "alertText": "* ÐŸÐ¾Ð»Ñ Ð½Ðµ Ñовпадают"
+ },
+ "phone": {
+ // credit: jquery.h5validate.js / orefalo
+ "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
+ "alertText": "* Ðеправильный формат телефона"
+ },
+ "email": {
+ // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/
+ "regex": /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/,
+ "alertText": "* Ðеверный формат email"
+ },
+ "integer": {
+ "regex": /^[\-\+]?\d+$/,
+ "alertText": "* Ðе целое чиÑло"
+ },
+ "number": {
+ // Number, including positive, negative, and floating decimal. credit: orefalo
+ "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
+ "alertText": "* Ðеправильное чиÑло Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+ },
+ "date": {
+ // Date in russian-specific format
+ "regex": /^\d{1,2}[\.]\d{1,2}[\.]\d{4}$/,
+ "alertText": "* ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ Ð´Ð°Ñ‚Ð° (должно быть в ДД.MM.ГГГГ формате)"
+ },
+ "ipv4": {
+ "regex": /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/,
+ "alertText": "* Ðеправильный IP-адреÑ"
+ },
+ "url": {
+ "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ "alertText": "* Ðеправильный URL"
+ },
+ "onlyNumberSp": {
+ "regex": /^[0-9\ ]+$/,
+ "alertText": "* Только чиÑла"
+ },
+ "onlyLetterSp": {
+ "regex": /^[a-zA-Z\u0400-\u04FF\ \']+$/,
+ "alertText": "* Только буквы"
+ },
+ "onlyLetterNumber": {
+ "regex": /^[0-9a-zA-Z\u0400-\u04FF]+$/,
+ "alertText": "* Запрещены Ñпециальные Ñимволы"
+ },
+ // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
+ "ajaxUserCall": {
+ "url": "ajaxValidateFieldUser",
+ // you may want to pass extra data on the ajax call
+ "extraData": "name=eric",
+ "alertText": "* Ðтот пользователь уже занÑÑ‚",
+ "alertTextLoad": "* Проверка, подождите..."
+ },
+ "ajaxNameCall": {
+ // remote json service location
+ "url": "ajaxValidateFieldName",
+ // error
+ "alertText": "* Ðто Ð¸Ð¼Ñ ÑƒÐ¶Ðµ занÑто",
+ // if you provide an "alertTextOk", it will show as a green prompt when the field validates
+ "alertTextOk": "* Ðто Ð¸Ð¼Ñ Ð´Ð¾Ñтупно",
+ // speaks by itself
+ "alertTextLoad": "* Проверка, подождите..."
+ },
+ "validate2fields": {
+ "alertText": "* ПожалуйÑта, введите HELLO"
+ }
+ };
+
+ }
+ };
+ $.validationEngineLanguage.newLang();
+})(jQuery);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/a_js/validator/js/jquery.validationEngine.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,1145 @@
+/*
+ * Inline Form Validation Engine 2.0 Beta, jQuery plugin
+ *
+ * Copyright(c) 2010, Cedric Dugas
+ * http://www.position-absolute.com
+ *
+ * 2.0 Rewrite by Olivier Refalo
+ * http://www.crionics.com
+ *
+ * Form validation engine allowing custom regex rules to be added.
+ * Licensed under the MIT License
+ */
+(function($) {
+
+ var methods = {
+
+ /**
+ * Kind of the constructor, called before any action
+ * @param {Map} user options
+ */
+ init: function(options) {
+
+ var form = this;
+ if (form.data('jqv') === undefined || form.data('jqv') == null ) {
+ methods._saveOptions(form, options);
+
+ // bind all formError elements to close on click
+ $(".formError").live("click", function() {
+ $(this).fadeOut(150, function() {
+
+ // remove prompt once invisible
+ $(this).remove();
+ });
+ });
+ }
+ },
+ /**
+ * Attachs jQuery.validationEngine to form.submit and field.blur events
+ * Takes an optional params: a list of options
+ * ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"});
+ */
+ attach: function(userOptions) {
+ var form = this;
+
+ var options;
+
+ if(userOptions)
+ options = methods._saveOptions(form, userOptions);
+ else
+ options = form.data('jqv');
+
+ if (!options.binded) {
+ if(options.bindMethod == "bind"){
+ // bind fields
+ form.find("[class*=validate]").not("[type=checkbox]").bind(options.validationEventTrigger, methods._onFieldEvent);
+ form.find("[class*=validate][type=checkbox]").bind("click", methods._onFieldEvent);
+
+ // bind form.submit
+ form.bind("submit", methods._onSubmitEvent);
+ }else if(options.bindMethod == "live"){
+ // bind fields with LIVE (for persistant state)
+ form.find("[class*=validate]").not("[type=checkbox]").live(options.validationEventTrigger, methods._onFieldEvent);
+ form.find("[class*=validate][type=checkbox]").live("click", methods._onFieldEvent);
+
+ // bind form.submit
+ form.live("submit", methods._onSubmitEvent);
+ }
+
+ options.binded = true;
+ }
+
+ },
+ /**
+ * Unregisters any bindings that may point to jQuery.validaitonEngine
+ */
+ detach: function() {
+ var form = this;
+ var options = form.data('jqv');
+ if (options.binded) {
+
+ // unbind fields
+ form.find("[class*=validate]").not("[type=checkbox]").unbind(options.validationEventTrigger, methods._onFieldEvent);
+ form.find("[class*=validate][type=checkbox]").unbind("click", methods._onFieldEvent);
+ // unbind form.submit
+ form.unbind("submit", methods.onAjaxFormComplete);
+
+
+ // unbind live fields (kill)
+ form.find("[class*=validate]").not("[type=checkbox]").die(options.validationEventTrigger, methods._onFieldEvent);
+ form.find("[class*=validate][type=checkbox]").die("click", methods._onFieldEvent);
+ // unbind form.submit
+ form.die("submit", methods.onAjaxFormComplete);
+
+ form.removeData('jqv');
+ }
+ },
+ /**
+ * Validates the form fields, shows prompts accordingly.
+ * Note: There is no ajax form validation with this method, only field ajax validation are evaluated
+ *
+ * @return true if the form validates, false if it fails
+ */
+ validate: function() {
+ return methods._validateFields(this);
+ },
+ /**
+ * Validates one field, shows prompt accordingly.
+ * Note: There is no ajax form validation with this method, only field ajax validation are evaluated
+ *
+ * @return true if the form validates, false if it fails
+ */
+ validateField: function(el) {
+ var options = $(this).data('jqv');
+ return methods._validateField($(el), options);
+ },
+ /**
+ * Validates the form fields, shows prompts accordingly.
+ * Note: this methods performs fields and form ajax validations(if setup)
+ *
+ * @return true if the form validates, false if it fails, undefined if ajax is used for form validation
+ */
+ validateform: function() {
+ return methods._onSubmitEvent(this);
+ },
+ /**
+ * Displays a prompt on a element.
+ * Note that the element needs an id!
+ *
+ * @param {String} promptText html text to display type
+ * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
+ * @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight
+ */
+ showPrompt: function(promptText, type, promptPosition, showArrow) {
+
+ var form = this.closest('form');
+ var options = form.data('jqv');
+
+ if(!promptPosition)
+ options.promptPosition=promptPosition;
+ options.showArrow = showArrow===true;
+
+ methods._showPrompt(this, promptText, type, false, options);
+ },
+ /**
+ * Closes all error prompts on the page
+ */
+ hidePrompt: function() {
+ var promptClass = "."+ $(this).attr("id").replace(":","_") + "formError"
+ $(promptClass).fadeTo("fast", 0.3, function() {
+ $(this).remove();
+ });
+ },
+ /**
+ * Closes form error prompts
+ */
+ hide: function() {
+ var formParentalClassName = "parentForm"+$(this).attr('id');
+ $('.'+formParentalClassName).fadeTo("fast", 0.3, function() {
+ $(this).remove();
+ });
+ },
+ /**
+ * Closes all error prompts on the page
+ */
+ hideAll: function() {
+ $('.formError').fadeTo("fast", 0.3, function() {
+ $(this).remove();
+ });
+ },
+ /**
+ * Typically called when user exists a field using tab or a mouse click, triggers a field
+ * validation
+ */
+ _onFieldEvent: function() {
+ var field = $(this);
+ var form = field.closest('form');
+ var options = form.data('jqv');
+ // validate the current field
+ methods._validateField(field, options);
+ },
+ /**
+ * Called when the form is submited, shows prompts accordingly
+ *
+ * @param {jqObject}
+ * form
+ * @return false if form submission needs to be cancelled
+ */
+ _onSubmitEvent: function() {
+
+ var form = $(this);
+ var r=methods._validateFields(form, true);
+
+ var options = form.data('jqv');
+ // validate the form using AJAX
+ if (r && options.ajaxFormValidation) {
+
+ methods._validateFormWithAjax(form, options);
+ return false;
+ }
+
+ if(options.onValidationComplete) {
+ options.onValidationComplete(form, r);
+ return false;
+ }
+ return r;
+ },
+ /**
+ * Return true if the ajax field validations passed so far
+ * @param {Object} options
+ * @return true, is all ajax validation passed so far (remember ajax is async)
+ */
+ _checkAjaxStatus: function(options) {
+ var status = true;
+ $.each(options.ajaxValidCache, function(key, value) {
+ if (value === false) {
+ status = false;
+ // break the each
+ return false;
+ }
+ });
+ return status;
+ },
+ /**
+ * Validates form fields, shows prompts accordingly
+ *
+ * @param {jqObject}
+ * form
+ * @return true if form is valid, false if not, undefined if ajax form validation is done
+ */
+ _validateFields: function(form, skipAjaxFieldValidation) {
+
+ var options = form.data('jqv');
+
+ // this variable is set to true if an error is found
+ var errorFound = false;
+
+ // first, evaluate status of non ajax fields
+ form.find('[class*=validate]').not(':hidden').each( function() {
+ var field = $(this);
+ // fields being valiated though ajax are marked with 'ajaxed',
+ // skip them
+ if (!field.hasClass("ajaxed"))
+ errorFound |= methods._validateField(field, options, skipAjaxFieldValidation);
+ });
+ // second, check to see if all ajax calls completed ok
+ errorFound |= !methods._checkAjaxStatus(options);
+
+ // thrird, check status and scroll the container accordingly
+ if (errorFound) {
+ if (options.scroll) {
+
+ // get the position of the first error, there should be at least one, no need to check this
+ //var destination = form.find(".formError:not('.greenPopup'):first").offset().top;
+
+ // look for the visually top prompt
+ var destination = Number.MAX_VALUE;
+
+ var lst = $(".formError:not('.greenPopup')");
+ for (var i = 0; i < lst.length; i++) {
+ var d = $(lst[i]).offset().top;
+ if (d < destination)
+ destination = d;
+ }
+
+ if (!options.isOverflown)
+ $("html:not(:animated),body:not(:animated)").animate({
+ scrollTop: destination
+ }, 1100);
+ else {
+ var overflowDIV = $(options.overflownDIV);
+ var scrollContainerScroll = overflowDIV.scrollTop();
+ var scrollContainerPos = -parseInt(overflowDIV.offset().top);
+
+ destination += scrollContainerScroll + scrollContainerPos - 5;
+ var scrollContainer = $(options.overflownDIV + ":not(:animated)");
+
+ scrollContainer.animate({
+ scrollTop: destination
+ }, 1100);
+ }
+ }
+ return false;
+ }
+ return true;
+ },
+ /**
+ * This method is called to perform an ajax form validation.
+ * During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true
+ *
+ * @param {jqObject} form
+ * @param {Map} options
+ */
+ _validateFormWithAjax: function(form, options) {
+
+ var data = form.serialize();
+
+ $.ajax({
+ type: "GET",
+ url: form.attr("action"),
+ cache: false,
+ dataType: "json",
+ data: data,
+ form: form,
+ methods: methods,
+ options: options,
+ beforeSend: function() {
+ return options.onBeforeAjaxFormValidation(form, options);
+ },
+ error: function(data, transport) {
+ methods._ajaxError(data, transport);
+ },
+ success: function(json) {
+
+ if (json !== true) {
+
+ // getting to this case doesn't necessary means that the form is invalid
+ // the server may return green or closing prompt actions
+ // this flag helps figuring it out
+ var errorInForm=false;
+ for (var i = 0; i < json.length; i++) {
+ var value = json[i];
+
+ var errorFieldId = value[0];
+ var errorField = $($("#" + errorFieldId)[0]);
+
+ // make sure we found the element
+ if (errorField.length == 1) {
+
+ // promptText or selector
+ var msg = value[2];
+
+ if (value[1] === true) {
+
+ if (msg == "")
+ // if for some reason, status==true and error="", just close the prompt
+ methods._closePrompt(errorField);
+ else {
+ // the field is valid, but we are displaying a green prompt
+ if (options.allrules[msg]) {
+ var txt = options.allrules[msg].alertTextOk;
+ if (txt)
+ msg = txt;
+ }
+ methods._showPrompt(errorField, msg, "pass", false, options);
+ }
+ } else {
+ // the field is invalid, show the red error prompt
+ errorInForm|=true;
+ if (options.allrules[msg]) {
+ var txt = options.allrules[msg].alertText;
+ if (txt)
+ msg = txt;
+ }
+ methods._showPrompt(errorField, msg, "", false, options);
+ }
+ }
+ }
+ options.onAjaxFormComplete(!errorInForm, form, json, options);
+ } else
+ options.onAjaxFormComplete(true, form, "", options);
+ }
+ });
+
+ },
+ /**
+ * Validates field, shows prompts accordingly
+ *
+ * @param {jqObject}
+ * field
+ * @param {Array[String]}
+ * field's validation rules
+ * @param {Map}
+ * user options
+ * @return true if field is valid
+ */
+ _validateField: function(field, options, skipAjaxFieldValidation) {
+
+ if (!field.attr("id"))
+ $.error("jQueryValidate: an ID attribute is required for this field: " + field.attr("name") + " class:" +
+ field.attr("class"));
+
+ var rulesParsing = field.attr('class');
+ var getRules = /validate\[(.*)\]/.exec(rulesParsing);
+ if (getRules === null)
+ return false;
+ var str = getRules[1];
+ var rules = str.split(/\[|,|\]/);
+
+ // true if we ran the ajax validation, tells the logic to stop messing with prompts
+ var isAjaxValidator = false;
+ var fieldName = field.attr("name");
+ var promptText = "";
+ var required = false;
+ options.isError = false;
+ options.showArrow = true;
+ optional = false;
+
+ for (var i = 0; i < rules.length; i++) {
+
+ var errorMsg = undefined;
+ switch (rules[i]) {
+
+ case "optional":
+ optional = true;
+ break;
+ case "required":
+ required = true;
+ errorMsg = methods._required(field, rules, i, options);
+ break;
+ case "custom":
+ errorMsg = methods._customRegex(field, rules, i, options);
+ break;
+ case "ajax":
+ if(!skipAjaxFieldValidation) {
+ // ajax has its own prompts handling technique
+ methods._ajax(field, rules, i, options);
+ isAjaxValidator = true;
+ }
+ break;
+ case "minSize":
+ errorMsg = methods._minSize(field, rules, i, options);
+ break;
+ case "maxSize":
+ errorMsg = methods._maxSize(field, rules, i, options);
+ break;
+ case "min":
+ errorMsg = methods._min(field, rules, i, options);
+ break;
+ case "max":
+ errorMsg = methods._max(field, rules, i, options);
+ break;
+ case "past":
+ errorMsg = methods._past(field, rules, i, options);
+ break;
+ case "future":
+ errorMsg = methods._future(field, rules, i, options);
+ break;
+ case "maxCheckbox":
+ errorMsg = methods._maxCheckbox(field, rules, i, options);
+ field = $($("input[name='" + fieldName + "']"));
+ break;
+ case "minCheckbox":
+ errorMsg = methods._minCheckbox(field, rules, i, options);
+ field = $($("input[name='" + fieldName + "']"));
+ break;
+ case "equals":
+ errorMsg = methods._equals(field, rules, i, options);
+ break;
+ case "funcCall":
+ errorMsg = methods._funcCall(field, rules, i, options);
+ break;
+
+ default:
+ //$.error("jQueryValidator rule not found"+rules[i]);
+ }
+
+ if (errorMsg !== undefined) {
+ promptText += errorMsg + "<br/>";
+ options.isError = true;
+ }
+
+ }
+ // If the rules required is not added, an empty field is not validated
+ if(!required && !optional ){
+ if(field.val() == "") options.isError = false;
+ }
+ // Hack for radio/checkbox group button, the validation go into the
+ // first radio/checkbox of the group
+ var fieldType = field.attr("type");
+
+ if ((fieldType == "radio" || fieldType == "checkbox") && $("input[name='" + fieldName + "']").size() > 1) {
+ field = $($("input[name='" + fieldName + "'][type!=hidden]:first"));
+ options.showArrow = false;
+ }
+
+ if (!isAjaxValidator) {
+ if (options.isError)
+ methods._showPrompt(field, promptText, "", false, options);
+ else
+ methods._closePrompt(field);
+ }
+ return options.isError;
+ },
+ /**
+ * Required validation
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _required: function(field, rules, i, options) {
+
+ switch (field.attr("type")) {
+ case "text":
+ case "password":
+ case "textarea":
+ if (!field.val())
+ return options.allrules[rules[i]].alertText;
+ break;
+ case "radio":
+ case "checkbox":
+ var name = field.attr("name");
+ if ($("input[name='" + name + "']:checked").size() === 0) {
+
+ if ($("input[name='" + name + "']").size() === 1)
+ return options.allrules[rules[i]].alertTextCheckboxe;
+ else
+ return options.allrules[rules[i]].alertTextCheckboxMultiple;
+ }
+ break;
+ // required for <select>
+ case "select-one":
+ // added by paul@kinetek.net for select boxes, Thank you
+ if (!field.val())
+ return options.allrules[rules[i]].alertText;
+ break;
+ case "select-multiple":
+ // added by paul@kinetek.net for select boxes, Thank you
+ if (!field.find("option:selected").val())
+ return options.allrules[rules[i]].alertText;
+ break;
+ }
+ },
+ /**
+ * Validate Regex rules
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _customRegex: function(field, rules, i, options) {
+ var customRule = rules[i + 1];
+ var pattern = new RegExp(options.allrules[customRule].regex);
+
+ if (!pattern.test(field.attr('value')))
+ return options.allrules[customRule].alertText;
+ },
+ /**
+ * Validate custom function outside of the engine scope
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _funcCall: function(field, rules, i, options) {
+ var functionName = rules[i + 1];
+ var fn = window[functionName];
+ if (typeof(fn) === 'function')
+ return fn(field, rules, i, options);
+
+ },
+ /**
+ * Field match
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _equals: function(field, rules, i, options) {
+ var equalsField = rules[i + 1];
+
+ if (field.attr('value') != $("#" + equalsField).attr('value'))
+ return options.allrules.equals.alertText;
+ },
+ /**
+ * Check the maximum size (in characters)
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _maxSize: function(field, rules, i, options) {
+ var max = rules[i + 1];
+ var len = field.attr('value').length;
+
+ if (len > max) {
+ var rule = options.allrules.maxSize;
+ return rule.alertText + max + rule.alertText2;
+ }
+ },
+ /**
+ * Check the minimum size (in characters)
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _minSize: function(field, rules, i, options) {
+ var min = rules[i + 1];
+ var len = field.attr('value').length;
+
+ if (len < min) {
+ var rule = options.allrules.minSize;
+ return rule.alertText + min + rule.alertText2;
+ }
+ },
+ /**
+ * Check number minimum value
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _min: function(field, rules, i, options) {
+ var min = parseFloat(rules[i + 1]);
+ var len = parseFloat(field.attr('value'));
+
+ if (len < min) {
+ var rule = options.allrules.min;
+ if (rule.alertText2) return rule.alertText + min + rule.alertText2;
+ return rule.alertText + min;
+ }
+ },
+ /**
+ * Check number maximum value
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _max: function(field, rules, i, options) {
+ var max = parseFloat(rules[i + 1]);
+ var len = parseFloat(field.attr('value'));
+
+ if (len >max ) {
+ var rule = options.allrules.max;
+ if (rule.alertText2) return rule.alertText + max + rule.alertText2;
+ //orefalo: to review, also do the translations
+ return rule.alertText + max;
+ }
+ },
+ /**
+ * Checks date is in the past
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _past: function(field, rules, i, options) {
+
+ var p=rules[i + 1];
+ var pdate = (p.toLowerCase() == "now")? new Date():methods._parseDate(p);
+ var vdate = methods._parseDate(field.attr('value'));
+
+ if (vdate > pdate ) {
+ var rule = options.allrules.past;
+ if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
+ return rule.alertText + methods._dateToString(pdate);
+ }
+ },
+ /**
+ * Checks date is in the past
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _future: function(field, rules, i, options) {
+
+ var p=rules[i + 1];
+ var pdate = (p.toLowerCase() == "now")? new Date():methods._parseDate(p);
+ var vdate = methods._parseDate(field.attr('value'));
+
+ if (vdate < pdate ) {
+ var rule = options.allrules.future;
+ if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
+ return rule.alertText + methods._dateToString(pdate);
+ }
+ },
+ /**
+ * Max number of checkbox selected
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _maxCheckbox: function(field, rules, i, options) {
+
+ var nbCheck = rules[i + 1];
+ var groupname = field.attr("name");
+ var groupSize = $("input[name='" + groupname + "']:checked").size();
+ if (groupSize > nbCheck) {
+ options.showArrow = false;
+ return options.allrules.maxCheckbox.alertText;
+ }
+ },
+ /**
+ * Min number of checkbox selected
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return an error string if validation failed
+ */
+ _minCheckbox: function(field, rules, i, options) {
+
+ var nbCheck = rules[i + 1];
+ var groupname = field.attr("name");
+ var groupSize = $("input[name='" + groupname + "']:checked").size();
+ if (groupSize < nbCheck) {
+ options.showArrow = false;
+ return options.allrules.minCheckbox.alertText + " " + nbCheck + " " +
+ options.allrules.minCheckbox.alertText2;
+ }
+ },
+ /**
+ * Ajax field validation
+ *
+ * @param {jqObject} field
+ * @param {Array[String]} rules
+ * @param {int} i rules index
+ * @param {Map}
+ * user options
+ * @return nothing! the ajax validator handles the prompts itself
+ */
+ _ajax: function(field, rules, i, options) {
+
+ var errorSelector = rules[i + 1];
+ var rule = options.allrules[errorSelector];
+ var extraData = rule.extraData;
+
+ if (!extraData)
+ extraData = "";
+
+ if (!options.isError) {
+ $.ajax({
+ type: "GET",
+ url: rule.url,
+ cache: false,
+ dataType: "json",
+ data: "fieldId=" + field.attr("id") + "&fieldValue=" + field.attr("value") + "&extraData=" + extraData,
+ field: field,
+ rule: rule,
+ methods: methods,
+ options: options,
+ beforeSend: function() {
+ // build the loading prompt
+ var loadingText = rule.alertTextLoad;
+ if (loadingText)
+ methods._showPrompt(field, loadingText, "load", true, options);
+ },
+ error: function(data, transport) {
+ methods._ajaxError(data, transport);
+ },
+ success: function(json) {
+
+ // asynchronously called on success, data is the json answer from the server
+ var errorFieldId = json[0];
+ var errorField = $($("#" + errorFieldId)[0]);
+ // make sure we found the element
+ if (errorField.length == 1) {
+
+ var status = json[1];
+
+ if (status === false) {
+ // Houston we got a problem
+ options.ajaxValidCache[errorFieldId] = false;
+ options.isError = true;
+ var promptText = rule.alertText;
+ methods._showPrompt(errorField, promptText, "", true, options);
+ } else {
+ if (options.ajaxValidCache[errorFieldId] !== undefined)
+ options.ajaxValidCache[errorFieldId] = true;
+
+ // see if we should display a green prompt
+ var alertTextOk = rule.alertTextOk;
+ if (alertTextOk)
+ methods._showPrompt(errorField, alertTextOk, "pass", true, options);
+ else
+ methods._closePrompt(errorField);
+ }
+ }
+ }
+ });
+ }
+ },
+ /**
+ * Common method to handle ajax errors
+ *
+ * @param {Object} data
+ * @param {Object} transport
+ */
+ _ajaxError: function(data, transport) {
+ if(data.status === 0 && transport === null)
+ alert("The page is not served from a server! ajax call failed");
+ else if(console)
+ console.log("Ajax error: " + data.status + " " + transport);
+ },
+ /**
+ * date -> string
+ *
+ * @param {Object} date
+ */
+ _dateToString: function(date) {
+
+ return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
+ },
+ /**
+ * Parses an ISO date
+ * @param {String} d
+ */
+ _parseDate: function(d) {
+
+ var dateParts = d.split("-");
+ if(dateParts!==d)
+ dateParts = d.split("/");
+ return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]);
+ },
+ /**
+ * Builds or updates a prompt with the given information
+ *
+ * @param {jqObject} field
+ * @param {String} promptText html text to display type
+ * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
+ * @param {boolean} ajaxed - use to mark fields than being validated with ajax
+ * @param {Map} options user options
+ */
+ _showPrompt: function(field, promptText, type, ajaxed, options) {
+ var prompt = methods._getPrompt(field);
+ if (prompt)
+ methods._updatePrompt(field, prompt, promptText, type, ajaxed, options);
+ else
+ methods._buildPrompt(field, promptText, type, ajaxed, options);
+ },
+ /**
+ * Builds and shades a prompt for the given field.
+ *
+ * @param {jqObject} field
+ * @param {String} promptText html text to display type
+ * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
+ * @param {boolean} ajaxed - use to mark fields than being validated with ajax
+ * @param {Map} options user options
+ */
+ _buildPrompt: function(field, promptText, type, ajaxed, options) {
+
+ // create the prompt
+ var prompt = $('<div>');
+ prompt.addClass(field.attr("id").replace(":","_") + "formError");
+ // add a class name to identify the parent form of the prompt
+ prompt.addClass("parentForm"+field.parents('form').attr("id").replace(":","_"));
+ prompt.addClass("formError");
+
+ switch (type) {
+ case "pass":
+ prompt.addClass("greenPopup");
+ break;
+ case "load":
+ prompt.addClass("blackPopup");
+ }
+ if (ajaxed)
+ prompt.addClass("ajaxed");
+
+ // create the prompt content
+ var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt);
+
+ // create the css arrow pointing at the field
+ // note that there is no triangle on max-checkbox and radio
+ if (options.showArrow) {
+ var arrow = $('<div>').addClass("formErrorArrow");
+
+ switch (options.promptPosition) {
+ case "bottomLeft":
+ case "bottomRight":
+ prompt.find(".formErrorContent").before(arrow);
+ arrow.addClass("formErrorArrowBottom").html('<div class="line1"><!-- --></div><div class="line2"><!-- --></div><div class="line3"><!-- --></div><div class="line4"><!-- --></div><div class="line5"><!-- --></div><div class="line6"><!-- --></div><div class="line7"><!-- --></div><div class="line8"><!-- --></div><div class="line9"><!-- --></div><div class="line10"><!-- --></div>');
+ break;
+ case "topLeft":
+ case "topRight":
+ arrow.html('<div class="line10"><!-- --></div><div class="line9"><!-- --></div><div class="line8"><!-- --></div><div class="line7"><!-- --></div><div class="line6"><!-- --></div><div class="line5"><!-- --></div><div class="line4"><!-- --></div><div class="line3"><!-- --></div><div class="line2"><!-- --></div><div class="line1"><!-- --></div>');
+ prompt.append(arrow);
+ break;
+ }
+ }
+
+ //Cedric: Needed if a container is in position:relative
+ // insert prompt in the form or in the overflown container?
+ if (options.isOverflown)
+ field.before(prompt);
+ else
+ $("body").append(prompt);
+
+ var pos = methods._calculatePosition(field, prompt, options);
+ prompt.css({
+ "top": pos.callerTopPosition,
+ "left": pos.callerleftPosition,
+ "marginTop": pos.marginTopSize,
+ "opacity": 0
+ });
+
+ return prompt.animate({
+ "opacity": 0.87
+ });
+
+ },
+ /**
+ * Updates the prompt text field - the field for which the prompt
+ * @param {jqObject} field
+ * @param {String} promptText html text to display type
+ * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
+ * @param {boolean} ajaxed - use to mark fields than being validated with ajax
+ * @param {Map} options user options
+ */
+ _updatePrompt: function(field, prompt, promptText, type, ajaxed, options) {
+
+ if (prompt) {
+ if (type == "pass")
+ prompt.addClass("greenPopup");
+ else
+ prompt.removeClass("greenPopup");
+
+ if (type == "load")
+ prompt.addClass("blackPopup");
+ else
+ prompt.removeClass("blackPopup");
+
+ if (ajaxed)
+ prompt.addClass("ajaxed");
+ else
+ prompt.removeClass("ajaxed");
+
+ prompt.find(".formErrorContent").html(promptText);
+
+ var pos = methods._calculatePosition(field, prompt, options);
+ prompt.animate({
+ "top": pos.callerTopPosition,
+ "marginTop": pos.marginTopSize
+ });
+ }
+ },
+ /**
+ * Closes the prompt associated with the given field
+ *
+ * @param {jqObject}
+ * field
+ */
+ _closePrompt: function(field) {
+
+ var prompt = methods._getPrompt(field);
+ if (prompt)
+ prompt.fadeTo("fast", 0, function() {
+ prompt.remove();
+ });
+ },
+ closePrompt: function(field) {
+ return methods._closePrompt(field);
+ },
+ /**
+ * Returns the error prompt matching the field if any
+ *
+ * @param {jqObject}
+ * field
+ * @return undefined or the error prompt (jqObject)
+ */
+ _getPrompt: function(field) {
+
+ var className = "." + field.attr("id").replace(":","_") + "formError";
+ var match = $(className)[0];
+ if (match)
+ return $(match);
+ },
+ /**
+ * Calculates prompt position
+ *
+ * @param {jqObject}
+ * field
+ * @param {jqObject}
+ * the prompt
+ * @param {Map}
+ * options
+ * @return positions
+ */
+ _calculatePosition: function(field, promptElmt, options) {
+
+ var promptTopPosition, promptleftPosition, marginTopSize;
+ var fieldWidth = field.width();
+ var promptHeight = promptElmt.height();
+
+ var overflow = options.isOverflown;
+ if (overflow) {
+ // is the form contained in an overflown container?
+ promptTopPosition = promptleftPosition = 0;
+ // compensation for the arrow
+ marginTopSize = -promptHeight;
+ } else {
+ var offset = field.offset();
+ promptTopPosition = offset.top;
+ promptleftPosition = offset.left;
+ marginTopSize = 0;
+ }
+
+ switch (options.promptPosition) {
+
+ default:
+ case "topRight":
+ if (overflow)
+ // Is the form contained in an overflown container?
+ promptleftPosition += fieldWidth - 30;
+ else {
+ promptleftPosition += fieldWidth - 30;
+ promptTopPosition += -promptHeight;
+ }
+ break;
+ case "topLeft":
+ promptTopPosition += -promptHeight - 10;
+ break;
+ case "centerRight":
+ promptleftPosition += fieldWidth + 13;
+ break;
+ case "bottomLeft":
+ promptTopPosition = promptTopPosition + field.height() + 15;
+ break;
+ case "bottomRight":
+ promptleftPosition += fieldWidth - 30;
+ promptTopPosition += field.height() + 5;
+ }
+
+ return {
+ "callerTopPosition": promptTopPosition + "px",
+ "callerleftPosition": promptleftPosition + "px",
+ "marginTopSize": marginTopSize + "px"
+ };
+ },
+ /**
+ * Saves the user options and variables in the form.data
+ *
+ * @param {jqObject}
+ * form - the form where the user option should be saved
+ * @param {Map}
+ * options - the user options
+ * @return the user options (extended from the defaults)
+ */
+ _saveOptions: function(form, options) {
+
+ // is there a language localisation ?
+ if ($.validationEngineLanguage)
+ var allRules = $.validationEngineLanguage.allRules;
+ else
+ $.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page");
+
+ var userOptions = $.extend({
+
+ // Name of the event triggering field validation
+ validationEventTrigger: "blur",
+ // Automatically scroll viewport to the first error
+ scroll: true,
+ // Opening box position, possible locations are: topLeft,
+ // topRight, bottomLeft, centerRight, bottomRight
+ promptPosition: "topRight",
+ bindMethod:"bind",
+
+ // if set to true, the form data is sent asynchronously via ajax to the form.action url (get)
+ ajaxFormValidation: false,
+ // Ajax form validation callback method: boolean onComplete(form, status, errors, options)
+ // retuns false if the form.submit event needs to be canceled.
+ onAjaxFormComplete: $.noop,
+ // called right before the ajax call, may return false to cancel
+ onBeforeAjaxFormValidation: $.noop,
+ // Stops form from submitting and execute function assiciated with it
+ onValidationComplete: false,
+
+ // Used when the form is displayed within a scrolling DIV
+ isOverflown: false,
+ overflownDIV: "",
+
+ // --- Internals DO NOT TOUCH or OVERLOAD ---
+ // validation rules and i18
+ allrules: allRules,
+ // true when form and fields are binded
+ binded: false,
+ // set to true, when the prompt arrow needs to be displayed
+ showArrow: true,
+ // did one of the validation fail ? kept global to stop further ajax validations
+ isError: false,
+ // Caches field validation status, typically only bad status are created.
+ // the array is used during ajax form validation to detect issues early and prevent an expensive submit
+ ajaxValidCache: {}
+
+ }, options);
+
+ form.data('jqv', userOptions);
+ return userOptions;
+ }
+ };
+
+ /**
+ * Plugin entry point.
+ * You may pass an action as a parameter or a list of options.
+ * if none, the init and attach methods are being called.
+ * Remember: if you pass options, the attached method is NOT called automatically
+ *
+ * @param {String}
+ * method (optional) action
+ */
+ $.fn.validationEngine = function(method) {
+
+ var form = $(this);
+ if(!form[0]) return false; // stop here if the form do not exist
+
+ if (typeof(method) === 'string' && method.charAt(0) != '_' && methods[method]) {
+ // make sure init is being called at least once
+ methods.init.apply(form);
+ return methods[method].apply(form, Array.prototype.slice.call(arguments, 1));
+ } else if (typeof method === 'object' || !method) {
+ methods.init.apply(form, arguments);
+ return methods.attach.apply(form);
+ } else {
+ $.error('Method ' + method + ' does not exist in jQuery.validationEngine');
+ }
+ };
+})(jQuery);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/index.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,189 @@
+<!--
+ ~ Copyright (c) 2011 Denis Duvauchelle (denisduvauchelle.com)
+ ~ under the MIT licence defined at
+ ~ http://www.opensource.org/licenses/mit-license.html
+ -->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+<title>SocWeb - The new semantic web</title>
+
+<link rel="shortcut icon" type="image/x-icon" href="a_img/favicon.ico">
+<link rel="stylesheet" type="text/css" href="a_css/general.css">
+
+
+
+<script type="text/javascript" src="a_js/jquery144min.js"></script>
+
+<!--PLUGGIN FOR AUTO COMPLETE-->
+<link rel="stylesheet" type="text/css" href="a_js/jquery-autocomplete/jquery.autocomplete.css">
+<script type="text/javascript" src="a_js/jquery-autocomplete/jquery.autocomplete.js"></script>
+
+<!--PLUGGIN FOR AJAX FILE UPLOADER-->
+<script type="text/javascript" src="js/ajaxuploader.js"></script>
+
+<script type="text/javascript" src="a_js/general.js"></script>
+
+
+</head>
+
+<body>
+
+
+<div id="topbar">
+ <div class="wrapper">
+ <h1 id="logo">SocWeb</h1>
+ <form method="get" action="">
+ <input type="text" value="" name="q" id="main_search">
+ <button type="submit"></button>
+ </form>
+
+ <a href="index.html" class="topbar_links">The Wall</a>
+ <a href="social_book.html" class="topbar_links">Social book</a>
+
+ <div>
+
+
+
+ <a href=""><img src="a_img/avatar.png" height="20" align="absmiddle" /> Username</a>
+ <span>|</span>
+ <a href="">Log out</a>
+
+
+
+
+
+ </div>
+ </div>
+</div>
+
+
+
+ <div id="site_wrapper">
+
+ <div id="status_box">
+ <h2>Say what you go to say:</h2>
+ <form method="post" id="form_status">
+ <textarea name="status_input" id="status_input"></textarea>
+
+ <div id="status_options_file" class="hide">
+ <button type="button" id="status_upload_file">Upload a file</button>
+ <span class="hider" id="status_file_name"></span>
+ <br />
+ </div>
+ <br />
+ <button id="status_btn_submit" type="submit">Update</button> <span>( Hit Tab + enter to submit the post )</span>
+ <input id="status_file_temp_name" type="hidden" name="file_name" value="" />
+ <input type="hidden" name="actions" value="add_status">
+ </form>
+ </div>
+
+
+
+ <br><br>
+ <h1>Feed display</h1>
+ <br><br>
+
+
+ <div class="story_box" id='story_box_181'>
+ <div class="story_left_column">
+ <img src="http://media.linkedin.com/mpr/mprx/0_7QQHyxI2mtCFMsAC7kvRypI8C-cbRJKCDTtByjsggciBXgbGi8nX-gaPuyBZZOlmm5k9PsX9885p" alt="User avatar" />
+ </div>
+
+
+ <div class="story_right_column">
+ <div class="text " id="text_181">This is where your wall post will go.</div>
+ <span>Published by <a href="#" class='username'>@denisduvauchelle</a></span> |
+ <a href='#' class='show_comment' title='181'>Add a comment</a>
+ </div>
+
+ <div class="clear"></div>
+
+ <div class="story_bottom_row">
+
+
+ <div class="story_bottom_right">
+
+ </div>
+
+ <div class="clear"></div>
+
+ </div>
+
+ <div class="clear"></div>
+
+ <div class='hide' id='comment_area_181'>
+ <br>
+ <div id="placing_181"></div>
+
+
+ <div class="story_comments">
+ <div class="story_comments_img">
+ <img src="http://media.linkedin.com/mpr/mprx/0_7QQHyxI2mtCFMsAC7kvRypI8C-cbRJKCDTtByjsggciBXgbGi8nX-gaPuyBZZOlmm5k9PsX9885p" alt="User avatar" width="30" height="30" />
+ </div>
+ <div class="story_comments_txt">
+ Username - <strong>This is a comment </strong>
+ </div>
+ <div class="clear"></div>
+ </div>
+
+
+
+ <div class="story_comments">
+
+ <div class="story_comments_img">
+ <img src="http://media.linkedin.com/mpr/mprx/0_7QQHyxI2mtCFMsAC7kvRypI8C-cbRJKCDTtByjsggciBXgbGi8nX-gaPuyBZZOlmm5k9PsX9885p" alt="User avatar" width="30" height="30" />
+ </div>
+
+ <div class="story_comments_txt">
+ <form class='comments_form' method='post'>
+ <textarea name="comment" class="story_comment_textarea" id='comment_field_181'></textarea>
+ <input type='hidden' name="id_feed" value='181' >
+ <input type='hidden' name="actions" value='add_comment' >
+ <button type="submit">Post</button>
+ </form>
+ </div>
+
+ <div class="clear"></div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+
+
+
+ <div class="clear"></div>
+
+
+
+
+</div> <!-- END OF SITE_WRAPPER -->
+
+ <div id="footer" class="wrapper">
+
+
+ </div> <!-- END OF FOOTER -->
+
+
+<script type="text/javascript">
+/*
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-25910668-1']);
+ _gaq.push(['_trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
+*/
+</script>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/social_book.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,190 @@
+<!--
+ ~ Copyright (c) 2011 Denis Duvauchelle (denisduvauchelle.com)
+ ~ under the MIT licence defined at
+ ~ http://www.opensource.org/licenses/mit-license.html
+ -->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+<title>SocWeb - The new semantic web</title>
+
+<link rel="shortcut icon" type="image/x-icon" href="a_img/favicon.ico">
+<link rel="stylesheet" type="text/css" href="a_css/general.css">
+
+
+
+<script type="text/javascript" src="a_js/jquery144min.js"></script>
+
+
+<!--PLUGGIN FOR AUTO COMPLETE-->
+<link rel="stylesheet" type="text/css" href="a_js/jquery-autocomplete/jquery.autocomplete.css">
+<script type="text/javascript" src="a_js/jquery-autocomplete/jquery.autocomplete.js"></script>
+
+
+
+
+</head>
+
+<body>
+
+
+<div id="topbar">
+ <div class="wrapper">
+ <h1 id="logo">SocWeb</h1>
+ <form method="get" action="">
+ <input type="text" value="" name="q" id="main_search">
+ <button type="submit"></button>
+ </form>
+
+ <a href="index.html" class="topbar_links">The Wall</a>
+ <a href="social_book.html" class="topbar_links">Social book</a>
+
+ <div>
+
+
+
+ <a href=""><img src="a_img/avatar.png" height="20" align="absmiddle" /> Username</a>
+ <span>|</span>
+ <a href="">Log out</a>
+
+
+
+
+
+ </div>
+ </div>
+</div>
+
+
+
+ <div id="site_wrapper">
+
+
+<h1>Social book</h1>
+
+<script type="text/javascript">
+$(document).ready(function(){
+
+ $('.listing_user').live('click',function(){
+ $(this).siblings().removeClass('clicked_user');
+ $(this).addClass('clicked_user');;
+
+ });
+
+});
+</script>
+
+
+<style>
+.panel{ float:left; height:500px; border:1px solid #CCC; overflow-y:scroll; overflo-x:hidden; }
+
+.listing{ margin-right:2px; width:186px; }
+.listing_user{ padding:4px 0px; padding-left:4px; width:165px; overflow:hidden; cursor:pointer; white-space: nowrap; }
+.listing_user:hover, .clicked_user{ background:#F2F2F2; }
+
+
+.user{ width:383px; }
+#user_wrapper{ padding:5px; width:355px; }
+#user_wrapper img{ float:left; }
+#user_wrapper h1{ margin:0px; padding:20px; font-size:18px; color:#333333; float:left; }
+#user_wrapper h1 span{ display:block; color:#CCC; font-size:12px; font-weight:normal; }
+#user_wrapper ul{ padding:0px; margin:0px; text-indent:0px; list-style:none; }
+#user_wrapper ul li{ padding:6px 4px; }
+#user_wrapper ul li:hover{ background:#F2F2F2; }
+#user_wrapper ul li label{ color:#3333333; font-weight:bold; width:150px; display:inline-block; }
+.user_info_input{ display:inline-block; color:#999; font-weight:normal; width:200px; }
+.user_info_input a{ font:14px !important; }
+</style>
+
+ <div class="panel listing" id="panel1">
+ <a class="listing_user" href="">Antoine Duvauchelle</a>
+ <a class="listing_user" href="">Henry Story</a>
+ <a class="listing_user" href="">Adolph Blaine Charles David Earl Frederick Gerald Hubert Irvin John Kenneth Lloyd Martin Nero Oliver Paul Quincy Randolph Sherman Thomas Uncas Victor William Xerxes Yancy Zeus Wolfeschlegelsteinhausenbergerdorff</a>
+ </div>
+
+ <div class="panel listing" id="panel2">
+ <div class="listing_user">Antoine Duvauchelle</div>
+ <div class="listing_user">Henry Story</div>
+
+ <div class="listing_user">Antoine Duvauchelle</div>
+ <div class="listing_user">Henry Story</div>
+ </div>
+
+ <div class="panel listing" id="panel3">
+
+ </div>
+
+ <div class="panel user">
+ <div id="user_wrapper">
+ <img src="a_img/avatar.png" width="80" alt="User avatar">
+ <h1>Henry Story <span>bblfish</span></h1>
+ <div class="clear"></div>
+ <br>
+ <ul>
+ <li>
+ <label>Phone<label>
+ <div class="user_info_input">+86 158 007 22 700</div>
+ </li>
+ <li>
+ <label>Mobile<label>
+ <div class="user_info_input">+86 158 007 22 700</div>
+ </li>
+ <li>
+ <label>Country<label>
+ <div class="user_info_input">France</div>
+ </li>
+ <li>
+ <label>Address<label>
+ <div class="user_info_input">20 Place Napoleon Bonaparte<br>77300 Fontainebleau<br>France</div>
+ </li>
+ <li>
+ <label>Email<label>
+ <div class="user_info_input">youremail@domain.com</div>
+ </li>
+ <li>
+ <label>Website<label>
+ <div class="user_info_input"><a href="#">http://www.website.com</a></div>
+ </li>
+ <li>
+ <label>Birthday<label>
+ <div class="user_info_input">15th of June 1988</div>
+ </li>
+
+ </ul>
+
+ </div>
+ </div>
+
+
+ <div class="clear"></div>
+
+
+
+
+</div> <!-- END OF SITE_WRAPPER -->
+
+ <div id="footer" class="wrapper">
+
+
+ </div> <!-- END OF FOOTER -->
+
+
+<script type="text/javascript">
+/*
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-25910668-1']);
+ _gaq.push(['_trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
+*/
+</script>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/people/test.php Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,21 @@
+<?php
+
+ $disp = "";
+ $disp .= " <div class=\"listing_user\">\n";
+ $disp .= " <div class=\"listing_user_left\">\n";
+ $disp .= " <img src=\"{$user->picture}\" width=\"60\" height=\"60\" />\n";
+ $disp .= " </div>\n";
+ $disp .= " <div class=\"listing_user_right\">\n";
+ $disp .= " <h3>{$user->username} </h3><h4> - {$user->name}</h4><br />\n";
+ $disp .= " {$user->about}<br />\n";
+ $disp .= " <span>{$user->skills}</span><br />\n";
+ $disp .= " \n";
+ $disp .= " <a href=\"\">Go to profile</a>\n";
+ $disp .= " {$friend_or_not}<br />\n";
+ $disp .= " </div>\n";
+ $disp .= " <div class=\"clear\"></div>\n";
+ $disp .= " </div>\n";
+
+ echo $disp;
+
+?>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/public/logout.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* two functions to enable TLS Login and Logout in javascript. Works
+ for Internet Explorer and Firefox. Sadly missing in other browsers */
+
+function logout(elem) {
+ if (document.all == null) {// FF, Opera, etc
+ if (window.crypto) {
+ try{
+ window.crypto.logout();
+ return false; //firefox ok -- no need to follow the link
+ } catch (err) {//Safari, Opera, Chrome -- try with session breaking
+ }
+ } else { //Opera, will require server side session breaking
+ }
+ } else { // MSIE 6+
+ document.execCommand('ClearAuthenticationCache');
+ return false;
+ };
+ return true
+}
+
+function login(elem) { return logout(elem) } //it's just the same at present
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/identity.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,516 @@
+// Identity management and indexing for RDF
+//
+// This file provides IndexedFormula a formula (set of triples) which
+// indexed by predicate, subject and object.
+//
+// It "smushes" (merges into a single node) things which are identical
+// according to owl:sameAs or an owl:InverseFunctionalProperty
+// or an owl:FunctionalProperty
+//
+//
+// 2005-10 Written Tim Berners-Lee
+// 2007 Changed so as not to munge statements from documents when smushing
+//
+//
+
+/*jsl:option explicit*/ // Turn on JavaScriptLint variable declaration checking
+
+$rdf.IndexedFormula = function() {
+
+var owl_ns = "http://www.w3.org/2002/07/owl#";
+// var link_ns = "http://www.w3.org/2007/ont/link#";
+
+/* hashString functions are used as array indeces. This is done to avoid
+** conflict with existing properties of arrays such as length and map.
+** See issue 139.
+*/
+$rdf.Literal.prototype.hashString = $rdf.Literal.prototype.toNT;
+$rdf.Symbol.prototype.hashString = $rdf.Symbol.prototype.toNT;
+$rdf.BlankNode.prototype.hashString = $rdf.BlankNode.prototype.toNT;
+$rdf.Collection.prototype.hashString = $rdf.Collection.prototype.toNT;
+
+
+//Stores an associative array that maps URIs to functions
+$rdf.IndexedFormula = function(features) {
+ this.statements = []; // As in Formula
+ this.optional = [];
+ this.propertyActions = []; // Array of functions to call when getting statement with {s X o}
+ //maps <uri> to [f(F,s,p,o),...]
+ this.classActions = []; // Array of functions to call when adding { s type X }
+ this.redirections = []; // redirect to lexically smaller equivalent symbol
+ this.aliases = []; // reverse mapping to redirection: aliases for this
+ this.HTTPRedirects = []; // redirections we got from HTTP
+ this.subjectIndex = []; // Array of statements with this X as subject
+ this.predicateIndex = []; // Array of statements with this X as subject
+ this.objectIndex = []; // Array of statements with this X as object
+ this.whyIndex = []; // Array of statements with X as provenance
+ this.index = [ this.subjectIndex, this.predicateIndex, this.objectIndex, this.whyIndex ];
+ this.namespaces = {} // Dictionary of namespace prefixes
+ if (features === undefined) features = ["sameAs",
+ "InverseFunctionalProperty", "FunctionalProperty"];
+// this.features = features
+ // Callbackify?
+ function handleRDFType(formula, subj, pred, obj, why) {
+ if (formula.typeCallback != undefined)
+ formula.typeCallback(formula, obj, why);
+
+ var x = formula.classActions[obj.hashString()];
+ var done = false;
+ if (x) {
+ for (var i=0; i<x.length; i++) {
+ done = done || x[i](formula, subj, pred, obj, why);
+ }
+ }
+ return done; // statement given is not needed if true
+ } //handleRDFType
+
+ //If the predicate is #type, use handleRDFType to create a typeCallback on the object
+ this.propertyActions[
+ '<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>'] = [ handleRDFType ];
+
+ // Assumption: these terms are not redirected @@fixme
+ if ($rdf.Util.ArrayIndexOf(features,"sameAs") >= 0)
+ this.propertyActions['<http://www.w3.org/2002/07/owl#sameAs>'] = [
+ function(formula, subj, pred, obj, why) {
+ // tabulator.log.warn("Equating "+subj.uri+" sameAs "+obj.uri); //@@
+ formula.equate(subj,obj);
+ return true; // true if statement given is NOT needed in the store
+ }]; //sameAs -> equate & don't add to index
+
+ if ($rdf.Util.ArrayIndexOf(features,"InverseFunctionalProperty") >= 0)
+ this.classActions["<"+owl_ns+"InverseFunctionalProperty>"] = [
+ function(formula, subj, pred, obj, addFn) {
+ return formula.newPropertyAction(subj, handle_IFP); // yes subj not pred!
+ }]; //IFP -> handle_IFP, do add to index
+
+ if ($rdf.Util.ArrayIndexOf(features,"FunctionalProperty") >= 0)
+ this.classActions["<"+owl_ns+"FunctionalProperty>"] = [
+ function(formula, subj, proj, obj, addFn) {
+ return formula.newPropertyAction(subj, handle_FP);
+ }]; //FP => handleFP, do add to index
+
+ function handle_IFP(formula, subj, pred, obj) {
+ var s1 = formula.any(undefined, pred, obj);
+ if (s1 == undefined) return false; // First time with this value
+ // tabulator.log.warn("Equating "+s1.uri+" and "+subj.uri + " because IFP "+pred.uri); //@@
+ formula.equate(s1, subj);
+ return true;
+ } //handle_IFP
+
+ function handle_FP(formula, subj, pred, obj) {
+ var o1 = formula.any(subj, pred, undefined);
+ if (o1 == undefined) return false; // First time with this value
+ // tabulator.log.warn("Equating "+o1.uri+" and "+obj.uri + " because FP "+pred.uri); //@@
+ formula.equate(o1, obj);
+ return true ;
+ } //handle_FP
+
+} /* end IndexedFormula */
+
+$rdf.IndexedFormula.prototype = new $rdf.Formula();
+$rdf.IndexedFormula.prototype.constructor = $rdf.IndexedFormula;
+$rdf.IndexedFormula.SuperClass = $rdf.Formula;
+
+$rdf.IndexedFormula.prototype.newPropertyAction = function newPropertyAction(pred, action) {
+ //$rdf.log.debug("newPropertyAction: "+pred);
+ var hash = pred.hashString();
+ if (this.propertyActions[hash] == undefined)
+ this.propertyActions[hash] = [];
+ this.propertyActions[hash].push(action);
+ // Now apply the function to to statements already in the store
+ var toBeFixed = this.statementsMatching(undefined, pred, undefined);
+ done = false;
+ for (var i=0; i<toBeFixed.length; i++) { // NOT optimized - sort toBeFixed etc
+ done = done || action(this, toBeFixed[i].subject, pred, toBeFixed[i].object);
+ }
+ return done;
+}
+
+$rdf.IndexedFormula.prototype.setPrefixForURI = function(prefix, nsuri) {
+ //TODO:This is a hack for our own issues, which ought to be fixed post-release
+ //See http://dig.csail.mit.edu/cgi-bin/roundup.cgi/$rdf/issue227
+ if(prefix=="tab" && this.namespaces["tab"]) {
+ return;
+ }
+ this.namespaces[prefix] = nsuri
+}
+
+// Deprocated ... name too generic
+$rdf.IndexedFormula.prototype.register = function(prefix, nsuri) {
+ this.namespaces[prefix] = nsuri
+}
+
+
+/** simplify graph in store when we realize two identifiers are equivalent
+
+We replace the bigger with the smaller.
+
+*/
+$rdf.IndexedFormula.prototype.equate = function(u1, u2) {
+ // tabulator.log.warn("Equating "+u1+" and "+u2); // @@
+ //@@JAMBO Must canonicalize the uris to prevent errors from a=b=c
+ //03-21-2010
+ u1 = this.canon( u1 );
+ u2 = this.canon( u2 );
+ var d = u1.compareTerm(u2);
+ if (!d) return true; // No information in {a = a}
+ var big, small;
+ if (d < 0) { // u1 less than u2
+ return this.replaceWith(u2, u1);
+ } else {
+ return this.replaceWith(u1, u2);
+ }
+}
+
+// Replace big with small, obsoleted with obsoleting.
+//
+$rdf.IndexedFormula.prototype.replaceWith = function(big, small) {
+ //$rdf.log.debug("Replacing "+big+" with "+small) // @@
+ var oldhash = big.hashString();
+ var newhash = small.hashString();
+
+ var moveIndex = function(ix) {
+ var oldlist = ix[oldhash];
+ if (oldlist == undefined) return; // none to move
+ var newlist = ix[newhash];
+ if (newlist == undefined) {
+ ix[newhash] = oldlist;
+ } else {
+ ix[newhash] = oldlist.concat(newlist);
+ }
+ delete ix[oldhash];
+ }
+
+ // the canonical one carries all the indexes
+ for (var i=0; i<4; i++) {
+ moveIndex(this.index[i]);
+ }
+
+ this.redirections[oldhash] = small;
+ if (big.uri) {
+ //@@JAMBO: must update redirections,aliases from sub-items, too.
+ if (this.aliases[newhash] == undefined)
+ this.aliases[newhash] = [];
+ this.aliases[newhash].push(big); // Back link
+
+ if( this.aliases[oldhash] ) {
+ for( var i = 0; i < this.aliases[oldhash].length; i++ ) {
+ this.redirections[this.aliases[oldhash][i].hashString()] = small;
+ this.aliases[newhash].push(this.aliases[oldhash][i]);
+ }
+ }
+
+ this.add(small, this.sym('http://www.w3.org/2007/ont/link#uri'), big.uri)
+
+ // If two things are equal, and one is requested, we should request the other.
+ if (this.sf) {
+ this.sf.nowKnownAs(big, small)
+ }
+ }
+
+ moveIndex(this.classActions);
+ moveIndex(this.propertyActions);
+
+ //$rdf.log.debug("Equate done. "+big+" to be known as "+small)
+ return true; // true means the statement does not need to be put in
+};
+
+// Return the symbol with canonical URI as smushed
+$rdf.IndexedFormula.prototype.canon = function(term) {
+ if (term == undefined) return term;
+ var y = this.redirections[term.hashString()];
+ if (y == undefined) return term;
+ return y;
+}
+
+// Compare by canonical URI as smushed
+$rdf.IndexedFormula.prototype.sameThings = function(x, y) {
+ if (x.sameTerm(y)) return true;
+ var x1 = this.canon(x);
+// alert('x1='+x1);
+ if (x1 == undefined) return false;
+ var y1 = this.canon(y);
+// alert('y1='+y1); //@@
+ if (y1 == undefined) return false;
+ return (x1.uri == y1.uri);
+}
+
+// A list of all the URIs by which this thing is known
+$rdf.IndexedFormula.prototype.uris = function(term) {
+ var cterm = this.canon(term)
+ var terms = this.aliases[cterm.hashString()];
+ if (!cterm.uri) return []
+ var res = [ cterm.uri ]
+ if (terms != undefined) {
+ for (var i=0; i<terms.length; i++) {
+ res.push(terms[i].uri)
+ }
+ }
+ return res
+}
+
+// On input parameters, convert constants to terms
+//
+function RDFMakeTerm(formula,val, canonicalize) {
+ if (typeof val != 'object') {
+ if (typeof val == 'string')
+ return new $rdf.Literal(val);
+ if (typeof val == 'number')
+ return new $rdf.Literal(val); // @@ differet types
+ if (typeof val == 'boolean')
+ return new $rdf.Literal(val?"1":"0", undefined,
+ $rdf.Symbol.prototype.XSDboolean);
+ else if (typeof val == 'number')
+ return new $rdf.Literal(''+val); // @@ datatypes
+ else if (typeof val == 'undefined')
+ return undefined;
+ else // @@ add converting of dates and numbers
+ throw "Can't make Term from " + val + " of type " + typeof val;
+ }
+ return val;
+}
+
+// Add a triple to the store
+//
+// Returns the statement added
+// (would it be better to return the original formula for chaining?)
+//
+$rdf.IndexedFormula.prototype.add = function(subj, pred, obj, why) {
+ var actions, st;
+ if (why == undefined) why = this.fetcher ? this.fetcher.appNode: this.sym("chrome:theSession"); //system generated
+ //defined in source.js, is this OK with identity.js only user?
+ subj = RDFMakeTerm(this, subj);
+ pred = RDFMakeTerm(this, pred);
+ obj = RDFMakeTerm(this, obj);
+ why = RDFMakeTerm(this, why);
+
+ var hash = [ this.canon(subj).hashString(), this.canon(pred).hashString(),
+ this.canon(obj).hashString(), this.canon(why).hashString()];
+
+
+ if (this.predicateCallback != undefined)
+ this.predicateCallback(this, pred, why);
+
+ // Action return true if the statement does not need to be added
+ var actions = this.propertyActions[hash[1]]; // Predicate hash
+ var done = false;
+ if (actions) {
+ // alert('type: '+typeof actions +' @@ actions='+actions);
+ for (var i=0; i<actions.length; i++) {
+ done = done || actions[i](this, subj, pred, obj, why);
+ }
+ }
+
+ //If we are tracking provenanance, every thing should be loaded into the store
+ //if (done) return new Statement(subj, pred, obj, why); // Don't put it in the store
+ // still return this statement for owl:sameAs input
+ var st = new $rdf.Statement(subj, pred, obj, why);
+ for (var i=0; i<4; i++) {
+ var ix = this.index[i];
+ var h = hash[i];
+ if (ix[h] == undefined) ix[h] = [];
+ ix[h].push(st); // Set of things with this as subject, etc
+ }
+
+ //$rdf.log.debug("ADDING {"+subj+" "+pred+" "+obj+"} "+why);
+ this.statements.push(st);
+ return st;
+}; //add
+
+
+// Find out whether a given URI is used as symbol in the formula
+$rdf.IndexedFormula.prototype.mentionsURI = function(uri) {
+ var hash = '<' + uri + '>';
+ return (!!this.subjectIndex[hash] || !!this.objectIndex[hash]
+ || !!this.predicateIndex[hash]);
+}
+
+// Find an unused id for a file being edited: return a symbol
+// (Note: Slow iff a lot of them -- could be O(log(k)) )
+$rdf.IndexedFormula.prototype.nextSymbol = function(doc) {
+ for(var i=0;;i++) {
+ var uri = doc.uri + '#n' + i;
+ if (!this.mentionsURI(uri)) return this.sym(uri);
+ }
+}
+
+
+$rdf.IndexedFormula.prototype.anyStatementMatching = function(subj,pred,obj,why) {
+ var x = this.statementsMatching(subj,pred,obj,why,true);
+ if (!x || x == []) return undefined;
+ return x[0];
+};
+
+
+// Return statements matching a pattern
+// ALL CONVENIENCE LOOKUP FUNCTIONS RELY ON THIS!
+$rdf.IndexedFormula.prototype.statementsMatching = function(subj,pred,obj,why,justOne) {
+ //$rdf.log.debug("Matching {"+subj+" "+pred+" "+obj+"}");
+
+ var pat = [ subj, pred, obj, why ];
+ var pattern = [];
+ var hash = [];
+ var wild = []; // wildcards
+ var given = []; // Not wild
+ for (var p=0; p<4; p++) {
+ pattern[p] = this.canon(RDFMakeTerm(this, pat[p]));
+ if (pattern[p] == undefined) {
+ wild.push(p);
+ } else {
+ given.push(p);
+ hash[p] = pattern[p].hashString();
+ }
+ }
+ if (given.length == 0) {
+ return this.statements;
+ }
+ if (given.length == 1) { // Easy too, we have an index for that
+ var p = given[0];
+ var list = this.index[p][hash[p]];
+ if(list && justOne) {
+ if(list.length>1)
+ list = list.slice(0,1);
+ }
+ return list == undefined ? [] : list;
+ }
+
+ // Now given.length is 2, 3 or 4.
+ // We hope that the scale-free nature of the data will mean we tend to get
+ // a short index in there somewhere!
+
+ var best = 1e10; // really bad
+ var best_i;
+ for (var i=0; i<given.length; i++) {
+ var p = given[i]; // Which part we are dealing with
+ var list = this.index[p][hash[p]];
+ if (list == undefined) return []; // No occurrences
+ if (list.length < best) {
+ best = list.length;
+ best_i = i; // (not p!)
+ }
+ }
+
+ // Ok, we have picked the shortest index but now we have to filter it
+ var best_p = given[best_i];
+ var possibles = this.index[best_p][hash[best_p]];
+ var check = given.slice(0, best_i).concat(given.slice(best_i+1)) // remove best_i
+ var results = [];
+ var parts = [ 'subject', 'predicate', 'object', 'why'];
+ for (var j=0; j<possibles.length; j++) {
+ var st = possibles[j];
+ for (var i=0; i <check.length; i++) { // for each position to be checked
+ var p = check[i];
+ if (!this.canon(st[parts[p]]).sameTerm(pattern[p])) {
+ st = null;
+ break;
+ }
+ }
+ if (st != null) results.push(st);
+ }
+
+ if(justOne) {
+ if(results.length>1)
+ results = results.slice(0,1);
+ }
+ return results;
+}; // statementsMatching
+
+/** remove a particular statement from the bank **/
+$rdf.IndexedFormula.prototype.remove = function (st) {
+ //$rdf.log.debug("entering remove w/ st=" + st);
+ var term = [ st.subject, st.predicate, st.object, st.why];
+ for (var p=0; p<4; p++) {
+ var c = this.canon(term[p]);
+ var h = c.hashString();
+ if (this.index[p][h] == undefined) {
+ //$rdf.log.warn ("Statement removal: no index '+p+': "+st);
+ } else {
+ $rdf.Util.RDFArrayRemove(this.index[p][h], st);
+ }
+ }
+ $rdf.Util.RDFArrayRemove(this.statements, st);
+}; //remove
+
+/** remove all statements matching args (within limit) **/
+$rdf.IndexedFormula.prototype.removeMany = function (subj, pred, obj, why, limit) {
+ //$rdf.log.debug("entering removeMany w/ subj,pred,obj,why,limit = " + subj +", "+ pred+", " + obj+", " + why+", " + limit);
+ var sts = this.statementsMatching (subj, pred, obj, why, false);
+ //This is a subtle bug that occcured in updateCenter.js too.
+ //The fact is, this.statementsMatching returns this.whyIndex instead of a copy of it
+ //but for perfromance consideration, it's better to just do that
+ //so make a copy here.
+ var statements = [];
+ for (var i=0;i<sts.length;i++) statements.push(sts[i]);
+ if (limit) statements = statements.slice(0, limit);
+ for (var i=0;i<statements.length;i++) this.remove(statements[i]);
+}; //removeMany
+
+/** Utility**/
+
+/* @method: copyTo
+ @description: replace @template with @target and add appropriate triples (no triple removed)
+ one-direction replication
+*/
+$rdf.IndexedFormula.prototype.copyTo = function(template,target,flags){
+ if (!flags) flags=[];
+ var statList=this.statementsMatching(template);
+ if ($rdf.Util.ArrayIndexOf(flags,'two-direction')!=-1)
+ statList.concat(this.statementsMatching(undefined,undefined,template));
+ for (var i=0;i<statList.length;i++){
+ var st=statList[i];
+ switch (st.object.termType){
+ case 'symbol':
+ this.add(target,st.predicate,st.object);
+ break;
+ case 'literal':
+ case 'bnode':
+ case 'collection':
+ this.add(target,st.predicate,st.object.copy(this));
+ }
+ if ($rdf.Util.ArrayIndexOf(flags,'delete')!=-1) this.remove(st);
+ }
+};
+//for the case when you alter this.value (text modified in userinput.js)
+$rdf.Literal.prototype.copy = function(){
+ return new $rdf.Literal(this.value,this.lang,this.datatype);
+};
+$rdf.BlankNode.prototype.copy = function(formula){ //depends on the formula
+ var bnodeNew=new $rdf.BlankNode();
+ formula.copyTo(this,bnodeNew);
+ return bnodeNew;
+}
+/** Full N3 bits -- placeholders only to allow parsing, no functionality! **/
+
+$rdf.IndexedFormula.prototype.newUniversal = function(uri) {
+ var x = this.sym(uri);
+ if (!this._universalVariables) this._universalVariables = [];
+ this._universalVariables.push(x);
+ return x;
+}
+
+$rdf.IndexedFormula.prototype.newExistential = function(uri) {
+ if (!uri) return this.bnode();
+ var x = this.sym(uri);
+ return this.declareExistential(x);
+}
+
+$rdf.IndexedFormula.prototype.declareExistential = function(x) {
+ if (!this._existentialVariables) this._existentialVariables = [];
+ this._existentialVariables.push(x);
+ return x;
+}
+
+$rdf.IndexedFormula.prototype.formula = function(features) {
+ return new $rdf.IndexedFormula(features);
+}
+
+$rdf.IndexedFormula.prototype.close = function() {
+ return this;
+}
+
+$rdf.IndexedFormula.prototype.hashString = $rdf.IndexedFormula.prototype.toNT;
+
+return $rdf.IndexedFormula;
+
+}();
+// ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/jsonparser.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,54 @@
+$rdf.jsonParser = function() {
+
+ return {
+ parseJSON: function( data, source, store ) {
+ var subject, predicate, object;
+ var bnodes = {};
+ var why = store.sym(source);
+ for (x in data) {
+ if( x.indexOf( "_:") === 0 ) {
+ if( bnodes[x] ) {
+ subject = bnodes[x];
+ } else {
+ subject = store.bnode(x);
+ bnodes[x]=subject;
+ }
+ } else {
+ subject = store.sym(x);
+ }
+ var preds = data[x];
+ for (y in preds) {
+ var objects = preds[y];
+ predicate = store.sym(y);
+ for( z in objects ) {
+ var obj = objects[z];
+ if( obj.type === "uri" ) {
+ object = store.sym(obj.value);
+ store.add( subject, predicate, object, why );
+ } else if( obj.type === "bnode" ) {
+ if( bnodes[obj.value] ) {
+ object = bnodes[obj.value];
+ } else {
+ object = store.bnode(obj.value);
+ bnodes[obj.value] = object;
+ }
+ store.add( subject, predicate, object, why );
+ } else if( obj.type === "literal" ) {
+ var datatype;
+ if( obj.datatype ) {
+ object = store.literal(obj.value, undefined, store.sym(obj.datatype));
+ } else if ( obj.lang ) {
+ object = store.literal(obj.value, obj.lang);
+ } else {
+ object = store.literal(obj.value);
+ }
+ store.add( subject, predicate, object, why );
+ } else {
+ throw "error: unexpected termtype: "+z.type;
+ }
+ }
+ }
+ }
+ }
+ }
+}();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/match.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,129 @@
+// Matching a statement against a formula
+//
+//
+// W3C open source licence 2005.
+//
+// We retpresent a set as an associative array whose value for
+// each member is set to true.
+
+
+$rdf.Symbol.prototype.sameTerm = function(other) {
+ if (!other) { return false }
+ return ((this.termType == other.termType) && (this.uri == other.uri))
+}
+
+$rdf.BlankNode.prototype.sameTerm = function(other) {
+ if (!other) { return false }
+ return ((this.termType == other.termType) && (this.id == other.id))
+}
+
+$rdf.Literal.prototype.sameTerm = function(other) {
+ if (!other) { return false }
+ return ((this.termType == other.termType)
+ && (this.value == other.value)
+ && (this.lang == other.lang) &&
+ ((!this.datatype && !other.datatype)
+ || (this.datatype && this.datatype.sameTerm(other.datatype))))
+}
+
+$rdf.Variable.prototype.sameTerm = function (other) {
+ if (!other) { return false }
+ return((this.termType == other.termType) && (this.uri == other.uri))
+}
+
+$rdf.Collection.prototype.sameTerm = $rdf.BlankNode.prototype.sameTerm
+
+$rdf.Formula.prototype.sameTerm = function (other) {
+ return this.hashString() == other.hashString();
+}
+// Comparison for ordering
+//
+// These compare with ANY term
+//
+//
+// When we smush nodes we take the lowest value. This is not
+// arbitrary: we want the value actually used to be the literal
+// (or list or formula).
+
+$rdf.Literal.prototype.classOrder = 1
+$rdf.Collection.prototype.classOrder = 3
+$rdf.Formula.prototype.classOrder = 4
+$rdf.Symbol.prototype.classOrder = 5
+$rdf.BlankNode.prototype.classOrder = 6
+
+// Compaisons return sign(self - other)
+// Literals must come out before terms for smushing
+
+$rdf.Literal.prototype.compareTerm = function(other) {
+ if (this.classOrder < other.classOrder) return -1
+ if (this.classOrder > other.classOrder) return +1
+ if (this.value < other.value) return -1
+ if (this.value > other.value) return +1
+ return 0
+}
+
+$rdf.Symbol.prototype.compareTerm = function(other) {
+ if (this.classOrder < other.classOrder) return -1
+ if (this.classOrder > other.classOrder) return +1
+ if (this.uri < other.uri) return -1
+ if (this.uri > other.uri) return +1
+ return 0
+}
+
+$rdf.BlankNode.prototype.compareTerm = function(other) {
+ if (this.classOrder < other.classOrder) return -1
+ if (this.classOrder > other.classOrder) return +1
+ if (this.id < other.id) return -1
+ if (this.id > other.id) return +1
+ return 0
+}
+
+$rdf.Collection.prototype.compareTerm = $rdf.BlankNode.prototype.compareTerm
+
+// Convenience routines
+
+// Only one of s p o can be undefined, and w is optional.
+$rdf.Formula.prototype.each = function(s,p,o,w) {
+ var results = []
+ var st, sts = this.statementsMatching(s,p,o,w,false)
+ var i, n=sts.length
+ if (typeof s == 'undefined') {
+ for (i=0; i<n; i++) {st=sts[i]; results.push(st.subject)}
+ } else if (typeof p == 'undefined') {
+ for (i=0; i<n; i++) {st=sts[i]; results.push(st.predicate)}
+ } else if (typeof o == 'undefined') {
+ for (i=0; i<n; i++) {st=sts[i]; results.push(st.object)}
+ } else if (typeof w == 'undefined') {
+ for (i=0; i<n; i++) {st=sts[i]; results.push(st.why)}
+ }
+ return results
+}
+
+$rdf.Formula.prototype.any = function(s,p,o,w) {
+ var st = this.anyStatementMatching(s,p,o,w)
+ if (typeof st == 'undefined') return undefined;
+
+ if (typeof s == 'undefined') return st.subject;
+ if (typeof p == 'undefined') return st.predicate;
+ if (typeof o == 'undefined') return st.object;
+
+ return undefined
+}
+
+$rdf.Formula.prototype.holds = function(s,p,o,w) {
+ var st = this.anyStatementMatching(s,p,o,w)
+ if (typeof st == 'undefined') return false;
+ return true;
+}
+
+$rdf.Formula.prototype.the = function(s,p,o,w) {
+ // the() should contain a check there is only one
+ var x = this.any(s,p,o,w)
+ if (typeof x == 'undefined')
+ $rdf.log.error("No value found for the(){" + s + " " + p + " " + o + "}.")
+ return x
+}
+
+$rdf.Formula.prototype.whether = function(s,p,o,w) {
+ return this.statementsMatching(s,p,o,w,false).length;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/n3parser.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,1529 @@
+/**
+*
+* UTF-8 data encode / decode
+* http://www.webtoolkit.info/
+*
+**/
+
+$rdf.N3Parser = function () {
+
+function hexify(str) { // also used in parser
+ return encodeURI(str);
+}
+
+var Utf8 = {
+
+ // public method for url encoding
+ encode : function (string) {
+ string = string.replace(/\r\n/g,"\n");
+ var utftext = "";
+
+ for (var n = 0; n < string.length; n++) {
+
+ var c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+
+ }
+
+ return utftext;
+ },
+
+ // public method for url decoding
+ decode : function (utftext) {
+ var string = "";
+ var i = 0;
+
+ while ( i < utftext.length ) {
+
+ var c = utftext.charCodeAt(i);
+ if (c < 128) {
+ string += String.fromCharCode(c);
+ i++;
+ }
+ else if((c > 191) && (c < 224)) {
+ string += String.fromCharCode(((c & 31) << 6)
+ | (utftext.charCodeAt(i+1) & 63));
+ i += 2;
+ }
+ else {
+ string += String.fromCharCode(((c & 15) << 12)
+ | ((utftext.charCodeAt(i+1) & 63) << 6)
+ | (utftext.charCodeAt(i+2) & 63));
+ i += 3;
+ }
+ }
+ return string;
+ }
+
+}// Things we need to define to make converted pythn code work in js
+// environment of $rdf
+
+var RDFSink_forSomeSym = "http://www.w3.org/2000/10/swap/log#forSome";
+var RDFSink_forAllSym = "http://www.w3.org/2000/10/swap/log#forAll";
+var Logic_NS = "http://www.w3.org/2000/10/swap/log#";
+
+// pyjs seems to reference runtime library which I didn't find
+
+var pyjslib_Tuple = function(theList) { return theList };
+
+var pyjslib_List = function(theList) { return theList };
+
+var pyjslib_Dict = function(listOfPairs) {
+ if (listOfPairs.length > 0)
+ throw "missing.js: oops nnonempty dict not imp";
+ return [];
+}
+
+var pyjslib_len = function(s) { return s.length }
+
+var pyjslib_slice = function(str, i, j) {
+ if (typeof str.slice == 'undefined')
+ throw '@@ mising.js: No .slice function for '+str+' of type '+(typeof str)
+ if ((typeof j == 'undefined') || (j ==null)) return str.slice(i);
+ return str.slice(i, j) // @ exactly the same spec?
+}
+var StopIteration = Error('dummy error stop iteration');
+
+var pyjslib_Iterator = function(theList) {
+ this.last = 0;
+ this.li = theList;
+ this.next = function() {
+ if (this.last == this.li.length) throw StopIteration;
+ return this.li[this.last++];
+ }
+ return this;
+};
+
+var ord = function(str) {
+ return str.charCodeAt(0)
+}
+
+var string_find = function(str, s) {
+ return str.indexOf(s)
+}
+
+var assertFudge = function(condition, desc) {
+ if (condition) return;
+ if (desc) throw "python Assertion failed: "+desc;
+ throw "(python) Assertion failed.";
+}
+
+
+var stringFromCharCode = function(uesc) {
+ return String.fromCharCode(uesc);
+}
+
+
+String.prototype.encode = function(encoding) {
+ if (encoding != 'utf-8') throw "UTF8_converter: can only do utf-8"
+ return Utf8.encode(this);
+}
+String.prototype.decode = function(encoding) {
+ if (encoding != 'utf-8') throw "UTF8_converter: can only do utf-8"
+ //return Utf8.decode(this);
+ return this;
+}
+
+
+
+var uripath_join = function(base, given) {
+ return $rdf.Util.uri.join(given, base) // sad but true
+}
+
+var becauseSubexpression = null; // No reason needed
+var diag_tracking = 0;
+var diag_chatty_flag = 0;
+var diag_progress = function(str) { /*$rdf.log.debug(str);*/ }
+
+// why_BecauseOfData = function(doc, reason) { return doc };
+
+
+var RDF_type_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
+var DAML_sameAs_URI = "http://www.w3.org/2002/07/owl#sameAs";
+
+/*
+function SyntaxError(details) {
+ return new __SyntaxError(details);
+}
+*/
+
+function __SyntaxError(details) {
+ this.details = details
+}
+
+/*
+
+$Id: n3parser.js 14561 2008-02-23 06:37:26Z kennyluck $
+
+HAND EDITED FOR CONVERSION TO JAVASCRIPT
+
+This module implements a Nptation3 parser, and the final
+part of a notation3 serializer.
+
+See also:
+
+Notation 3
+http://www.w3.org/DesignIssues/Notation3
+
+Closed World Machine - and RDF Processor
+http://www.w3.org/2000/10/swap/cwm
+
+To DO: See also "@@" in comments
+
+- Clean up interfaces
+______________________________________________
+
+Module originally by Dan Connolly, includeing notation3
+parser and RDF generator. TimBL added RDF stream model
+and N3 generation, replaced stream model with use
+of common store/formula API. Yosi Scharf developped
+the module, including tests and test harness.
+
+*/
+
+var ADDED_HASH = "#";
+var LOG_implies_URI = "http://www.w3.org/2000/10/swap/log#implies";
+var INTEGER_DATATYPE = "http://www.w3.org/2001/XMLSchema#integer";
+var FLOAT_DATATYPE = "http://www.w3.org/2001/XMLSchema#double";
+var DECIMAL_DATATYPE = "http://www.w3.org/2001/XMLSchema#decimal";
+var BOOLEAN_DATATYPE = "http://www.w3.org/2001/XMLSchema#boolean";
+var option_noregen = 0;
+var _notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~";
+var _notNameChars = ( _notQNameChars + ":" ) ;
+var _rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+var N3CommentCharacter = "#";
+var eol = new RegExp("^[ \\t]*(#[^\\n]*)?\\r?\\n", 'g');
+var eof = new RegExp("^[ \\t]*(#[^\\n]*)?$", 'g');
+var ws = new RegExp("^[ \\t]*", 'g');
+var signed_integer = new RegExp("^[-+]?[0-9]+", 'g');
+var number_syntax = new RegExp("^([-+]?[0-9]+)(\\.[0-9]+)?(e[-+]?[0-9]+)?", 'g');
+var digitstring = new RegExp("^[0-9]+", 'g');
+var interesting = new RegExp("[\\\\\\r\\n\\\"]", 'g');
+var langcode = new RegExp("^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?", 'g');
+function SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) {
+ return new __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why);
+}
+function __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) {
+ if (typeof openFormula == 'undefined') openFormula=null;
+ if (typeof thisDoc == 'undefined') thisDoc="";
+ if (typeof baseURI == 'undefined') baseURI=null;
+ if (typeof genPrefix == 'undefined') genPrefix="";
+ if (typeof metaURI == 'undefined') metaURI=null;
+ if (typeof flags == 'undefined') flags="";
+ if (typeof why == 'undefined') why=null;
+ /*
+ note: namespace names should *not* end in #;
+ the # will get added during qname processing */
+
+ this._bindings = new pyjslib_Dict([]);
+ this._flags = flags;
+ if ((thisDoc != "")) {
+ assertFudge((thisDoc.indexOf(":") >= 0), ( "Document URI not absolute: " + thisDoc ) );
+ this._bindings[""] = ( ( thisDoc + "#" ) );
+ }
+ this._store = store;
+ if (genPrefix) {
+ store.setGenPrefix(genPrefix);
+ }
+ this._thisDoc = thisDoc;
+ this.source = store.sym(thisDoc);
+ this.lines = 0;
+ this.statementCount = 0;
+ this.startOfLine = 0;
+ this.previousLine = 0;
+ this._genPrefix = genPrefix;
+ this.keywords = new pyjslib_List(["a", "this", "bind", "has", "is", "of", "true", "false"]);
+ this.keywordsSet = 0;
+ this._anonymousNodes = new pyjslib_Dict([]);
+ this._variables = new pyjslib_Dict([]);
+ this._parentVariables = new pyjslib_Dict([]);
+ this._reason = why;
+ this._reason2 = null;
+ if (diag_tracking) {
+ this._reason2 = why_BecauseOfData(store.sym(thisDoc), this._reason);
+ }
+ if (baseURI) {
+ this._baseURI = baseURI;
+ }
+ else {
+ if (thisDoc) {
+ this._baseURI = thisDoc;
+ }
+ else {
+ this._baseURI = null;
+ }
+ }
+ assertFudge(!(this._baseURI) || (this._baseURI.indexOf(":") >= 0));
+ if (!(this._genPrefix)) {
+ if (this._thisDoc) {
+ this._genPrefix = ( this._thisDoc + "#_g" ) ;
+ }
+ else {
+ this._genPrefix = RDFSink_uniqueURI();
+ }
+ }
+ if ((openFormula == null)) {
+ if (this._thisDoc) {
+ this._formula = store.formula( ( thisDoc + "#_formula" ) );
+ }
+ else {
+ this._formula = store.formula();
+ }
+ }
+ else {
+ this._formula = openFormula;
+ }
+ this._context = this._formula;
+ this._parentContext = null;
+}
+__SinkParser.prototype.here = function(i) {
+ return ( ( ( ( this._genPrefix + "_L" ) + this.lines ) + "C" ) + ( ( i - this.startOfLine ) + 1 ) ) ;
+};
+__SinkParser.prototype.formula = function() {
+ return this._formula;
+};
+__SinkParser.prototype.loadStream = function(stream) {
+ return this.loadBuf(stream.read());
+};
+__SinkParser.prototype.loadBuf = function(buf) {
+ /*
+ Parses a buffer and returns its top level formula*/
+
+ this.startDoc();
+ this.feed(buf);
+ return this.endDoc();
+};
+__SinkParser.prototype.feed = function(octets) {
+ /*
+ Feed an octet stream tothe parser
+
+ if BadSyntax is raised, the string
+ passed in the exception object is the
+ remainder after any statements have been parsed.
+ So if there is more data to feed to the
+ parser, it should be straightforward to recover.*/
+
+ var str = octets.decode("utf-8");
+ var i = 0;
+ while ((i >= 0)) {
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return;
+ }
+ var i = this.directiveOrStatement(str, j);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "expected directive or statement");
+ }
+ }
+};
+__SinkParser.prototype.directiveOrStatement = function(str, h) {
+ var i = this.skipSpace(str, h);
+ if ((i < 0)) {
+ return i;
+ }
+ var j = this.directive(str, i);
+ if ((j >= 0)) {
+ return this.checkDot(str, j);
+ }
+ var j = this.statement(str, i);
+ if ((j >= 0)) {
+ return this.checkDot(str, j);
+ }
+ return j;
+};
+__SinkParser.prototype.tok = function(tok, str, i) {
+ /*
+ Check for keyword. Space must have been stripped on entry and
+ we must not be at end of file.*/
+ var whitespace = "\t\n\v\f\r ";
+ if ((pyjslib_slice(str, i, ( i + 1 ) ) == "@")) {
+ var i = ( i + 1 ) ;
+ }
+ else {
+ if (($rdf.Util.ArrayIndexOf(this.keywords,tok) < 0)) {
+ return -1;
+ }
+ }
+ var k = ( i + pyjslib_len(tok) ) ;
+ if ((pyjslib_slice(str, i, k) == tok) && (_notQNameChars.indexOf(str.charAt(k)) >= 0)) {
+ return k;
+ }
+ else {
+ return -1;
+ }
+};
+__SinkParser.prototype.directive = function(str, i) {
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return j;
+ }
+ var res = new pyjslib_List([]);
+ var j = this.tok("bind", str, i);
+ if ((j > 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "keyword bind is obsolete: use @prefix");
+ }
+ var j = this.tok("keywords", str, i);
+ if ((j > 0)) {
+ var i = this.commaSeparatedList(str, j, res, false);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "'@keywords' needs comma separated list of words");
+ }
+ this.setKeywords(pyjslib_slice(res, null, null));
+ if ((diag_chatty_flag > 80)) {
+ diag_progress("Keywords ", this.keywords);
+ }
+ return i;
+ }
+ var j = this.tok("forAll", str, i);
+ if ((j > 0)) {
+ var i = this.commaSeparatedList(str, j, res, true);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forAll");
+ }
+
+ var __x = new pyjslib_Iterator(res);
+ try {
+ while (true) {
+ var x = __x.next();
+
+
+ if ($rdf.Util.ArrayIndexOf(this._variables,x) < 0 || ($rdf.Util.ArrayIndexOf(this._parentVariables,x) >= 0)) {
+ this._variables[x] = ( this._context.newUniversal(x));
+ }
+
+ }
+ } catch (e) {
+ if (e != StopIteration) {
+ throw e;
+ }
+ }
+
+ return i;
+ }
+ var j = this.tok("forSome", str, i);
+ if ((j > 0)) {
+ var i = this.commaSeparatedList(str, j, res, this.uri_ref2);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forSome");
+ }
+
+ var __x = new pyjslib_Iterator(res);
+ try {
+ while (true) {
+ var x = __x.next();
+
+
+ this._context.declareExistential(x);
+
+ }
+ } catch (e) {
+ if (e != StopIteration) {
+ throw e;
+ }
+ }
+
+ return i;
+ }
+ var j = this.tok("prefix", str, i);
+ if ((j >= 0)) {
+ var t = new pyjslib_List([]);
+ var i = this.qname(str, j, t);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "expected qname after @prefix");
+ }
+ var j = this.uri_ref2(str, i, t);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "expected <uriref> after @prefix _qname_");
+ }
+ var ns = t[1].uri;
+ if (this._baseURI) {
+ var ns = uripath_join(this._baseURI, ns);
+ }
+ else {
+ assertFudge((ns.indexOf(":") >= 0), "With no base URI, cannot handle relative URI for NS");
+ }
+ assertFudge((ns.indexOf(":") >= 0));
+ this._bindings[t[0][0]] = ( ns);
+
+ this.bind(t[0][0], hexify(ns));
+ return j;
+ }
+ var j = this.tok("base", str, i);
+ if ((j >= 0)) {
+ var t = new pyjslib_List([]);
+ var i = this.uri_ref2(str, j, t);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "expected <uri> after @base ");
+ }
+ var ns = t[0].uri;
+ if (this._baseURI) {
+ var ns = uripath_join(this._baseURI, ns);
+ }
+ else {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, ( ( "With no previous base URI, cannot use relative URI in @base <" + ns ) + ">" ) );
+ }
+ assertFudge((ns.indexOf(":") >= 0));
+ this._baseURI = ns;
+ return i;
+ }
+ return -1;
+};
+__SinkParser.prototype.bind = function(qn, uri) {
+ if ((qn == "")) {
+ }
+ else {
+ this._store.setPrefixForURI(qn, uri);
+ }
+};
+__SinkParser.prototype.setKeywords = function(k) {
+ /*
+ Takes a list of strings*/
+
+ if ((k == null)) {
+ this.keywordsSet = 0;
+ }
+ else {
+ this.keywords = k;
+ this.keywordsSet = 1;
+ }
+};
+__SinkParser.prototype.startDoc = function() {
+};
+__SinkParser.prototype.endDoc = function() {
+ /*
+ Signal end of document and stop parsing. returns formula*/
+
+ return this._formula;
+};
+__SinkParser.prototype.makeStatement = function(quad) {
+ quad[0].add(quad[2], quad[1], quad[3], this.source);
+ this.statementCount += 1;
+};
+__SinkParser.prototype.statement = function(str, i) {
+ var r = new pyjslib_List([]);
+ var i = this.object(str, i, r);
+ if ((i < 0)) {
+ return i;
+ }
+ var j = this.property_list(str, i, r[0]);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "expected propertylist");
+ }
+ return j;
+};
+__SinkParser.prototype.subject = function(str, i, res) {
+ return this.item(str, i, res);
+};
+__SinkParser.prototype.verb = function(str, i, res) {
+ /*
+ has _prop_
+ is _prop_ of
+ a
+ =
+ _prop_
+ >- prop ->
+ <- prop -<
+ _operator_*/
+
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return j;
+ }
+ var r = new pyjslib_List([]);
+ var j = this.tok("has", str, i);
+ if ((j >= 0)) {
+ var i = this.prop(str, j, r);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "expected property after 'has'");
+ }
+ res.push(new pyjslib_Tuple(["->", r[0]]));
+ return i;
+ }
+ var j = this.tok("is", str, i);
+ if ((j >= 0)) {
+ var i = this.prop(str, j, r);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "expected <property> after 'is'");
+ }
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "End of file found, expected property after 'is'");
+ return j;
+ }
+ var i = j;
+ var j = this.tok("of", str, i);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "expected 'of' after 'is' <prop>");
+ }
+ res.push(new pyjslib_Tuple(["<-", r[0]]));
+ return j;
+ }
+ var j = this.tok("a", str, i);
+ if ((j >= 0)) {
+ res.push(new pyjslib_Tuple(["->", this._store.sym(RDF_type_URI)]));
+ return j;
+ }
+ if ((pyjslib_slice(str, i, ( i + 2 ) ) == "<=")) {
+ res.push(new pyjslib_Tuple(["<-", this._store.sym( ( Logic_NS + "implies" ) )]));
+ return ( i + 2 ) ;
+ }
+ if ((pyjslib_slice(str, i, ( i + 1 ) ) == "=")) {
+ if ((pyjslib_slice(str, ( i + 1 ) , ( i + 2 ) ) == ">")) {
+ res.push(new pyjslib_Tuple(["->", this._store.sym( ( Logic_NS + "implies" ) )]));
+ return ( i + 2 ) ;
+ }
+ res.push(new pyjslib_Tuple(["->", this._store.sym(DAML_sameAs_URI)]));
+ return ( i + 1 ) ;
+ }
+ if ((pyjslib_slice(str, i, ( i + 2 ) ) == ":=")) {
+ res.push(new pyjslib_Tuple(["->", ( Logic_NS + "becomes" ) ]));
+ return ( i + 2 ) ;
+ }
+ var j = this.prop(str, i, r);
+ if ((j >= 0)) {
+ res.push(new pyjslib_Tuple(["->", r[0]]));
+ return j;
+ }
+ if ((pyjslib_slice(str, i, ( i + 2 ) ) == ">-") || (pyjslib_slice(str, i, ( i + 2 ) ) == "<-")) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, ">- ... -> syntax is obsolete.");
+ }
+ return -1;
+};
+__SinkParser.prototype.prop = function(str, i, res) {
+ return this.item(str, i, res);
+};
+__SinkParser.prototype.item = function(str, i, res) {
+ return this.path(str, i, res);
+};
+__SinkParser.prototype.blankNode = function(uri) {
+ return this._context.bnode(uri, this._reason2);
+};
+__SinkParser.prototype.path = function(str, i, res) {
+ /*
+ Parse the path production.
+ */
+
+ var j = this.nodeOrLiteral(str, i, res);
+ if ((j < 0)) {
+ return j;
+ }
+ while (("!^.".indexOf(pyjslib_slice(str, j, ( j + 1 ) )) >= 0)) {
+ var ch = pyjslib_slice(str, j, ( j + 1 ) );
+ if ((ch == ".")) {
+ var ahead = pyjslib_slice(str, ( j + 1 ) , ( j + 2 ) );
+ if (!(ahead) || (_notNameChars.indexOf(ahead) >= 0) && (":?<[{(".indexOf(ahead) < 0)) {
+ break;
+ }
+ }
+ var subj = res.pop();
+ var obj = this.blankNode(this.here(j));
+ var j = this.node(str, ( j + 1 ) , res);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in middle of path syntax");
+ }
+ var pred = res.pop();
+ if ((ch == "^")) {
+ this.makeStatement(new pyjslib_Tuple([this._context, pred, obj, subj]));
+ }
+ else {
+ this.makeStatement(new pyjslib_Tuple([this._context, pred, subj, obj]));
+ }
+ res.push(obj);
+ }
+ return j;
+};
+__SinkParser.prototype.anonymousNode = function(ln) {
+ /*
+ Remember or generate a term for one of these _: anonymous nodes*/
+
+ var term = this._anonymousNodes[ln];
+ if (term) {
+ return term;
+ }
+ var term = this._store.bnode(this._context, this._reason2);
+ this._anonymousNodes[ln] = ( term);
+ return term;
+};
+__SinkParser.prototype.node = function(str, i, res, subjectAlready) {
+ if (typeof subjectAlready == 'undefined') subjectAlready=null;
+ /*
+ Parse the <node> production.
+ Space is now skipped once at the beginning
+ instead of in multipe calls to self.skipSpace().
+ */
+
+ var subj = subjectAlready;
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return j;
+ }
+ var i = j;
+ var ch = pyjslib_slice(str, i, ( i + 1 ) );
+ if ((ch == "[")) {
+ var bnodeID = this.here(i);
+ var j = this.skipSpace(str, ( i + 1 ) );
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF after '['");
+ }
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) == "=")) {
+ var i = ( j + 1 ) ;
+ var objs = new pyjslib_List([]);
+ var j = this.objectList(str, i, objs);
+
+ if ((j >= 0)) {
+ var subj = objs[0];
+ if ((pyjslib_len(objs) > 1)) {
+
+ var __obj = new pyjslib_Iterator(objs);
+ try {
+ while (true) {
+ var obj = __obj.next();
+
+
+ this.makeStatement(new pyjslib_Tuple([this._context, this._store.sym(DAML_sameAs_URI), subj, obj]));
+
+ }
+ } catch (e) {
+ if (e != StopIteration) {
+ throw e;
+ }
+ }
+
+ }
+ var j = this.skipSpace(str, j);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when objectList expected after [ = ");
+ }
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) == ";")) {
+ var j = ( j + 1 ) ;
+ }
+ }
+ else {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "objectList expected after [= ");
+ }
+ }
+ if ((subj == null)) {
+ var subj = this.blankNode(bnodeID);
+ }
+ var i = this.property_list(str, j, subj);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "property_list expected");
+ }
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when ']' expected after [ <propertyList>");
+ }
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) != "]")) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "']' expected");
+ }
+ res.push(subj);
+ return ( j + 1 ) ;
+ }
+ if ((ch == "{")) {
+ var ch2 = pyjslib_slice(str, ( i + 1 ) , ( i + 2 ) );
+ if ((ch2 == "$")) {
+ i += 1;
+ var j = ( i + 1 ) ;
+ var mylist = new pyjslib_List([]);
+ var first_run = true;
+ while (1) {
+ var i = this.skipSpace(str, j);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '$}', found end.");
+ }
+ if ((pyjslib_slice(str, i, ( i + 2 ) ) == "$}")) {
+ var j = ( i + 2 ) ;
+ break;
+ }
+ if (!(first_run)) {
+ if ((pyjslib_slice(str, i, ( i + 1 ) ) == ",")) {
+ i += 1;
+ }
+ else {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "expected: ','");
+ }
+ }
+ else {
+ var first_run = false;
+ }
+ var item = new pyjslib_List([]);
+ var j = this.item(str, i, item);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in set or '$}'");
+ }
+ mylist.push(item[0]);
+ }
+ res.push(this._store.newSet(mylist, this._context));
+ return j;
+ }
+ else {
+ var j = ( i + 1 ) ;
+ var oldParentContext = this._parentContext;
+ this._parentContext = this._context;
+ var parentAnonymousNodes = this._anonymousNodes;
+ var grandParentVariables = this._parentVariables;
+ this._parentVariables = this._variables;
+ this._anonymousNodes = new pyjslib_Dict([]);
+ this._variables = this._variables.slice();
+ var reason2 = this._reason2;
+ this._reason2 = becauseSubexpression;
+ if ((subj == null)) {
+ var subj = this._store.formula();
+ }
+ this._context = subj;
+ while (1) {
+ var i = this.skipSpace(str, j);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '}', found end.");
+ }
+ if ((pyjslib_slice(str, i, ( i + 1 ) ) == "}")) {
+ var j = ( i + 1 ) ;
+ break;
+ }
+ var j = this.directiveOrStatement(str, i);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "expected statement or '}'");
+ }
+ }
+ this._anonymousNodes = parentAnonymousNodes;
+ this._variables = this._parentVariables;
+ this._parentVariables = grandParentVariables;
+ this._context = this._parentContext;
+ this._reason2 = reason2;
+ this._parentContext = oldParentContext;
+ res.push(subj.close());
+ return j;
+ }
+ }
+ if ((ch == "(")) {
+ var thing_type = this._store.list;
+ var ch2 = pyjslib_slice(str, ( i + 1 ) , ( i + 2 ) );
+ if ((ch2 == "$")) {
+ var thing_type = this._store.newSet;
+ i += 1;
+ }
+ var j = ( i + 1 ) ;
+ var mylist = new pyjslib_List([]);
+ while (1) {
+ var i = this.skipSpace(str, j);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "needed ')', found end.");
+ }
+ if ((pyjslib_slice(str, i, ( i + 1 ) ) == ")")) {
+ var j = ( i + 1 ) ;
+ break;
+ }
+ var item = new pyjslib_List([]);
+ var j = this.item(str, i, item);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in list or ')'");
+ }
+ mylist.push(item[0]);
+ }
+ res.push(thing_type(mylist, this._context));
+ return j;
+ }
+ var j = this.tok("this", str, i);
+ if ((j >= 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "Keyword 'this' was ancient N3. Now use @forSome and @forAll keywords.");
+ res.push(this._context);
+ return j;
+ }
+ var j = this.tok("true", str, i);
+ if ((j >= 0)) {
+ res.push(true);
+ return j;
+ }
+ var j = this.tok("false", str, i);
+ if ((j >= 0)) {
+ res.push(false);
+ return j;
+ }
+ if ((subj == null)) {
+ var j = this.uri_ref2(str, i, res);
+ if ((j >= 0)) {
+ return j;
+ }
+ }
+ return -1;
+};
+__SinkParser.prototype.property_list = function(str, i, subj) {
+ /*
+ Parse property list
+ Leaves the terminating punctuation in the buffer
+ */
+
+ while (1) {
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found when expected verb in property list");
+ return j;
+ }
+ if ((pyjslib_slice(str, j, ( j + 2 ) ) == ":-")) {
+ var i = ( j + 2 ) ;
+ var res = new pyjslib_List([]);
+ var j = this.node(str, i, res, subj);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "bad {} or () or [] node after :- ");
+ }
+ var i = j;
+ continue;
+ }
+ var i = j;
+ var v = new pyjslib_List([]);
+ var j = this.verb(str, i, v);
+ if ((j <= 0)) {
+ return i;
+ }
+ var objs = new pyjslib_List([]);
+ var i = this.objectList(str, j, objs);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "objectList expected");
+ }
+
+ var __obj = new pyjslib_Iterator(objs);
+ try {
+ while (true) {
+ var obj = __obj.next();
+
+
+ var pairFudge = v[0];
+ var dir = pairFudge[0];
+ var sym = pairFudge[1];
+ if ((dir == "->")) {
+ this.makeStatement(new pyjslib_Tuple([this._context, sym, subj, obj]));
+ }
+ else {
+ this.makeStatement(new pyjslib_Tuple([this._context, sym, obj, subj]));
+ }
+
+ }
+ } catch (e) {
+ if (e != StopIteration) {
+ throw e;
+ }
+ }
+
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in list of objects");
+ return j;
+ }
+ if ((pyjslib_slice(str, i, ( i + 1 ) ) != ";")) {
+ return i;
+ }
+ var i = ( i + 1 ) ;
+ }
+};
+__SinkParser.prototype.commaSeparatedList = function(str, j, res, ofUris) {
+ /*
+ return value: -1 bad syntax; >1 new position in str
+ res has things found appended
+
+ Used to use a final value of the function to be called, e.g. this.bareWord
+ but passing the function didn't work fo js converion pyjs
+ */
+
+ var i = this.skipSpace(str, j);
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found expecting comma sep list");
+ return i;
+ }
+ if ((str.charAt(i) == ".")) {
+ return j;
+ }
+ if (ofUris) {
+ var i = this.uri_ref2(str, i, res);
+ }
+ else {
+ var i = this.bareWord(str, i, res);
+ }
+ if ((i < 0)) {
+ return -1;
+ }
+ while (1) {
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return j;
+ }
+ var ch = pyjslib_slice(str, j, ( j + 1 ) );
+ if ((ch != ",")) {
+ if ((ch != ".")) {
+ return -1;
+ }
+ return j;
+ }
+ if (ofUris) {
+ var i = this.uri_ref2(str, ( j + 1 ) , res);
+ }
+ else {
+ var i = this.bareWord(str, ( j + 1 ) , res);
+ }
+ if ((i < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "bad list content");
+ return i;
+ }
+ }
+};
+__SinkParser.prototype.objectList = function(str, i, res) {
+ var i = this.object(str, i, res);
+ if ((i < 0)) {
+ return -1;
+ }
+ while (1) {
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found after object");
+ return j;
+ }
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) != ",")) {
+ return j;
+ }
+ var i = this.object(str, ( j + 1 ) , res);
+ if ((i < 0)) {
+ return i;
+ }
+ }
+};
+__SinkParser.prototype.checkDot = function(str, i) {
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return j;
+ }
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) == ".")) {
+ return ( j + 1 ) ;
+ }
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) == "}")) {
+ return j;
+ }
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) == "]")) {
+ return j;
+ }
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "expected '.' or '}' or ']' at end of statement");
+ return i;
+};
+__SinkParser.prototype.uri_ref2 = function(str, i, res) {
+ /*
+ Generate uri from n3 representation.
+
+ Note that the RDF convention of directly concatenating
+ NS and local name is now used though I prefer inserting a '#'
+ to make the namesapces look more like what XML folks expect.
+ */
+
+ var qn = new pyjslib_List([]);
+ var j = this.qname(str, i, qn);
+ if ((j >= 0)) {
+ var pairFudge = qn[0];
+ var pfx = pairFudge[0];
+ var ln = pairFudge[1];
+ if ((pfx == null)) {
+ assertFudge(0, "not used?");
+ var ns = ( this._baseURI + ADDED_HASH ) ;
+ }
+ else {
+ var ns = this._bindings[pfx];
+ if (!(ns)) {
+ if ((pfx == "_")) {
+ res.push(this.anonymousNode(ln));
+ return j;
+ }
+ throw BadSyntax(this._thisDoc, this.lines, str, i, ( ( "Prefix " + pfx ) + " not bound." ) );
+ }
+ }
+ var symb = this._store.sym( ( ns + ln ) );
+ if (($rdf.Util.ArrayIndexOf(this._variables, symb) >= 0)) {
+ res.push(this._variables[symb]);
+ }
+ else {
+ res.push(symb);
+ }
+ return j;
+ }
+ var i = this.skipSpace(str, i);
+ if ((i < 0)) {
+ return -1;
+ }
+ if ((str.charAt(i) == "?")) {
+ var v = new pyjslib_List([]);
+ var j = this.variable(str, i, v);
+ if ((j > 0)) {
+ res.push(v[0]);
+ return j;
+ }
+ return -1;
+ }
+ else if ((str.charAt(i) == "<")) {
+ var i = ( i + 1 ) ;
+ var st = i;
+ while ((i < pyjslib_len(str))) {
+ if ((str.charAt(i) == ">")) {
+ var uref = pyjslib_slice(str, st, i);
+ if (this._baseURI) {
+ var uref = uripath_join(this._baseURI, uref);
+ }
+ else {
+ assertFudge((uref.indexOf(":") >= 0), "With no base URI, cannot deal with relative URIs");
+ }
+ if ((pyjslib_slice(str, ( i - 1 ) , i) == "#") && !((pyjslib_slice(uref, -1, null) == "#"))) {
+ var uref = ( uref + "#" ) ;
+ }
+ var symb = this._store.sym(uref);
+ if (($rdf.Util.ArrayIndexOf(this._variables,symb) >= 0)) {
+ res.push(this._variables[symb]);
+ }
+ else {
+ res.push(symb);
+ }
+ return ( i + 1 ) ;
+ }
+ var i = ( i + 1 ) ;
+ }
+ throw BadSyntax(this._thisDoc, this.lines, str, j, "unterminated URI reference");
+ }
+ else if (this.keywordsSet) {
+ var v = new pyjslib_List([]);
+ var j = this.bareWord(str, i, v);
+ if ((j < 0)) {
+ return -1;
+ }
+ if (($rdf.Util.ArrayIndexOf(this.keywords, v[0]) >= 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, ( ( "Keyword \"" + v[0] ) + "\" not allowed here." ) );
+ }
+ res.push(this._store.sym( ( this._bindings[""] + v[0] ) ));
+ return j;
+ }
+ else {
+ return -1;
+ }
+};
+__SinkParser.prototype.skipSpace = function(str, i) {
+ /*
+ Skip white space, newlines and comments.
+ return -1 if EOF, else position of first non-ws character*/
+ var tmp = str;
+ var whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000';
+ for (var j = (i ? i : 0); j < str.length; j++) {
+ if (whitespace.indexOf(str.charAt(j)) === -1) {
+ if( str.charAt(j)==='#' ) {
+ str = str.slice(i).replace(/^[^\n]*\n/,"");
+ i=0;
+ j=-1;
+ } else {
+ break;
+ }
+ }
+ }
+ val = (tmp.length - str.length) + j;
+ if( val === tmp.length ) {
+ return -1;
+ }
+ return val;
+};
+__SinkParser.prototype.variable = function(str, i, res) {
+ /*
+ ?abc -> variable(:abc)
+ */
+
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return -1;
+ }
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) != "?")) {
+ return -1;
+ }
+ var j = ( j + 1 ) ;
+ var i = j;
+ if (("0123456789-".indexOf(str.charAt(j)) >= 0)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, ( ( "Varible name can't start with '" + str.charAt(j) ) + "s'" ) );
+ return -1;
+ }
+ while ((i < pyjslib_len(str)) && (_notNameChars.indexOf(str.charAt(i)) < 0)) {
+ var i = ( i + 1 ) ;
+ }
+ if ((this._parentContext == null)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, j, ( "Can't use ?xxx syntax for variable in outermost level: " + pyjslib_slice(str, ( j - 1 ) , i) ) );
+ }
+ res.push(this._store.variable(pyjslib_slice(str, j, i)));
+ return i;
+};
+__SinkParser.prototype.bareWord = function(str, i, res) {
+ /*
+ abc -> :abc
+ */
+
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return -1;
+ }
+ var ch = str.charAt(j);
+ if (("0123456789-".indexOf(ch) >= 0)) {
+ return -1;
+ }
+ if ((_notNameChars.indexOf(ch) >= 0)) {
+ return -1;
+ }
+ var i = j;
+ while ((i < pyjslib_len(str)) && (_notNameChars.indexOf(str.charAt(i)) < 0)) {
+ var i = ( i + 1 ) ;
+ }
+ res.push(pyjslib_slice(str, j, i));
+ return i;
+};
+__SinkParser.prototype.qname = function(str, i, res) {
+ /*
+
+ xyz:def -> ('xyz', 'def')
+ If not in keywords and keywordsSet: def -> ('', 'def')
+ :def -> ('', 'def')
+ */
+
+ var i = this.skipSpace(str, i);
+ if ((i < 0)) {
+ return -1;
+ }
+ var c = str.charAt(i);
+ if (("0123456789-+".indexOf(c) >= 0)) {
+ return -1;
+ }
+ if ((_notNameChars.indexOf(c) < 0)) {
+ var ln = c;
+ var i = ( i + 1 ) ;
+ while ((i < pyjslib_len(str))) {
+ var c = str.charAt(i);
+ if ((_notNameChars.indexOf(c) < 0)) {
+ var ln = ( ln + c ) ;
+ var i = ( i + 1 ) ;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ else {
+ var ln = "";
+ }
+ if ((i < pyjslib_len(str)) && (str.charAt(i) == ":")) {
+ var pfx = ln;
+ var i = ( i + 1 ) ;
+ var ln = "";
+ while ((i < pyjslib_len(str))) {
+ var c = str.charAt(i);
+ if ((_notNameChars.indexOf(c) < 0)) {
+ var ln = ( ln + c ) ;
+ var i = ( i + 1 ) ;
+ }
+ else {
+ break;
+ }
+ }
+ res.push(new pyjslib_Tuple([pfx, ln]));
+ return i;
+ }
+ else {
+ if (ln && this.keywordsSet && ($rdf.Util.ArrayIndexOf(this.keywords, ln) < 0)) {
+ res.push(new pyjslib_Tuple(["", ln]));
+ return i;
+ }
+ return -1;
+ }
+};
+__SinkParser.prototype.object = function(str, i, res) {
+ var j = this.subject(str, i, res);
+ if ((j >= 0)) {
+ return j;
+ }
+ else {
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return -1;
+ }
+ else {
+ var i = j;
+ }
+ if ((str.charAt(i) == "\"")) {
+ if ((pyjslib_slice(str, i, ( i + 3 ) ) == "\"\"\"")) {
+ var delim = "\"\"\"";
+ }
+ else {
+ var delim = "\"";
+ }
+ var i = ( i + pyjslib_len(delim) ) ;
+ var pairFudge = this.strconst(str, i, delim);
+ var j = pairFudge[0];
+ var s = pairFudge[1];
+ res.push(this._store.literal(s));
+ diag_progress("New string const ", s, j);
+ return j;
+ }
+ else {
+ return -1;
+ }
+ }
+};
+__SinkParser.prototype.nodeOrLiteral = function(str, i, res) {
+ var j = this.node(str, i, res);
+ if ((j >= 0)) {
+ return j;
+ }
+ else {
+ var j = this.skipSpace(str, i);
+ if ((j < 0)) {
+ return -1;
+ }
+ else {
+ var i = j;
+ }
+ var ch = str.charAt(i);
+ if (("-+0987654321".indexOf(ch) >= 0)) {
+ number_syntax.lastIndex = 0;
+ var m = number_syntax.exec(str.slice(i));
+ if ((m == null)) {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad number syntax");
+ }
+ var j = ( i + number_syntax.lastIndex ) ;
+ var val = pyjslib_slice(str, i, j);
+ if ((val.indexOf("e") >= 0)) {
+ res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(FLOAT_DATATYPE)));
+ }
+ else if ((pyjslib_slice(str, i, j).indexOf(".") >= 0)) {
+ res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(DECIMAL_DATATYPE)));
+ }
+ else {
+ res.push(this._store.literal(parseInt(val), undefined, this._store.sym(INTEGER_DATATYPE)));
+ }
+ return j;
+ }
+ if ((str.charAt(i) == "\"")) {
+ if ((pyjslib_slice(str, i, ( i + 3 ) ) == "\"\"\"")) {
+ var delim = "\"\"\"";
+ }
+ else {
+ var delim = "\"";
+ }
+ var i = ( i + pyjslib_len(delim) ) ;
+ var dt = null;
+ var pairFudge = this.strconst(str, i, delim);
+ var j = pairFudge[0];
+ var s = pairFudge[1];
+ var lang = null;
+ if ((pyjslib_slice(str, j, ( j + 1 ) ) == "@")) {
+ langcode.lastIndex = 0;
+
+ var m = langcode.exec(str.slice( ( j + 1 ) ));
+ if ((m == null)) {
+ throw BadSyntax(this._thisDoc, startline, str, i, "Bad language code syntax on string literal, after @");
+ }
+ var i = ( ( langcode.lastIndex + j ) + 1 ) ;
+
+ var lang = pyjslib_slice(str, ( j + 1 ) , i);
+ var j = i;
+ }
+ if ((pyjslib_slice(str, j, ( j + 2 ) ) == "^^")) {
+ var res2 = new pyjslib_List([]);
+ var j = this.uri_ref2(str, ( j + 2 ) , res2);
+ var dt = res2[0];
+ }
+ res.push(this._store.literal(s, lang, dt));
+ return j;
+ }
+ else {
+ return -1;
+ }
+ }
+};
+__SinkParser.prototype.strconst = function(str, i, delim) {
+ /*
+ parse an N3 string constant delimited by delim.
+ return index, val
+ */
+
+ var j = i;
+ var ustr = "";
+ var startline = this.lines;
+ while ((j < pyjslib_len(str))) {
+ var i = ( j + pyjslib_len(delim) ) ;
+ if ((pyjslib_slice(str, j, i) == delim)) {
+ return new pyjslib_Tuple([i, ustr]);
+ }
+ if ((str.charAt(j) == "\"")) {
+ var ustr = ( ustr + "\"" ) ;
+ var j = ( j + 1 ) ;
+ continue;
+ }
+ interesting.lastIndex = 0;
+ var m = interesting.exec(str.slice(j));
+ if (!(m)) {
+ throw BadSyntax(this._thisDoc, startline, str, j, ( ( ( "Closing quote missing in string at ^ in " + pyjslib_slice(str, ( j - 20 ) , j) ) + "^" ) + pyjslib_slice(str, j, ( j + 20 ) ) ) );
+ }
+ var i = ( ( j + interesting.lastIndex ) - 1 ) ;
+ var ustr = ( ustr + pyjslib_slice(str, j, i) ) ;
+ var ch = str.charAt(i);
+ if ((ch == "\"")) {
+ var j = i;
+ continue;
+ }
+ else if ((ch == "\r")) {
+ var j = ( i + 1 ) ;
+ continue;
+ }
+ else if ((ch == "\n")) {
+ if ((delim == "\"")) {
+ throw BadSyntax(this._thisDoc, startline, str, i, "newline found in string literal");
+ }
+ this.lines = ( this.lines + 1 ) ;
+ var ustr = ( ustr + ch ) ;
+ var j = ( i + 1 ) ;
+ this.previousLine = this.startOfLine;
+ this.startOfLine = j;
+ }
+ else if ((ch == "\\")) {
+ var j = ( i + 1 ) ;
+ var ch = pyjslib_slice(str, j, ( j + 1 ) );
+ if (!(ch)) {
+ throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal (2)");
+ }
+ var k = string_find("abfrtvn\\\"", ch);
+ if ((k >= 0)) {
+ var uch = "\a\b\f\r\t\v\n\\\"".charAt(k);
+ var ustr = ( ustr + uch ) ;
+ var j = ( j + 1 ) ;
+ }
+ else if ((ch == "u")) {
+ var pairFudge = this.uEscape(str, ( j + 1 ) , startline);
+ var j = pairFudge[0];
+ var ch = pairFudge[1];
+ var ustr = ( ustr + ch ) ;
+ }
+ else if ((ch == "U")) {
+ var pairFudge = this.UEscape(str, ( j + 1 ) , startline);
+ var j = pairFudge[0];
+ var ch = pairFudge[1];
+ var ustr = ( ustr + ch ) ;
+ }
+ else {
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "bad escape");
+ }
+ }
+ }
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "unterminated string literal");
+};
+__SinkParser.prototype.uEscape = function(str, i, startline) {
+ var j = i;
+ var count = 0;
+ var value = 0;
+ while ((count < 4)) {
+ var chFudge = pyjslib_slice(str, j, ( j + 1 ) );
+ var ch = chFudge.toLowerCase();
+ var j = ( j + 1 ) ;
+ if ((ch == "")) {
+ throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)");
+ }
+ var k = string_find("0123456789abcdef", ch);
+ if ((k < 0)) {
+ throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape");
+ }
+ var value = ( ( value * 16 ) + k ) ;
+ var count = ( count + 1 ) ;
+ }
+ var uch = String.fromCharCode(value);
+ return new pyjslib_Tuple([j, uch]);
+};
+__SinkParser.prototype.UEscape = function(str, i, startline) {
+ var j = i;
+ var count = 0;
+ var value = "\\U";
+ while ((count < 8)) {
+ var chFudge = pyjslib_slice(str, j, ( j + 1 ) );
+ var ch = chFudge.toLowerCase();
+ var j = ( j + 1 ) ;
+ if ((ch == "")) {
+ throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)");
+ }
+ var k = string_find("0123456789abcdef", ch);
+ if ((k < 0)) {
+ throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape");
+ }
+ var value = ( value + ch ) ;
+ var count = ( count + 1 ) ;
+ }
+ var uch = stringFromCharCode( ( ( "0x" + pyjslib_slice(value, 2, 10) ) - 0 ) );
+ return new pyjslib_Tuple([j, uch]);
+};
+function OLD_BadSyntax(uri, lines, str, i, why) {
+ return new __OLD_BadSyntax(uri, lines, str, i, why);
+}
+function __OLD_BadSyntax(uri, lines, str, i, why) {
+ this._str = str.encode("utf-8");
+ this._str = str;
+ this._i = i;
+ this._why = why;
+ this.lines = lines;
+ this._uri = uri;
+}
+__OLD_BadSyntax.prototype.toString = function() {
+ var str = this._str;
+ var i = this._i;
+ var st = 0;
+ if ((i > 60)) {
+ var pre = "...";
+ var st = ( i - 60 ) ;
+ }
+ else {
+ var pre = "";
+ }
+ if (( ( pyjslib_len(str) - i ) > 60)) {
+ var post = "...";
+ }
+ else {
+ var post = "";
+ }
+ return "Line %i of <%s>: Bad syntax (%s) at ^ in:\n\"%s%s^%s%s\"" % new pyjslib_Tuple([ ( this.lines + 1 ) , this._uri, this._why, pre, pyjslib_slice(str, st, i), pyjslib_slice(str, i, ( i + 60 ) ), post]);
+};
+function BadSyntax(uri, lines, str, i, why) {
+ return ( ( ( ( ( ( ( ( "Line " + ( lines + 1 ) ) + " of <" ) + uri ) + ">: Bad syntax: " ) + why ) + "\nat: \"" ) + pyjslib_slice(str, i, ( i + 30 ) ) ) + "\"" ) ;
+}
+
+
+function stripCR(str) {
+ var res = "";
+
+ var __ch = new pyjslib_Iterator(str);
+ try {
+ while (true) {
+ var ch = __ch.next();
+
+
+ if ((ch != "\r")) {
+ var res = ( res + ch ) ;
+ }
+
+ }
+ } catch (e) {
+ if (e != StopIteration) {
+ throw e;
+ }
+ }
+
+ return res;
+}
+
+
+function dummyWrite(x) {
+}
+
+return SinkParser;
+
+}();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/query.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,563 @@
+// Matching a formula against another formula
+//
+//
+// W3C open source licence 2005.
+//
+// This builds on term.js, match.js (and identity.js?)
+// to allow a query of a formula.
+//
+// Here we introduce for the first time a subclass of term: variable.
+//
+// SVN ID: $Id: query.js 25116 2008-11-15 16:13:48Z timbl $
+
+// Variable
+//
+// Compare with BlankNode. They are similar, but a variable
+// stands for something whose value is to be returned.
+// Also, users name variables and want the same name back when stuff is printed
+
+/*jsl:option explicit*/ // Turn on JavaScriptLint variable declaration checking
+
+
+// The Query object. Should be very straightforward.
+//
+// This if for tracking queries the user has in the UI.
+//
+$rdf.Query = function (name, id) {
+ this.pat = new $rdf.IndexedFormula(); // The pattern to search for
+ this.vars = []; // Used by UI code but not in query.js
+// this.orderBy = []; // Not used yet
+ this.name = name;
+ this.id = id;
+}
+
+/**The QuerySource object stores a set of listeners and a set of queries.
+ * It keeps the listeners aware of those queries that the source currently
+ * contains, and it is then up to the listeners to decide what to do with
+ * those queries in terms of displays.
+ * Not used 2010-08 -- TimBL
+ * @constructor
+ * @author jambo
+ */
+$rdf.QuerySource = function() {
+ /**stores all of the queries currently held by this source, indexed by ID number.
+ */
+ this.queries=[];
+ /**stores the listeners for a query object.
+ * @see TabbedContainer
+ */
+ this.listeners=[];
+
+ /**add a Query object to the query source--It will be given an ID number
+ * and a name, if it doesn't already have one. This subsequently adds the
+ * query to all of the listeners the QuerySource knows about.
+ */
+ this.addQuery = function(q) {
+ var i;
+ if(q.name==null || q.name=="")
+ q.name="Query #"+(this.queries.length+1);
+ q.id=this.queries.length;
+ this.queries.push(q);
+ for(i=0; i<this.listeners.length; i++) {
+ if(this.listeners[i]!=null)
+ this.listeners[i].addQuery(q);
+ }
+ };
+
+ /**Remove a Query object from the source. Tells all listeners to also
+ * remove the query.
+ */
+ this.removeQuery = function(q) {
+ var i;
+ for(i=0; i<this.listeners.length; i++) {
+ if(this.listeners[i]!=null)
+ this.listeners[i].removeQuery(q);
+ }
+ if(this.queries[q.id]!=null)
+ delete this.queries[q.id];
+ };
+
+ /**adds a "Listener" to this QuerySource - that is, an object
+ * which is capable of both adding and removing queries.
+ * Currently, only the TabbedContainer class is added.
+ * also puts all current queries into the listener to be used.
+ */
+ this.addListener = function(listener) {
+ var i;
+ this.listeners.push(listener);
+ for(i=0; i<this.queries.length; i++) {
+ if(this.queries[i]!=null)
+ listener.addQuery(this.queries[i]);
+ }
+ };
+ /**removes listener from the array of listeners, if it exists! Also takes
+ * all of the queries from this source out of the listener.
+ */
+ this.removeListener = function(listener) {
+ var i;
+ for(i=0; i<this.queries.length; i++) {
+ if(this.queries[i]!=null)
+ listener.removeQuery(this.queries[i]);
+ }
+
+ for(i=0; i<this.listeners.length; i++) {
+ if(this.listeners[i]===listener) {
+ delete this.listeners[i];
+ }
+ }
+ };
+}
+
+$rdf.Variable.prototype.isVar = 1;
+$rdf.BlankNode.prototype.isVar = 1;
+$rdf.BlankNode.prototype.isBlank = 1;
+$rdf.Symbol.prototype.isVar = 0;
+$rdf.Literal.prototype.isVar = 0;
+$rdf.Formula.prototype.isVar = 0;
+$rdf.Collection.prototype.isVar = 0;
+
+
+/**
+ * This function will match a pattern to the current kb
+ *
+ * The callback function is called whenever a match is found
+ * When fetcher is supplied this will be called to satisfy any resource requests
+ * currently not in the kb. The fetcher function needs to be defined manualy and
+ * should call $rdf.Util.AJAR_handleNewTerm to process the requested resource.
+ *
+ * @param myQuery, a knowledgebase containing a pattern to use as query
+ * @param callback, whenever the pattern in myQuery is met this is called with
+ * the binding as parameter
+ * @param fetcher, whenever a resource needs to be loaded this gets called
+ * @param onDone callback when
+ */
+$rdf.IndexedFormula.prototype.query = function(myQuery, callback, fetcher, onDone) {
+ var kb = this;
+ $rdf.log.info("Query:"+myQuery.pat+", fetcher="+fetcher+"\n");
+ tabulator.log.error("@@@@ query.js 4: "+$rdf.log.error); // @@ works
+ $rdf.log.error("@@@@ query.js 5"); // @@
+
+ ///////////// Debug strings
+
+ function bindingsDebug(nbs) {
+ var str = "Bindings: ";
+ var i, n=nbs.length;
+ for (i=0; i<n; i++) {
+ str+= bindingDebug(nbs[i][0])+';\n\t';
+ };
+ return str;
+ } //bindingsDebug
+
+ function bindingDebug(b) {
+ var str = "", v;
+ for (v in b) {
+ str += " "+v+" -> "+b[v];
+ }
+ return str;
+ }
+
+
+// Unification: see also
+// http://www.w3.org/2000/10/swap/term.py
+// for similar things in python
+//
+// Unification finds all bindings such that when the binding is applied
+// to one term it is equal to the other.
+// Returns: a list of bindings, where a binding is an associative array
+// mapping variuable to value.
+
+
+ function RDFUnifyTerm(self, other, bindings, formula) {
+ var actual = bindings[self];
+ if (typeof actual == 'undefined') { // Not mapped
+ if (self.isVar) {
+ /*if (self.isBlank) //bnodes are existential variables
+ {
+ if (self.toString() == other.toString()) return [[ [], null]];
+ else return [];
+ }*/
+ var b = [];
+ b[self] = other;
+ return [[ b, null ]]; // Match
+ }
+ actual = self;
+ }
+ if (!actual.complexType) {
+ if (formula.redirections[actual]) actual = formula.redirections[actual];
+ if (formula.redirections[other]) other = formula.redirections[other];
+ if (actual.sameTerm(other)) return [[ [], null]];
+ return [];
+ }
+ if (self instanceof Array) {
+ if (!(other instanceof Array)) return [];
+ return RDFArrayUnifyContents(self, other, bindings)
+ };
+ throw("query.js: oops - code not written yet");
+ return undefined; // for lint
+ // return actual.unifyContents(other, bindings)
+ }; //RDFUnifyTerm
+
+
+
+ function RDFArrayUnifyContents(self, other, bindings, formula) {
+ if (self.length != other.length) return []; // no way
+ if (!self.length) return [[ [], null ]]; // Success
+ var nbs = RDFUnifyTerm(self[0], other[0], bindings, formula);
+ if (nbs == []) return nbs;
+ var res = [];
+ var i, n=nbs.length, nb, b2, j, m, v, nb2;
+ for (i=0; i<n; i++) { // for each possibility from the first term
+ nb = nbs[i][0]; // new bindings
+ var bindings2 = [];
+ for (v in nb) {
+ bindings2[v] = nb[v]; // copy
+ }
+ for (v in bindings) bindings2[v] = bindings[v]; // copy
+ var nbs2 = RDFArrayUnifyContents(self.slice(1), other.slice(1), bindings2, formula);
+ m = nbs2.length;
+ for (j=0; j<m; j++) {
+ var nb2 = nbs2[j][0]; //@@@@ no idea whether this is used or right
+ for (v in nb) nb2[v]=nb[v];
+ res.push([nb2, null]);
+ }
+ }
+ return res;
+ } // RDFArrayUnifyContents
+
+
+
+ // Matching
+ //
+ // Matching finds all bindings such that when the binding is applied
+ // to one term it is equal to the other term. We only match formulae.
+
+ /** if x is not in the bindings array, return the var; otherwise, return the bindings **/
+ function RDFBind(x, binding) {
+ var y = binding[x];
+ if (typeof y == 'undefined') return x;
+ return y;
+ }
+
+
+
+ /** prepare -- sets the index of the item to the possible matches
+ * @param f - formula
+ * @param item - an Statement, possibly w/ vars in it
+ * @param bindings -
+ * @returns true if the query fails -- there are no items that match **/
+ function prepare(f, item, bindings) {
+ item.nvars = 0;
+ item.index = null;
+ // if (!f.statements) $rdf.log.warn("@@@ prepare: f is "+f);
+ // $rdf.log.debug("Prepare: f has "+ f.statements.length);
+ //$rdf.log.debug("Prepare: Kb size "+f.statements.length+" Preparing "+item);
+
+ var t,c,terms = [item.subject,item.predicate,item.object],ind = [f.subjectIndex,f.predicateIndex,f.objectIndex];
+ for (i=0;i<3;i++)
+ {
+ //alert("Prepare "+terms[i]+" "+(terms[i] in bindings));
+ if (terms[i].isVar && !(terms[i] in bindings)) {
+ item.nvars++;
+ } else {
+ var t = RDFBind(terms[i], bindings); //returns the RDF binding if bound, otherwise itself
+ //if (terms[i]!=RDFBind(terms[i],bindings) alert("Term: "+terms[i]+"Binding: "+RDFBind(terms[i], bindings));
+ if (f.redirections[t.hashString()]) t = f.redirections[t.hashString()]; //redirect
+ termIndex=ind[i]
+ item.index = termIndex[t.hashString()];
+ if (typeof item.index == 'undefined') {
+ // $rdf.log.debug("prepare: no occurrence [yet?] of term: "+ t);
+ item.index = [];
+ }
+ }
+ }
+
+ if (item.index == null) item.index = f.statements;
+ // $rdf.log.debug("Prep: index length="+item.index.length+" for "+item)
+ // $rdf.log.debug("prepare: index length "+item.index.length +" for "+ item);
+ return false;
+ } //prepare
+
+ /** sorting function -- negative if self is easier **/
+ // We always prefer to start with a URI to be able to browse a graph
+ // this is why we put off items with more variables till later.
+ function easiestQuery(self, other) {
+ if (self.nvars != other.nvars) return self.nvars - other.nvars;
+ return self.index.length - other.index.length;
+ }
+
+ var match_index = 0; //index
+ /** matches a pattern formula against the knowledge base, e.g. to find matches for table-view
+ *
+ * @param f - knowledge base formula
+ * @param g - pattern formula (may have vars)
+ * @param bindingsSoFar - bindings accumulated in matching to date
+ * @param level - spaces to indent stuff also lets you know what level of recursion you're at
+ * @param fetcher - function (term, requestedBy) - myFetcher / AJAR_handleNewTerm / the sort
+ * @param localCallback - function(bindings, pattern, branch) called on sucess
+ * @returns nothing
+ *
+ * Will fetch linked data from the web iff the knowledge base an associated source fetcher (f.sf)
+ ***/
+ function match(f, g, bindingsSoFar, level, fetcher, localCallback, branch) {
+ $rdf.log.debug("Match begins, Branch count now: "+branch.count+" for "+branch.pattern_debug);
+ var sf = null;
+ if( typeof f.sf != 'undefined' ) {
+ sf = f.sf;
+ }
+ //$rdf.log.debug("match: f has "+f.statements.length+", g has "+g.statements.length)
+ var pattern = g.statements;
+ if (pattern.length == 0) { //when it's satisfied all the pattern triples
+
+ $rdf.log.debug("FOUND MATCH WITH BINDINGS:"+bindingDebug(bindingsSoFar));
+ if (g.optional.length==0) branch.reportMatch(bindingsSoFar);
+ else {
+ $rdf.log.debug("OPTIONAL: "+g.optional);
+ var junction = new OptionalBranchJunction(callback, bindingsSoFar); // @@ won't work with nested optionals? nest callbacks
+ var br = [], b;
+ for (b =0; b < g.optional.length; b++) {
+ br[b] = new OptionalBranch(junction); // Allocate branches to prevent premature ending
+ br[b].pattern_debug = g.optional[b]; // for diagnotics only
+ }
+ for (b =0; b < g.optional.length; b++) {
+ br[b].count = br[b].count + 1; // Count how many matches we have yet to complete
+ match(f, g.optional[b], bindingsSoFar, '', fetcher, callback, br[b]);
+ }
+ }
+ branch.count--;
+ $rdf.log.debug("Match ends -- success , Branch count now: "+branch.count+" for "+branch.pattern_debug);
+ return; // Success
+ }
+
+ var item, i, n=pattern.length;
+ //$rdf.log.debug(level + "Match "+n+" left, bs so far:"+bindingDebug(bindingsSoFar))
+
+ // Follow links from variables in query
+ if (fetcher) { //Fetcher is used to fetch URIs, function first term is a URI term, second is the requester
+ var id = "match" + match_index++;
+ var fetchResource = function (requestedTerm, id) {
+ var path = requestedTerm.uri;
+ if(path.indexOf("#")!=-1) {
+ path=path.split("#")[0];
+ }
+ if( sf ) {
+ sf.addCallback('done', function(uri) {
+ if ((kb.canon(kb.sym(uri)).uri != path) && (uri != kb.canon(kb.sym(path)))) {
+ return true
+ }
+
+ match(f, g, bindingsSoFar, level, fetcher, // match not match2 to look up any others necessary.
+ localCallback, branch)
+ return false
+ })
+ }
+ fetcher(requestedTerm, id)
+ }
+ for (i=0; i<n; i++) {
+ item = pattern[i]; //for each of the triples in the query
+ if (item.subject in bindingsSoFar
+ && bindingsSoFar[item.subject].uri
+ && sf && sf.getState($rdf.Util.uri.docpart(bindingsSoFar[item.subject].uri)) == "unrequested") {
+ //fetch the subject info and return to id
+ fetchResource(bindingsSoFar[item.subject],id)
+ return; // only look up one per line this time, but we will come back again though match
+ } else if (item.object in bindingsSoFar
+ && bindingsSoFar[item.object].uri
+ && sf && sf.getState($rdf.Util.uri.docpart(bindingsSoFar[item.object].uri)) == "unrequested") {
+ fetchResource(bindingsSoFar[item.object], id)
+ return;
+ }
+ }
+ } // if fetcher
+ match2(f, g, bindingsSoFar, level, fetcher, localCallback, branch)
+ return;
+ } // match
+
+ /** match2 -- stuff after the fetch **/
+ function match2(f, g, bindingsSoFar, level, fetcher, callback, branch) //post-fetch
+ {
+ var pattern = g.statements, n = pattern.length, i;
+ for (i=0; i<n; i++) { //For each statement left in the query, run prepare
+ item = pattern[i];
+ $rdf.log.info("match2: item=" + item + ", bindingsSoFar=" + bindingDebug(bindingsSoFar));
+ prepare(f, item, bindingsSoFar);
+ }
+ pattern.sort(easiestQuery);
+ // $rdf.log.debug("Sorted pattern:\n"+pattern)
+ var item = pattern[0];
+ var rest = f.formula();
+ rest.optional = g.optional;
+ rest.constraints = g.constraints;
+ rest.statements = pattern.slice(1); // No indexes: we will not query g.
+ $rdf.log.debug(level + "match2 searching "+item.index.length+ " for "+item+
+ "; bindings so far="+bindingDebug(bindingsSoFar));
+ //var results = [];
+ var c, nc=item.index.length, nbs1;
+ //var x;
+ for (c=0; c<nc; c++) { // For each candidate statement
+ var st = item.index[c]; //for each statement in the item's index, spawn a new match with that binding
+ nbs1 = RDFArrayUnifyContents(
+ [item.subject, item.predicate, item.object],
+ [st.subject, st.predicate, st.object], bindingsSoFar, f);
+ $rdf.log.info(level+" From first: "+nbs1.length+": "+bindingsDebug(nbs1))
+ var k, nk=nbs1.length, nb1, v;
+ //branch.count += nk;
+ //$rdf.log.debug("Branch count bumped "+nk+" to: "+branch.count);
+ for (k=0; k<nk; k++) { // For each way that statement binds
+ var bindings2 = [];
+ var newBindings1 = nbs1[k][0];
+ if (!constraintsSatisfied(newBindings1,g.constraints)) {
+ //branch.count--;
+ $rdf.log.debug("Branch count CS: "+branch.count);
+ continue;}
+ for (var v in newBindings1){
+ bindings2[v] = newBindings1[v]; // copy
+ }
+ for (var v in bindingsSoFar) {
+ bindings2[v] = bindingsSoFar[v]; // copy
+ }
+
+ branch.count++; // Count how many matches we have yet to complete
+ match(f, rest, bindings2, level+ ' ', fetcher, callback, branch); //call match
+ }
+ }
+ branch.count--;
+ $rdf.log.debug("Match2 ends, Branch count: "+branch.count +" for "+branch.pattern_debug);
+ if (branch.count == 0)
+ {
+ $rdf.log.debug("Branch finished.");
+ branch.reportDone(branch);
+ }
+ } //match2
+
+ function constraintsSatisfied(bindings,constraints)
+ {
+ var res=true;
+ for (var x in bindings) {
+ if (constraints[x]) {
+ var test = constraints[x].test;
+ if (test && !test(bindings[x]))
+ res=false;
+ }
+ }
+ return res;
+ }
+
+ //////////////////////////// Body of query() ///////////////////////
+
+ if(!fetcher) {
+ fetcher=function (x, requestedBy) {
+ if (x == null) {
+ return;
+ } else {
+ $rdf.Util.AJAR_handleNewTerm(kb, x, requestedBy);
+ }
+ };
+ }
+ //prepare, oncallback: match1
+ //match1: fetcher, oncallback: match2
+ //match2, oncallback: populatetable
+ // $rdf.log.debug("Query F length"+this.statements.length+" G="+myQuery)
+ var f = this;
+ $rdf.log.debug("Query on "+this.statements.length)
+// if (kb != this) alert("@@@@??? this="+ this)
+
+ //kb.remoteQuery(myQuery,'http://jena.hpl.hp.com:3040/backstage',callback);
+ //return;
+
+
+ // When there are OPTIONAL clauses, we must return bindings without them if none of them
+ // succeed. However, if any of them do succeed, we should not. (This is what branchCount()
+ // tracked. The problem currently is (2011/7) that when several optionals exist, and they
+ // all match, multiple sets of bindings are returned, each with one optional filled in.)
+
+ union = function(a,b) {
+ var c= {};
+ var x;
+ for (x in a) c[x] = a[x];
+ for (x in b) c[x] = b[x];
+ return c
+ }
+
+ function OptionalBranchJunction(originalCallback, trunkBindings) {
+ this.trunkBindings = trunkBindings;
+ this.originalCallback = originalCallback;
+ this.branches = [];
+ //this.results = []; // result[i] is an array of bindings for branch i
+ //this.done = {}; // done[i] means all/any results are in for branch i
+ //this.count = {};
+ return this;
+ }
+
+ OptionalBranchJunction.prototype.checkAllDone = function() {
+ for (var i=0; i<this.branches.length; i++) if (!this.branches[i].done) return;
+ $rdf.log.debug("OPTIONAL BIDNINGS ALL DONE:");
+ this.doCallBacks(this.branches.length-1, this.trunkBindings);
+
+ };
+ // Recrursively generate the cross product of the bindings
+ OptionalBranchJunction.prototype.doCallBacks = function(b, bindings) {
+ if (b < 0) return this.originalCallback(bindings);
+ for (var j=0; j < this.branches[b].results.length; j++) {
+ this.doCallBacks(b-1, union(bindings, this.branches[b].results[j]));
+ }
+ };
+
+ // A mandatory branch is the normal one, where callbacks
+ // are made immediately and no junction is needed.
+ // Might be useful for onFinsihed callback for query API.
+ function MandatoryBranch(callback, onDone) {
+ this.count = 0;
+ this.success = false;
+ this.done = false;
+ // this.results = [];
+ this.callback = callback;
+ this.onDone = onDone;
+ // this.junction = junction;
+ // junction.branches.push(this);
+ return this;
+ }
+
+ MandatoryBranch.prototype.reportMatch = function(bindings) {
+ tabulator.log.error("@@@@ query.js 1"); // @@
+ $rdf.log.error("@@@@ query.js 2"); // @@
+ this.callback(bindings);
+ this.success = true;
+ };
+
+ MandatoryBranch.prototype.reportDone = function(b) {
+ this.done = true;
+ $rdf.log.info("Mandatory query branch finished.***")
+ if (this.onDone != undefined) this.onDone();
+ };
+
+
+ // An optional branch hoards its results.
+ function OptionalBranch(junction) {
+ this.count = 0;
+ this.done = false;
+ this.results = [];
+ this.junction = junction;
+ junction.branches.push(this);
+ return this;
+ }
+
+ OptionalBranch.prototype.reportMatch = function(bindings) {
+ this.results.push(bindings);
+ };
+
+ OptionalBranch.prototype.reportDone = function() {
+ $rdf.log.debug("Optional branch finished - results.length = "+this.results.length);
+ if (this.results.length == 0) {// This is what optional means: if no hits,
+ this.results.push({}); // mimic success, but with no bindings
+ $rdf.log.debug("Optional branch FAILED - that's OK.");
+ }
+ this.done = true;
+ this.junction.checkAllDone();
+ };
+
+ var trunck = new MandatoryBranch(callback, onDone);
+ trunck.count++; // count one branch to complete at the moment
+ setTimeout(function() { match(f, myQuery.pat, myQuery.pat.initBindings, '', fetcher, callback, trunck /*branch*/ ); }, 0);
+
+ return; //returns nothing; callback does the work
+}; //query
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/rdfa.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,725 @@
+/*
+ * jQuery RDFa @VERSION
+ * U N T E S T E D T R I A L O N L Y
+ * P O R T I N P R O G R E S S
+ *
+ * Copyright (c) 2008,2009 Jeni Tennison
+ * Licensed under the MIT (MIT-LICENSE.txt)
+ * 2010-06-11 Taken from http://code.google.com/p/rdfquery/source/checkout TBL
+ * Callbacks for new triples removed -- should more logically be on the store
+ * so as to make common for all sources
+ *
+ * Depends:
+ * uri.js
+ * term.js
+ * identity.js
+ *
+ * jquery.rdf.js
+ */
+/**
+ * @fileOverview jQuery RDFa processing
+ * @author <a href="mailto:jeni@jenitennison.com">Jeni Tennison</a>
+ * @copyright (c) 2008,2009 Jeni Tennison
+ * @license MIT license (MIT-LICENSE.txt)
+ * @version 1.0
+ * @requires jquery.uri.js
+ * @requires jquery.xmlns.js
+ * @requires jquery.curie.js
+ * @requires jquery.datatype.js
+ * @requires jquery.rdf.js
+ */
+
+
+
+
+
+
+/*
+ * jQuery CURIE @VERSION
+ *
+ * Copyright (c) 2008 Jeni Tennison
+ * Licensed under the MIT (MIT-LICENSE.txt)
+ *
+ * Depends:
+ * jquery.uri.js
+ * jquery.xmlns.js
+ */
+/*global jQuery */
+
+// The curie module itself is also the parse function
+$rdf.curie = function (curie, options) {
+ var
+ opts = $rdf.Util.extend({}, $rdf.curie.defaults, options || {}),
+ m = /^(([^:]*):)?(.+)$/.exec(curie),
+ prefix = m[2],
+ local = m[3],
+ ns = opts.namespaces[prefix];
+ if (prefix) {
+ if (ns === undefined) {
+ throw "Malformed CURIE: No namespace binding for " + prefix + " in CURIE " + curie;
+ }
+ } else if (opts.reserved.length && $rdf.Util.inArray(curie, opts.reserved) >= 0) {
+ ns = opts.reservedNamespace;
+ local = curie;
+ } else if (opts.defaultNamespace === undefined) {
+ // the default namespace is provided by the application; it's not clear whether
+ // the default XML namespace should be used if there's a colon but no prefix
+ throw "Malformed CURIE: No prefix and no default namespace for unprefixed CURIE " + curie;
+ } else {
+ ns = opts.defaultNamespace;
+ }
+ return $rdf.sym(ns.uri + local);
+};
+
+$rdf.curie.defaults = {
+ namespaces: {},
+ reserved: [],
+ reservedNamespace: undefined,
+ defaultNamespace: undefined
+};
+
+$rdf.curie.safeCurie = function (safeCurie, options) {
+ var m = /^\[([^\]]+)\]$/.exec(safeCurie);
+ return m ? $rdf.curie(m[1], options) : $rdf.sym(safeCurie);
+};
+
+$rdf.curie.createCurie = function (uri, options) {
+ var opts = $rdf.Util.extend({}, $rdf.curie.defaults, options || {}),
+ ns = opts.namespaces,
+ curie;
+ uri = $rdf.sym(uri).toString();
+ for (var prefix in ns) {
+ var namespace = ns[prefix];
+ if (uri.substring(0, namespace.toString().length) === namespace.toString()) {
+ curie = prefix + ':' + uri.substring(namespace.toString().length);
+ return null;
+ }
+ };
+ if (curie === undefined) {
+ throw "No Namespace Binding: There's no appropriate namespace binding for generating a CURIE from " + uri;
+ } else {
+ return curie;
+ }
+};
+
+// Extend JQuery with the curie functionr
+$.fn.curie = function (curie, options) {
+ var opts = $rdf.Util.extend({}, $rdf.curie.defaults, {
+ namespaces: this.xmlns()
+ }, options || {});
+ return $rdf.curie(curie, opts);
+};
+
+$rdf.safeCurie = function (safeCurie, options) {
+ var opts = $rdf.Util.extend({}, $rdf.curie.defaults, {
+ namespaces: this.xmlns()
+ }, options || {});
+ return $rdf.curie.safeCurie(safeCurie, opts);
+};
+
+$rdf.createCurie = function (uri, options) {
+ var opts = $rdf.Util.extend({}, $rdf.curie.defaults, {
+ namespaces: this.xmlns()
+ }, options || {});
+ return $rdf.curie.createCurie(uri, opts);
+};
+
+$rdf.curie.defaults = {
+ reserved: ['alternate', 'appendix', 'bookmark', 'cite', 'chapter', 'contents', 'copyright', 'first', 'glossary', 'help', 'icon', 'index', 'last', 'license', 'meta', 'next', 'p3pv1', 'prev', 'role', 'section', 'stylesheet', 'subsection', 'start', 'top', 'up'],
+ reservedNamespace: 'http://www.w3.org/1999/xhtml/vocab#',
+ defaultNamespace: undefined
+};
+
+$rdf.safeCurie = function (safeCurie, options) {
+ var opts = $rdf.Util.extend({}, $rdf.curie.defaults, {
+ namespaces: this.xmlns()
+ }, options || {});
+ return $rdf.safeCurie(safeCurie, opts);
+};
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+$rdf.rdfa = {};
+
+$rdf.rdfa.parse = function (dom, kb, baseUri, doc) {
+ return $rdf.rdfa.parseThis.call($(dom), kb, baseUri, doc);
+};
+
+$rdf.rdfa.parseThis = function (kb, baseUri, doc) {
+ this.kb = kb;
+ this.baseUri = baseUri;
+
+
+// Agenda:
+// fn.curie.
+// docResource (relies on database-wide document base)
+// Replace all $jq.rdf. with equivalent $rdf.
+//
+// Note: The original jQuery "$" is now $jq in this code.
+////////////////////////////////////////////////////
+
+ //if ($ == undefined && tabulator && tabulator.jq) $ = tabulator.jq; // not sure hot this is upposed to be wired - tbl
+
+ var
+ ns = {
+ rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+ xsd: "http://www.w3.org/2001/XMLSchema#",
+ xml: 'http://www.w3.org/XML/1998/namespace',
+ xmlns: 'http://www.w3.org/2000/xmlns/'
+ },
+
+ rdfXMLLiteral = ns.rdf + 'XMLLiteral',
+ rdfXMLLiteralSym = kb.sym(rdfXMLLiteral),
+
+ rdfaCurieDefaults = $rdf.curie.defaults,
+ relReserved = [
+ 'alternate', 'appendix', 'bookmark', 'cite', 'chapter', 'contents', 'copyright',
+ 'first', 'glossary', 'help', 'icon', 'index', 'last', 'license', 'meta', 'next',
+ 'p3pv1', 'prev', 'role', 'section', 'stylesheet', 'subsection', 'start', 'top', 'up'
+ ],
+
+ attRegex = /\s([^ =]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^ >]+))/g,
+
+ ncNameChar = '[-A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF\.0-9\u00B7\u0300-\u036F\u203F-\u2040]',
+ ncNameStartChar = '[\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3\u4E00-\u9FA5\u3007\u3021-\u3029_]', //"
+ ncNameRegex = new RegExp('^' + ncNameStartChar + ncNameChar + '*$'),
+
+ docResource = kb.sym(baseUri),
+ bnodeMap = {};
+
+ var type = kb.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
+ var why = docResource;
+
+ parseEntities = function (string) {
+ var result = "", m, entity;
+ if (!/&/.test(string)) {
+ return string;
+ }
+ while (string.length > 0) {
+ m = /([^&]*)(&([^;]+);)(.*)/g.exec(string);
+ if (m === null) {
+ result += string;
+ break;
+ }
+ result += m[1];
+ entity = m[3];
+ string = m[4];
+ if (entity.charAt(0) === '#') {
+ if (entity.charAt(1) === 'x') {
+ result += String.fromCharCode(parseInt(entity.substring(2), 16));
+ } else {
+ result += String.fromCharCode(parseInt(entity.substring(1), 10));
+ }
+ } else {
+ switch(entity) {
+ case 'amp':
+ result += '&';
+ break;
+ case 'nbsp':
+ result += String.fromCharCode(160);
+ break;
+ case 'quot':
+ result += '"';
+ break;
+ case 'apos':
+ result += "'";
+ break;
+ default:
+ result += '&' + entity + ';';
+ }
+ }
+ }
+ return result;
+ };
+
+ // @param elem is a JQ object
+ // returns attrubtes an namespaces
+ //
+ getAttributes = function (elem) {
+ var i, e, a, tag, name, value, attMap, prefix,
+ atts = {},
+ nsMap = {};
+ var e = elem[0];
+ nsMap[':length'] = 0;
+
+ if (e.nodeType == 9) return { atts: atts, namespaces: nsMap }; // Document
+
+ if (e.attributes && e.attributes.getNamedItemNS) {
+ attMap = e.attributes;
+ for (i = 0; i < attMap.length; i += 1) {
+ a = attMap[i];
+ if (/^xmlns(:(.+))?$/.test(a.nodeName) && a.nodeValue !== '') {
+ prefix = /^xmlns(:(.+))?$/.exec(a.nodeName)[2] || '';
+ if (ncNameRegex.test(prefix) && (prefix !== 'xml' || a.nodeValue === ns.xml) && (a.nodeValue !== ns.xml || prefix === 'xml') && prefix !== 'xmlns' && a.nodeValue !== ns.xmlns) {
+ nsMap[prefix] = $rdf.sym(a.nodeValue);
+ nsMap[':length'] += 1;
+ }
+// } else if (/rel|rev|lang|xml:lang/.test(a.nodeName)) {
+// atts[a.nodeName] = a.nodeValue === '' ? undefined : a.nodeValue;
+ } else if (/rel|rev|lang|xml:lang|about|href|src|resource|property|typeof|content|datatype/.test(a.nodeName)) {
+ atts[a.nodeName] = a.nodeValue === null ? undefined : a.nodeValue;
+ }
+ }
+ } else { // For IE, which hides namespaces to carefully
+ tag = /<[^>]+>/.exec(e.outerHTML);
+ a = attRegex.exec(tag);
+ while (a !== null) {
+ name = a[1];
+ value = a[2] || a[3] || a[4];
+ if (/^xmlns/.test(name) && name !== 'xmlns:' && value !== '') {
+ prefix = /^xmlns(:(.+))?$/.exec(name)[2] || '';
+ if (ncNameRegex.test(prefix) && (prefix !== 'xml' || a.nodeValue === ns.xml) && (a.nodeValue !== ns.xml || prefix === 'xml') && prefix !== 'xmlns' && a.nodeValue !== ns.xmlns) {
+ nsMap[prefix] = $rdf.sym(value);
+ nsMap[':length'] += 1;
+ }
+ } else if (/about|href|src|resource|property|typeof|content|datatype|rel|rev|lang|xml:lang/.test(name)) {
+ atts[name] = parseEntities(value);
+ }
+ a = attRegex.exec(tag);
+ }
+ attRegex.lastIndex = 0;
+ }
+ return { atts: atts, namespaces: nsMap };
+ };
+
+ getAttribute = function (elem, attr) {
+ var val = elem[0].getAttribute(attr);
+// if (attr === 'rev' || attr === 'rel' || attr === 'lang' || attr === 'xml:lang') {
+// val = val === '' ? undefined : val;
+// }
+ return val === null ? undefined : val;
+ };
+
+ resourceFromUri = function (uri) {
+ return kb.sym(uri);
+ };
+
+ resourceFromCurie = function (curie, elem, noblanks, options) {
+ if (curie.substring(0, 2) === '_:') {
+ if (noblanks) {
+ return undefined;
+ }
+ var bn = bnodeMap[curie]
+ if (bn) return bn;
+ var bn = kb.bnode();
+ bnodeMap[curie] = bn
+ return bn;
+ } else {
+ try {
+ return $rdf.curie(curie, options);
+ } catch (e) {
+ return undefined;
+ }
+ }
+ },
+
+ resourceFromSafeCurie = function (safeCurie, elem, options) {
+ var m = /^\[(.*)\]$/.exec(safeCurie),
+ base = options.base || elem.base();
+ return m ? resourceFromCurie(m[1], elem, false, options) : $rdf.sym(safeCurie, base);
+ },
+
+ resourcesFromCuries = function (curies, elem, noblanks, options) {
+ var i, resource, resources = [];
+ curies = curies && curies.split ? curies.split(/[ \t\n\r\x0C]+/g) : [];
+ for (i = 0; i < curies.length; i += 1) {
+ if (curies[i] !== '') {
+ resource = resourceFromCurie(curies[i], elem, noblanks, options);
+ if (resource !== undefined) {
+ resources.push(resource);
+ }
+ }
+ }
+ return resources;
+ },
+
+ /* @@ suppressed for now as we only read not change them -- timbl
+ removeCurie = function (curies, resource, options) {
+ var i, r, newCuries = [];
+ resource = resource.type === 'uri' ? resource : $jq.rdf.resource(resource, options);
+ curies = curies && curies.split ? curies.split(/\s+/) : [];
+ for (i = 0; i < curies.length; i += 1) {
+ if (curies[i] !== '') {
+ r = resourceFromCurie(curies[i], null, false, options);
+ if (r !== resource) {
+ newCuries.push(curies[i]);
+ }
+ }
+ }
+ return newCuries.reverse().join(' ');
+ },
+ */
+
+ $rdf.rdfaParser = function(kb, baseUri) {
+ this.kb = kb;
+ this.baseUri = baseUri;
+ return true;
+ }
+
+ getObjectResource = function (elem, context, relation) {
+ var r, resource, atts, curieOptions;
+ context = context || {};
+ atts = context.atts || getAttributes(elem).atts;
+ r = relation === undefined ? atts.rel !== undefined || atts.rev !== undefined : relation;
+ resource = atts.resource;
+ resource = resource === undefined ? atts.href : resource;
+ if (resource === undefined) {
+ resource = r ? kb.bnode() : resource;
+ } else {
+ curieOptions = context.curieOptions || $rdf.Util.extend(
+ {}, rdfaCurieDefaults, { namespaces: elem.xmlns() });
+ resource = resourceFromSafeCurie(resource, elem, curieOptions);
+ }
+ return resource;
+ };
+
+ getSubject = function (elem, context, relation) {
+ var r, atts, curieOptions, subject, skip = false;
+ context = context || {};
+ atts = context.atts || getAttributes(elem).atts;
+ curieOptions = context.curieOptions || $rdf.Util.extend({},
+ rdfaCurieDefaults, { namespaces: elem.xmlns(), base: elem.base() });
+ r = relation === undefined ? atts.rel !== undefined || atts.rev !== undefined : relation;
+ if (atts.about !== undefined) {
+ subject = resourceFromSafeCurie(atts.about, elem, curieOptions);
+ }
+ if (subject === undefined && atts.src !== undefined) {
+ subject = resourceFromSafeCurie(atts.src, elem, curieOptions);
+ }
+ if (!r && subject === undefined && atts.resource !== undefined) {
+ subject = resourceFromSafeCurie(atts.resource, elem, curieOptions);
+ }
+ if (!r && subject === undefined && atts.href !== undefined) {
+ subject = resourceFromSafeCurie(atts.href, elem, curieOptions);
+ }
+ if (subject === undefined) {
+ if (/^(head|body)$/i.test(elem[0].nodeName)) {
+ subject = docResource;
+ } else if (atts['typeof'] !== undefined) {
+ subject = kb.bnode();
+ } else if (elem[0].parentNode && elem[0].parentNode.nodeType === 1) {
+ subject = context.object || getObjectResource(elem.parent()) || getSubject(elem.parent()).subject;
+ skip = !r && atts.property === undefined;
+ } else {
+ subject = docResource;
+ }
+ }
+ return { subject: subject, skip: skip };
+ };
+
+ getLang = function (elem, context) {
+ var lang;
+ context = context || {};
+ if (context.atts) {
+ lang = context.atts.lang;
+ lang = lang || context.atts['xml:lang'];
+ } else {
+ lang = elem[0].getAttribute('lang');
+ try {
+ lang = (lang === null || lang === '') ? elem[0].getAttribute('xml:lang') : lang;
+ } catch (e) {
+ }
+ lang = (lang === null || lang === '') ? undefined : lang;
+ }
+ if (lang === undefined) {
+ if (context.lang) {
+ lang = context.lang;
+ } else {
+ if (elem[0].parentNode && elem[0].parentNode.nodeType === 1) {
+ lang = getLang(elem.parent());
+ }
+ }
+ }
+ return lang;
+ };
+
+ entity = function (c) {
+ switch (c) {
+ case '<':
+ return '<';
+ case '"':
+ return '"';
+ case '&':
+ return '&';
+ }
+ };
+
+ serialize = function (elem, ignoreNs) {
+ var i, string = '', atts, a, name, ns, tag;
+ elem.contents().each(function () {
+ var j = $(this), // @@@ ? Use of "this'?
+ e = j[0];
+ if (e.nodeType === 1) { // tests whether the node is an element
+ name = e.nodeName.toLowerCase();
+ string += '<' + name;
+ if (e.outerHTML) {
+ tag = /<[^>]+>/.exec(e.outerHTML);
+ a = attRegex.exec(tag);
+ while (a !== null) {
+ if (!/^jQuery/.test(a[1])) {
+ string += ' ' + a[1] + '=';
+ string += a[2] ? a[3] : '"' + a[1] + '"';
+ }
+ a = attRegex.exec(tag);
+ }
+ attRegex.lastIndex = 0;
+ } else {
+ atts = e.attributes;
+ for (i = 0; i < atts.length; i += 1) {
+ a = atts.item(i);
+ string += ' ' + a.nodeName + '="';
+ string += a.nodeValue.replace(/[<"&]/g, entity);
+ string += '"'; //'
+ }
+ }
+ if (!ignoreNs) {
+ ns = j.xmlns('');
+ if (ns !== undefined && j.attr('xmlns') === undefined) {
+ string += ' xmlns="' + ns + '"';
+ }
+ }
+ string += '>';
+ string += serialize(j, true);
+ string += '</' + name + '>';
+ } else if (e.nodeType === 8) { // tests whether the node is a comment
+ string += '<!--';
+ string += e.nodeValue;
+ string += '-->';
+ } else {
+ string += e.nodeValue;
+ }
+ });
+ return string;
+ },
+
+ // Originally:
+ // This is the main function whcih extracts te RDFA
+ // 'this' is a JQ object for the DOM element to be parsed
+ // $rdf.rdfaParser(kb).rdfa.call($(element or document))
+ // parseElement = function(element) {
+ // this.rdfa.call($(element));
+ // };
+
+
+ parse = function (context) {
+ var i, subject, resource, lang, datatype, content, text,
+ types, object, triple, parent,
+ properties, rels, revs,
+ forward, backward,
+ triples = [],
+ callback, relCurieOptions,
+ attsAndNs, atts, namespaces, ns,
+ children = this.children();
+ context = context || {};
+ forward = context.forward || [];
+ backward = context.backward || [];
+ callback = context.callback || function () { return this; };
+ attsAndNs = getAttributes(this);
+ atts = attsAndNs.atts;
+ context.atts = atts;
+ namespaces = context.namespaces || this.xmlns();
+ if (attsAndNs.namespaces[':length'] > 0) {
+ namespaces = $rdf.Util.extend({}, namespaces);
+ for (ns in attsAndNs.namespaces) {
+ if (ns != ':length') {
+ namespaces[ns] = attsAndNs.namespaces[ns];
+ }
+ }
+ }
+ context.curieOptions = $rdf.Util.extend({},
+ rdfaCurieDefaults, { reserved: [], namespaces: namespaces, base: this.base() });
+ relCurieOptions = $rdf.Util.extend({}, context.curieOptions, { reserved: relReserved });
+ subject = getSubject(this, context);
+ lang = getLang(this, context);
+ if (subject.skip) {
+ rels = context.forward;
+ revs = context.backward;
+ subject = context.subject;
+ resource = context.object;
+ } else {
+ subject = subject.subject;
+ if (forward.length > 0 || backward.length > 0) {
+ parent = context.subject || getSubject(this.parent()).subject; // @@
+ for (i = 0; i < forward.length; i += 1) {
+ kb.add(parent, forward[i], subject, why);
+ // triple = callback.call(triple, this.get(0), triple);
+ //if (triple !== undefined && triple !== null) {
+ // triples = triples.concat(triple);
+ //}
+ }
+ for (i = 0; i < backward.length; i += 1) {
+ kb.add(subject, backward[i], parent, why);
+ //triple = callback.call(triple, this.get(0), triple);
+ //if (triple !== undefined && triple !== null) {
+ // triples = triples.concat(triple);
+ //}
+ }
+ }
+ resource = getObjectResource(this, context);
+ types = resourcesFromCuries(atts['typeof'], this, false, context.curieOptions);
+ for (i = 0; i < types.length; i += 1) {
+ kb.add(subject, type, types[i], why);
+ //triple = callback.call(triple, this.get(0), triple);
+ //if (triple !== undefined && triple !== null) {
+ // triples = triples.concat(triple);
+ //}
+ }
+ properties = resourcesFromCuries(atts.property, this, true, context.curieOptions);
+ if (properties.length > 0) {
+ datatype = atts.datatype;
+ content = atts.content;
+ text = this.text().replace(/"/g, '\\"'); //')
+ if (datatype !== undefined && datatype !== '') {
+ datatype = $rdf.curie(datatype, context.curieOptions);
+ if (datatype.toString() === rdfXMLLiteral) {
+ object = kb.literal(serialize(this), undefined, rdfXMLLiteralSym );
+ } else if (content !== undefined) {
+ object = kb.literal(content, kb.sym(datatype));
+ } else {
+ object = kb.literal(text, kb.sym(datatype));
+ }
+ } else if (content !== undefined) {
+ if (lang === undefined) {
+ object = kb.literal(content);
+ } else {
+ object = kb.literal(content, lang);
+ }
+ } else if (children.length === 0 ||
+ datatype === '') {
+ lang = getLang(this, context);
+ if (lang === undefined) {
+ object = kb.literal(text); //@@ removed extra double quote marks??
+ } else {
+ object = kb.literal(text, undefined, lang);
+ }
+ } else {
+ object = kb.literal(serialize(this), kb.sym(rdfXMLLiteral));
+ }
+ for (i = 0; i < properties.length; i += 1) {
+ kb.add(subject, properties[i], object, why);
+ }
+ } // if properties/length > 0
+ rels = resourcesFromCuries(atts.rel, this, true, relCurieOptions);
+ revs = resourcesFromCuries(atts.rev, this, true, relCurieOptions);
+ if (atts.resource !== undefined || atts.href !== undefined) {
+ // make the triples immediately
+ if (rels !== undefined) {
+ for (i = 0; i < rels.length; i += 1) {
+ kb.add(subject, rels[i], resource, why);
+ }
+ }
+ rels = [];
+ if (revs !== undefined) {
+ for (i = 0; i < revs.length; i += 1) {
+ kb.add(resource, revs[i], subject, why);
+ }
+ }
+ revs = [];
+ }
+ } // end subject not skip
+ children.each(function () {
+ parse.call($(this), { forward: rels, backward: revs,
+ subject: subject, object: resource || subject,
+ lang: lang, namespaces: namespaces, callback: callback });
+ });
+ return;
+ }; // parse
+
+ // Add to list of gleaners @@@
+ gleaner = function (options) {
+ var type, atts;
+ if (options && options.about !== undefined) {
+ atts = getAttributes(this).atts;
+ if (options.about === null) {
+ return atts.property !== undefined ||
+ atts.rel !== undefined ||
+ atts.rev !== undefined ||
+ atts['typeof'] !== undefined;
+ } else {
+ return getSubject(this, {atts: atts}).subject.value === options.about;
+ }
+ } else if (options && options.type !== undefined) {
+ type = getAttribute(this, 'typeof');
+ if (type !== undefined) {
+ return options.type === null ? true : this.curie(type) === options.type;
+ }
+ return false;
+ } else {
+ return parse(this, options);
+ }
+ }
+
+ // return; // debug later @@@@@@@@
+
+ return parse.call(this);
+ // End of Parser object
+
+}
+
+
+ /**
+ * Creates a {@link jQuery.rdf} object containing the RDF triples parsed from the RDFa found in the current jQuery selection or adds the specified triple as RDFa markup on each member of the current jQuery selection. To create an {@link jQuery.rdf} object, you will usually want to use {@link jQuery#rdf} instead, as this may perform other useful processing (such as of microformats used within the page).
+ * @methodOf jQuery#
+ * @name jQuery#rdfa
+ * @param {jQuery.rdf.triple} [triple] The RDF triple to be added to each item in the jQuery selection.
+ * @returns {jQuery.rdf}
+ * @example
+ * // Extract RDFa markup from all span elements contained inside #main
+ * rdf = $('#main > span').rdfa();
+ * @example
+ * // Add RDFa markup to a particular element
+ * var span = $('#main > p > span');
+ * span.rdfa('<> dc:date "2008-10-19"^^xsd:date .');
+ */
+ /*
+ // 'this' is a jq bject whcih wraps an element
+ $jq.fn.rdfa = function (triple) {
+ if (triple === undefined) {
+ var triples = $jq.map($(this), function (elem) {
+ return rdfa.call($(elem));
+ });
+ return $jq.rdf({ triples: triples });
+ } else {
+ $(this).each(function () {
+ addRDFa.call($(this), triple);
+ });
+ return this;
+ }
+ };
+ */
+
+ /**
+ * Removes the specified RDFa markup from each of the items in the current jQuery selection. The input parameter can be either an object or an array of objects. The objects can either have a <code>type</code> property, in which case the specified type is removed from the RDFa provided on the selected elements, or a <code>property</code> property, in which case the specified property is removed from the RDFa provided on the selected elements.
+ * @methodOf jQuery#
+ * @name jQuery#removeRdfa
+ * @param {Object|Object[]} triple The RDFa markup items to be removed
+ * from the items in the jQuery selection.
+ * @returns {jQuery} The original jQuery object.
+ * @example
+ * // To remove a property resource or relation from an element
+ * $('#main > p > a').removeRdfa({ property: "dc:creator" });
+ * @example
+ * // To remove a type from an element
+ * $('#main >p > a').removeRdfa({ type: "foaf:Person" });
+ * @example
+ * // To remove multiple triples from an element
+ * $('#main > p > a').removeRdfa([{ property: "foaf:depicts" }, { property: "dc:creator" }]);
+ */
+ /*
+ $jq.fn.removeRdfa = function (triple) {
+ $(this).each(function () {
+ removeRDFa.call($(this), triple);
+ });
+ return this;
+ };
+
+ $jq.rdf.gleaners.push(gleaner);
+*/
+/*
+$rdf.parseRdfa = function(element, kb, baseUri) {
+ var p = new $rdf.RDFaParser(kb, baseUri);
+ p.rdfa.call(element);
+};
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/rdfparser.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,597 @@
+/**
+ * @fileoverview
+ * TABULATOR RDF PARSER
+ *
+ * Version 0.1
+ * Parser believed to be in full positive RDF/XML parsing compliance
+ * with the possible exception of handling deprecated RDF attributes
+ * appropriately. Parser is believed to comply fully with other W3C
+ * and industry standards where appropriate (DOM, ECMAScript, &c.)
+ *
+ * Author: David Sheets <dsheets@mit.edu>
+ * SVN ID: $Id$
+ *
+ * W3C® SOFTWARE NOTICE AND LICENSE
+ * http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+ * This work (and included software, documentation such as READMEs, or
+ * other related items) is being provided by the copyright holders under
+ * the following license. By obtaining, using and/or copying this work,
+ * you (the licensee) agree that you have read, understood, and will
+ * comply with the following terms and conditions.
+ *
+ * Permission to copy, modify, and distribute this software and its
+ * documentation, with or without modification, for any purpose and
+ * without fee or royalty is hereby granted, provided that you include
+ * the following on ALL copies of the software and documentation or
+ * portions thereof, including modifications:
+ *
+ * 1. The full text of this NOTICE in a location viewable to users of
+ * the redistributed or derivative work.
+ * 2. Any pre-existing intellectual property disclaimers, notices, or terms and
+ * conditions. If none exist, the W3C Software Short Notice should be
+ * included (hypertext is preferred, text is permitted) within the body
+ * of any redistributed or derivative code.
+ * 3. Notice of any changes or modifications to the files, including the
+ * date changes were made. (We recommend you provide URIs to the location
+ * from which the code is derived.)
+ *
+ * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT
+ * HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS
+ * FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR
+ * DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
+ * TRADEMARKS OR OTHER RIGHTS.
+ *
+ * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
+ * OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
+ * DOCUMENTATION.
+ *
+ * The name and trademarks of copyright holders may NOT be used in
+ * advertising or publicity pertaining to the software without specific,
+ * written prior permission. Title to copyright in this software and any
+ * associated documentation will at all times remain with copyright
+ * holders.
+ */
+/**
+ * @class Class defining an RDFParser resource object tied to an RDFStore
+ *
+ * @author David Sheets <dsheets@mit.edu>
+ * @version 0.1
+ *
+ * @constructor
+ * @param {RDFStore} store An RDFStore object
+ */
+$rdf.RDFParser = function (store) {
+ var RDFParser = {};
+
+ /** Standard namespaces that we know how to handle @final
+ * @member RDFParser
+ */
+ RDFParser['ns'] = {'RDF':
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+ 'RDFS':
+ "http://www.w3.org/2000/01/rdf-schema#"}
+ /** DOM Level 2 node type magic numbers @final
+ * @member RDFParser
+ */
+ RDFParser['nodeType'] = {'ELEMENT': 1, 'ATTRIBUTE': 2, 'TEXT': 3,
+ 'CDATA_SECTION': 4, 'ENTITY_REFERENCE': 5,
+ 'ENTITY': 6, 'PROCESSING_INSTRUCTION': 7,
+ 'COMMENT': 8, 'DOCUMENT': 9, 'DOCUMENT_TYPE': 10,
+ 'DOCUMENT_FRAGMENT': 11, 'NOTATION': 12}
+
+ /**
+ * Frame class for namespace and base URI lookups
+ * Base lookups will always resolve because the parser knows
+ * the default base.
+ *
+ * @private
+ */
+ this['frameFactory'] = function (parser, parent, element) {
+ return {'NODE': 1,
+ 'ARC': 2,
+ 'parent': parent,
+ 'parser': parser,
+ 'store': parser['store'],
+ 'element': element,
+ 'lastChild': 0,
+ 'base': null,
+ 'lang': null,
+ 'node': null,
+ 'nodeType': null,
+ 'listIndex': 1,
+ 'rdfid': null,
+ 'datatype': null,
+ 'collection': false,
+
+ /** Terminate the frame and notify the store that we're done */
+ 'terminateFrame': function () {
+ if (this['collection']) {
+ this['node']['close']()
+ }
+ },
+
+ /** Add a symbol of a certain type to the this frame */
+ 'addSymbol': function (type, uri) {
+ uri = $rdf.Util.uri.join(uri, this['base'])
+ this['node'] = this['store']['sym'](uri)
+ this['nodeType'] = type
+ },
+
+ /** Load any constructed triples into the store */
+ 'loadTriple': function () {
+ if (this['parent']['parent']['collection']) {
+ this['parent']['parent']['node']['append'](this['node'])
+ }
+ else {
+ this['store']['add'](this['parent']['parent']['node'],
+ this['parent']['node'],
+ this['node'],
+ this['parser']['why'])
+ }
+ if (this['parent']['rdfid'] != null) { // reify
+ var triple = this['store']['sym'](
+ $rdf.Util.uri.join("#"+this['parent']['rdfid'],
+ this['base']))
+ this['store']['add'](triple,
+ this['store']['sym'](
+ RDFParser['ns']['RDF']
+ +"type"),
+ this['store']['sym'](
+ RDFParser['ns']['RDF']
+ +"Statement"),
+ this['parser']['why'])
+ this['store']['add'](triple,
+ this['store']['sym'](
+ RDFParser['ns']['RDF']
+ +"subject"),
+ this['parent']['parent']['node'],
+ this['parser']['why'])
+ this['store']['add'](triple,
+ this['store']['sym'](
+ RDFParser['ns']['RDF']
+ +"predicate"),
+ this['parent']['node'],
+ this['parser']['why'])
+ this['store']['add'](triple,
+ this['store']['sym'](
+ RDFParser['ns']['RDF']
+ +"object"),
+ this['node'],
+ this['parser']['why'])
+ }
+ },
+
+ /** Check if it's OK to load a triple */
+ 'isTripleToLoad': function () {
+ return (this['parent'] != null
+ && this['parent']['parent'] != null
+ && this['nodeType'] == this['NODE']
+ && this['parent']['nodeType'] == this['ARC']
+ && this['parent']['parent']['nodeType']
+ == this['NODE'])
+ },
+
+ /** Add a symbolic node to this frame */
+ 'addNode': function (uri) {
+ this['addSymbol'](this['NODE'],uri)
+ if (this['isTripleToLoad']()) {
+ this['loadTriple']()
+ }
+ },
+
+ /** Add a collection node to this frame */
+ 'addCollection': function () {
+ this['nodeType'] = this['NODE']
+ this['node'] = this['store']['collection']()
+ this['collection'] = true
+ if (this['isTripleToLoad']()) {
+ this['loadTriple']()
+ }
+ },
+
+ /** Add a collection arc to this frame */
+ 'addCollectionArc': function () {
+ this['nodeType'] = this['ARC']
+ },
+
+ /** Add a bnode to this frame */
+ 'addBNode': function (id) {
+ if (id != null) {
+ if (this['parser']['bnodes'][id] != null) {
+ this['node'] = this['parser']['bnodes'][id]
+ } else {
+ this['node'] = this['parser']['bnodes'][id] = this['store']['bnode']()
+ }
+ } else { this['node'] = this['store']['bnode']() }
+
+ this['nodeType'] = this['NODE']
+ if (this['isTripleToLoad']()) {
+ this['loadTriple']()
+ }
+ },
+
+ /** Add an arc or property to this frame */
+ 'addArc': function (uri) {
+ if (uri == RDFParser['ns']['RDF']+"li") {
+ uri = RDFParser['ns']['RDF']+"_"+this['parent']['listIndex']++
+ }
+ this['addSymbol'](this['ARC'], uri)
+ },
+
+ /** Add a literal to this frame */
+ 'addLiteral': function (value) {
+ if (this['parent']['datatype']) {
+ this['node'] = this['store']['literal'](
+ value, "", this['store']['sym'](
+ this['parent']['datatype']))
+ }
+ else {
+ this['node'] = this['store']['literal'](
+ value, this['lang'])
+ }
+ this['nodeType'] = this['NODE']
+ if (this['isTripleToLoad']()) {
+ this['loadTriple']()
+ }
+ }
+ }
+ }
+
+ //from the OpenLayers source .. needed to get around IE problems.
+ this['getAttributeNodeNS'] = function(node, uri, name) {
+ var attributeNode = null;
+ if(node.getAttributeNodeNS) {
+ attributeNode = node.getAttributeNodeNS(uri, name);
+ } else {
+ var attributes = node.attributes;
+ var potentialNode, fullName;
+ for(var i=0; i<attributes.length; ++i) {
+ potentialNode = attributes[i];
+ if(potentialNode.namespaceURI == uri) {
+ fullName = (potentialNode.prefix) ?
+ (potentialNode.prefix + ":" + name) : name;
+ if(fullName == potentialNode.nodeName) {
+ attributeNode = potentialNode;
+ break;
+ }
+ }
+ }
+ }
+ return attributeNode;
+ }
+
+ /** Our triple store reference @private */
+ this['store'] = store
+ /** Our identified blank nodes @private */
+ this['bnodes'] = {}
+ /** A context for context-aware stores @private */
+ this['why'] = null
+ /** Reification flag */
+ this['reify'] = false
+
+ /**
+ * Build our initial scope frame and parse the DOM into triples
+ * @param {DOMTree} document The DOM to parse
+ * @param {String} base The base URL to use
+ * @param {Object} why The context to which this resource belongs
+ */
+ this['parse'] = function (document, base, why) {
+ // alert('parse base:'+base);
+ var children = document['childNodes']
+
+ // clean up for the next run
+ this['cleanParser']()
+
+ // figure out the root element
+ //var root = document.documentElement; //this is faster, I think, cross-browser issue? well, DOM 2
+ if (document['nodeType'] == RDFParser['nodeType']['DOCUMENT']) {
+ for (var c=0; c<children['length']; c++) {
+ if (children[c]['nodeType']
+ == RDFParser['nodeType']['ELEMENT']) {
+ var root = children[c]
+ break
+ }
+ }
+ }
+ else if (document['nodeType'] == RDFParser['nodeType']['ELEMENT']) {
+ var root = document
+ }
+ else {
+ throw new Error("RDFParser: can't find root in " + base
+ + ". Halting. ")
+ return false
+ }
+
+ this['why'] = why
+
+
+ // our topmost frame
+
+ var f = this['frameFactory'](this)
+ this['base'] = base
+ f['base'] = base
+ f['lang'] = ''
+
+ this['parseDOM'](this['buildFrame'](f,root))
+ return true
+ }
+ this['parseDOM'] = function (frame) {
+ // a DOM utility function used in parsing
+ var elementURI = function (el) {
+ var result = "";
+ if (el['namespaceURI'] == null) {
+ throw new Error("RDF/XML syntax error: No namespace for "
+ +el['localName']+" in "+this.base)
+ }
+ if( el['namespaceURI'] ) {
+ result = result + el['namespaceURI'];
+ }
+ if( el['localName'] ) {
+ result = result + el['localName'];
+ } else if( el['nodeName'] ) {
+ if(el['nodeName'].indexOf(":")>=0)
+ result = result + el['nodeName'].split(":")[1];
+ else
+ result = result + el['nodeName'];
+ }
+ return result;
+ }
+ var dig = true // if we'll dig down in the tree on the next iter
+
+ while (frame['parent']) {
+ var dom = frame['element']
+ var attrs = dom['attributes']
+
+ if (dom['nodeType']
+ == RDFParser['nodeType']['TEXT']
+ || dom['nodeType']
+ == RDFParser['nodeType']['CDATA_SECTION']) {//we have a literal
+ frame['addLiteral'](dom['nodeValue'])
+ }
+ else if (elementURI(dom)
+ != RDFParser['ns']['RDF']+"RDF") { // not root
+ if (frame['parent'] && frame['parent']['collection']) {
+ // we're a collection element
+ frame['addCollectionArc']()
+ frame = this['buildFrame'](frame,frame['element'])
+ frame['parent']['element'] = null
+ }
+ if (!frame['parent'] || !frame['parent']['nodeType']
+ || frame['parent']['nodeType'] == frame['ARC']) {
+ // we need a node
+ var about =this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"about")
+ var rdfid =this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"ID")
+ if (about && rdfid) {
+ throw new Error("RDFParser: " + dom['nodeName']
+ + " has both rdf:id and rdf:about."
+ + " Halting. Only one of these"
+ + " properties may be specified on a"
+ + " node.");
+ }
+ if (about == null && rdfid) {
+ frame['addNode']("#"+rdfid['nodeValue'])
+ dom['removeAttributeNode'](rdfid)
+ }
+ else if (about == null && rdfid == null) {
+ var bnid = this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"nodeID")
+ if (bnid) {
+ frame['addBNode'](bnid['nodeValue'])
+ dom['removeAttributeNode'](bnid)
+ } else { frame['addBNode']() }
+ }
+ else {
+ frame['addNode'](about['nodeValue'])
+ dom['removeAttributeNode'](about)
+ }
+
+ // Typed nodes
+ var rdftype = this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"type")
+ if (RDFParser['ns']['RDF']+"Description"
+ != elementURI(dom)) {
+ rdftype = {'nodeValue': elementURI(dom)}
+ }
+ if (rdftype != null) {
+ this['store']['add'](frame['node'],
+ this['store']['sym'](
+ RDFParser['ns']['RDF']+"type"),
+ this['store']['sym'](
+ $rdf.Util.uri.join(
+ rdftype['nodeValue'],
+ frame['base'])),
+ this['why'])
+ if (rdftype['nodeName']){
+ dom['removeAttributeNode'](rdftype)
+ }
+ }
+
+ // Property Attributes
+ for (var x = attrs['length']-1; x >= 0; x--) {
+ this['store']['add'](frame['node'],
+ this['store']['sym'](
+ elementURI(attrs[x])),
+ this['store']['literal'](
+ attrs[x]['nodeValue'],
+ frame['lang']),
+ this['why'])
+ }
+ }
+ else { // we should add an arc (or implicit bnode+arc)
+ frame['addArc'](elementURI(dom))
+
+ // save the arc's rdf:ID if it has one
+ if (this['reify']) {
+ var rdfid = this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"ID")
+ if (rdfid) {
+ frame['rdfid'] = rdfid['nodeValue']
+ dom['removeAttributeNode'](rdfid)
+ }
+ }
+
+ var parsetype = this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"parseType")
+ var datatype = this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"datatype")
+ if (datatype) {
+ frame['datatype'] = datatype['nodeValue']
+ dom['removeAttributeNode'](datatype)
+ }
+
+ if (parsetype) {
+ var nv = parsetype['nodeValue']
+ if (nv == "Literal") {
+ frame['datatype']
+ = RDFParser['ns']['RDF']+"XMLLiteral"
+ // (this.buildFrame(frame)).addLiteral(dom)
+ // should work but doesn't
+ frame = this['buildFrame'](frame)
+ frame['addLiteral'](dom)
+ dig = false
+ }
+ else if (nv == "Resource") {
+ frame = this['buildFrame'](frame,frame['element'])
+ frame['parent']['element'] = null
+ frame['addBNode']()
+ }
+ else if (nv == "Collection") {
+ frame = this['buildFrame'](frame,frame['element'])
+ frame['parent']['element'] = null
+ frame['addCollection']()
+ }
+ dom['removeAttributeNode'](parsetype)
+ }
+
+ if (attrs['length'] != 0) {
+ var resource = this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"resource")
+ var bnid = this['getAttributeNodeNS'](dom,
+ RDFParser['ns']['RDF'],"nodeID")
+
+ frame = this['buildFrame'](frame)
+ if (resource) {
+ frame['addNode'](resource['nodeValue'])
+ dom['removeAttributeNode'](resource)
+ } else {
+ if (bnid) {
+ frame['addBNode'](bnid['nodeValue'])
+ dom['removeAttributeNode'](bnid)
+ } else { frame['addBNode']() }
+ }
+
+ for (var x = attrs['length']-1; x >= 0; x--) {
+ var f = this['buildFrame'](frame)
+ f['addArc'](elementURI(attrs[x]))
+ if (elementURI(attrs[x])
+ ==RDFParser['ns']['RDF']+"type"){
+ (this['buildFrame'](f))['addNode'](
+ attrs[x]['nodeValue'])
+ } else {
+ (this['buildFrame'](f))['addLiteral'](
+ attrs[x]['nodeValue'])
+ }
+ }
+ }
+ else if (dom['childNodes']['length'] == 0) {
+ (this['buildFrame'](frame))['addLiteral']("")
+ }
+ }
+ } // rdf:RDF
+
+ // dig dug
+ dom = frame['element']
+ while (frame['parent']) {
+ var pframe = frame
+ while (dom == null) {
+ frame = frame['parent']
+ dom = frame['element']
+ }
+ var candidate = dom['childNodes'][frame['lastChild']]
+ if (candidate == null || !dig) {
+ frame['terminateFrame']()
+ if (!(frame = frame['parent'])) { break } // done
+ dom = frame['element']
+ dig = true
+ }
+ else if ((candidate['nodeType']
+ != RDFParser['nodeType']['ELEMENT']
+ && candidate['nodeType']
+ != RDFParser['nodeType']['TEXT']
+ && candidate['nodeType']
+ != RDFParser['nodeType']['CDATA_SECTION'])
+ || ((candidate['nodeType']
+ == RDFParser['nodeType']['TEXT']
+ || candidate['nodeType']
+ == RDFParser['nodeType']['CDATA_SECTION'])
+ && dom['childNodes']['length'] != 1)) {
+ frame['lastChild']++
+ }
+ else { // not a leaf
+ frame['lastChild']++
+ frame = this['buildFrame'](pframe,
+ dom['childNodes'][frame['lastChild']-1])
+ break
+ }
+ }
+ } // while
+ }
+
+ /**
+ * Cleans out state from a previous parse run
+ * @private
+ */
+ this['cleanParser'] = function () {
+ this['bnodes'] = {}
+ this['why'] = null
+ }
+
+ /**
+ * Builds scope frame
+ * @private
+ */
+ this['buildFrame'] = function (parent, element) {
+ var frame = this['frameFactory'](this,parent,element)
+ if (parent) {
+ frame['base'] = parent['base']
+ frame['lang'] = parent['lang']
+ }
+ if (element == null
+ || element['nodeType'] == RDFParser['nodeType']['TEXT']
+ || element['nodeType'] == RDFParser['nodeType']['CDATA_SECTION']) {
+ return frame
+ }
+
+ var attrs = element['attributes']
+
+ var base = element['getAttributeNode']("xml:base")
+ if (base != null) {
+ frame['base'] = base['nodeValue']
+ element['removeAttribute']("xml:base")
+ }
+ var lang = element['getAttributeNode']("xml:lang")
+ if (lang != null) {
+ frame['lang'] = lang['nodeValue']
+ element['removeAttribute']("xml:lang")
+ }
+
+ // remove all extraneous xml and xmlns attributes
+ for (var x = attrs['length']-1; x >= 0; x--) {
+ if (attrs[x]['nodeName']['substr'](0,3) == "xml") {
+ if (attrs[x].name.slice(0,6)=='xmlns:') {
+ var uri = attrs[x].nodeValue;
+ // alert('base for namespac attr:'+this.base);
+ if (this.base) uri = $rdf.Util.uri.join(uri, this.base);
+ this.store.setPrefixForURI(attrs[x].name.slice(6),
+ uri);
+ }
+// alert('rdfparser: xml atribute: '+attrs[x].name) //@@
+ element['removeAttributeNode'](attrs[x])
+ }
+ }
+ return frame
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/rdfs.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,156 @@
+// RDFS Inference
+//
+// These are hand-written implementations of a backward-chaining reasoner over the RDFS axioms
+// These RDFS bits were moved from panes/categoryPane.js to a js/rdf/rdfs.js
+
+// @param seeds: a hash of NTs of classes to start with
+// @param predicate: The property to trace though
+// @param inverse: trace inverse direction
+
+$rdf.Formula.prototype.transitiveClosure = function(seeds, predicate, inverse){
+ var done = {}; // Classes we have looked up
+ var agenda = {};
+ for (var t in seeds) agenda[t] = seeds[t]; // Take a copy
+ for(;;) {
+ var t = (function(){for (var pickOne in agenda) {return pickOne;} return undefined}());
+ if (t == undefined) return done;
+ var sups = inverse ? this.each(undefined, predicate, this.fromNT(t))
+ : this.each(this.fromNT(t), predicate);
+ for (var i=0; i<sups.length; i++) {
+ var s = sups[i].toNT();
+ if (s in done) continue;
+ if (s in agenda) continue;
+ agenda[s] = agenda[t];
+ }
+ done[t] = agenda[t];
+ delete agenda[t];
+ }
+};
+
+
+// Find members of classes
+//
+// For this class or any subclass, anything which has it is its type
+// or is the object of something which has the tpe as its range, or subject
+// of something which has the type as its domain
+// We don't bother doing subproperty (yet?)as it doesn't seeem to be used much.
+
+$rdf.Formula.prototype.findMembersNT = function (thisClass) {
+ var seeds = {}; seeds [thisClass.toNT()] = true;
+ var types = this.transitiveClosure(seeds,
+ this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), true);
+ var members = {};
+ var kb = this;
+ for (t in types) {
+ this.statementsMatching(undefined, this.sym('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), this.fromNT(t))
+ .map(function(st){members[st.subject.toNT()] = st});
+ this.each(undefined, this.sym('http://www.w3.org/2000/01/rdf-schema#domain'), this.fromNT(t))
+ .map(function(pred){
+ kb.statementsMatching(undefined, pred).map(function(st){members[st.subject.toNT()] = st});
+ });
+ this.each(undefined, this.sym('http://www.w3.org/2000/01/rdf-schema#range'), this.fromNT(t))
+ .map(function(pred){
+ kb.statementsMatching(undefined, pred).map(function(st){members[st.object.toNT()] = st});
+ });
+ }
+ return members;
+};
+
+// Get all the Classes of which we can RDFS-infer the subject is a member
+// @returns a hash of URIS
+
+$rdf.Formula.prototype.findTypeURIs = function (subject) {
+ return this.NTtoURI(this.findTypesNT(subject));
+}
+
+$rdf.Formula.prototype.NTtoURI = function (t) {
+ var uris = {};
+ for (nt in t) {
+ if (nt[0] == '<') uris[nt.slice(1,-1)] = t[nt];
+ }
+ return uris;
+}
+
+$rdf.Formula.prototype.findTypesNT = function (subject) {
+// Get all the Classes of which we can RDFS-infer the subject is a member
+// ** @@ This will loop is there is a class subclass loop (Sublass loops are not illegal)
+// Returns a hash table where key is NT of type and value is statement why we think so.
+// Does NOT return terms, returns URI strings.
+// We use NT representations inthis version because they handle blank nodes.
+
+ var sts = this.statementsMatching(subject, undefined, undefined); // fast
+ var rdftype = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
+ var types = [];
+ for (var i=0; i < sts.length; i++) {
+ st = sts[i];
+ if (st.predicate.uri == rdftype) {
+ types[st.object.toNT()] = st;
+ } else {
+ // $rdf.log.warn('types: checking predicate ' + st.predicate.uri);
+ var ranges = this.each(st.predicate, this.sym('http://www.w3.org/2000/01/rdf-schema#domain'))
+ for (var j=0; j<ranges.length; j++) {
+ types[ranges[j].toNT()] = st; // A pointer to one part of the inference only
+ }
+ }
+ }
+ var sts = this.statementsMatching(undefined, undefined, subject); // fast
+ for (var i=0; i < sts.length; i++) {
+ st = sts[i];
+ var domains = this.each(st.predicate, this.sym('http://www.w3.org/2000/01/rdf-schema#range'))
+ for (var j=0; j < domains.length; j++) {
+ types[domains[j].toNT()] = st;
+ }
+ }
+ return this.transitiveClosure(types,
+ this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), false);
+};
+
+/* Find the types in the list which have no *stored* supertypes
+** We exclude the universal class, owl:Things and rdf:Resource, as it is not information-free.*/
+
+$rdf.Formula.prototype.topTypeURIs = function(types) {
+ var tops = [];
+ for (var u in types) {
+ var sups = this.each(this.sym(u), this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'));
+ var k = 0
+ for (var j=0; j < sups.length; j++) {
+ if (sups[j].uri != 'http://www.w3.org/2000/01/rdf-schema#Resource') {
+ k++; break;
+ }
+ }
+ if (!k) tops[u] = types[u];
+ }
+ if (tops['http://www.w3.org/2000/01/rdf-schema#Resource'])
+ delete tops['http://www.w3.org/2000/01/rdf-schema#Resource'];
+ if (tops['http://www.w3.org/2002/07/owl#Thing'])
+ delete tops['http://www.w3.org/2002/07/owl#Thing'];
+ return tops;
+}
+
+/* Find the types in the list which have no *stored* subtypes
+** These are a set of classes which provide by themselves complete
+** information -- the other classes are redundant for those who
+** know the class DAG.
+*/
+
+$rdf.Formula.prototype.bottomTypeURIs = function(types) {
+ var bots = [];
+ for (var u in types) {
+ var subs = this.each(undefined, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'),this.sym(u));
+ var bottom = true;
+ for (var i=0; i<subs.length; i++) {
+ if (subs[i].uri in types) {
+ bottom = false;
+ break;
+ }
+ }
+ if (bottom) bots[u] = types[u];
+ }
+ return bots;
+}
+
+
+
+//ends
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/serialize.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,785 @@
+/* Serialization of RDF Graphs
+**
+** Tim Berners-Lee 2006
+** This is or was http://dig.csail.mit.edu/2005/ajar/ajaw/js/rdf/serialize.js
+**
+** Bug: can't serialize http://data.semanticweb.org/person/abraham-bernstein/rdf
+** in XML (from mhausenblas)
+*/
+
+// @@@ Check the whole toStr thing tosee whetehr it still makes sense -- tbl
+//
+$rdf.Serializer = function() {
+
+var __Serializer = function( store ){
+ this.flags = "";
+ this.base = null;
+ this.prefixes = [];
+ this.keywords = ['a']; // The only one we generate at the moment
+ this.prefixchars = "abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ this.incoming = null; // Array not calculated yet
+ this.formulas = []; // remebering original formulae from hashes
+ this.store = store;
+
+ /* pass */
+}
+
+var Serializer = function( store ) {return new __Serializer( store )};
+
+__Serializer.prototype.setBase = function(base)
+ { this.base = base };
+
+__Serializer.prototype.setFlags = function(flags)
+ { this.flags = flags?flags: '' };
+
+
+__Serializer.prototype.toStr = function(x) {
+ var s = x.toNT();
+ if (x.termType == 'formula') {
+ this.formulas[s] = x; // remember as reverse does not work
+ }
+ return s;
+};
+
+__Serializer.prototype.fromStr = function(s) {
+ if (s[0] == '{') {
+ var x = this.formulas[s];
+ if (!x) alert('No formula object for '+s)
+ return x;
+ }
+ return this.store.fromNT(s);
+};
+
+
+
+
+
+/* Accumulate Namespaces
+**
+** These are only hints. If two overlap, only one gets used
+** There is therefore no guarantee in general.
+*/
+
+__Serializer.prototype.suggestPrefix = function(prefix, uri) {
+ this.prefixes[uri] = prefix;
+}
+
+// Takes a namespace -> prefix map
+__Serializer.prototype.suggestNamespaces = function(namespaces) {
+ for (var px in namespaces) {
+ this.prefixes[namespaces[px]] = px;
+ }
+}
+
+// Make up an unused prefix for a random namespace
+__Serializer.prototype.makeUpPrefix = function(uri) {
+ var p = uri;
+ var namespaces = [];
+ var pok;
+ var sz = this;
+
+ function canUse(pp) {
+ if (namespaces[pp]) return false; // already used
+
+ sz.prefixes[uri] = pp;
+ pok = pp;
+ return true
+ }
+ for (var ns in sz.prefixes) {
+ namespaces[sz.prefixes[ns]] = ns; // reverse index
+ }
+ if ('#/'.indexOf(p[p.length-1]) >= 0) p = p.slice(0, -1);
+ var slash = p.lastIndexOf('/');
+ if (slash >= 0) p = p.slice(slash+1);
+ var i = 0;
+ while (i < p.length)
+ if (sz.prefixchars.indexOf(p[i])) i++; else break;
+ p = p.slice(0,i);
+ if (p.length < 6 && canUse(p)) return pok; // exact i sbest
+ if (canUse(p.slice(0,3))) return pok;
+ if (canUse(p.slice(0,2))) return pok;
+ if (canUse(p.slice(0,4))) return pok;
+ if (canUse(p.slice(0,1))) return pok;
+ if (canUse(p.slice(0,5))) return pok;
+ for (var i=0;; i++) if (canUse(p.slice(0,3)+i)) return pok;
+}
+
+
+
+// Todo:
+// - Sort the statements by subject, pred, object
+// - do stuff about the docu first and then (or first) about its primary topic.
+
+__Serializer.prototype.rootSubjects = function(sts) {
+ var incoming = [];
+ var subjects = [];
+ var sz = this;
+ var allBnodes = {};
+
+/* This scan is to find out which nodes will have to be the roots of trees
+** in the serialized form. This will be any symbols, and any bnodes
+** which hve more or less than one incoming arc, and any bnodes which have
+** one incoming arc but it is an uninterrupted loop of such nodes back to itself.
+** This should be kept linear time with repect to the number of statements.
+** Note it does not use any indexing of the store.
+*/
+
+
+ tabulator.log.debug('serialize.js Find bnodes with only one incoming arc\n')
+ for (var i = 0; i<sts.length; i++) {
+ var st = sts[i];
+ [ st.subject, st.predicate, st.object].map(function(y){
+ if (y.termType =='bnode'){allBnodes[y.toNT()] = true}});
+ var x = sts[i].object;
+ if (!incoming[x]) incoming[x] = [];
+ incoming[x].push(st.subject) // List of things which will cause this to be printed
+ var ss = subjects[sz.toStr(st.subject)]; // Statements with this as subject
+ if (!ss) ss = [];
+ ss.push(st);
+ subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula?
+ //$rdf.log.debug(' sz potential subject: '+sts[i].subject)
+ }
+
+ var roots = [];
+ for (var xNT in subjects) {
+ var x = sz.fromStr(xNT);
+ if ((x.termType != 'bnode') || !incoming[x] || (incoming[x].length != 1)){
+ roots.push(x);
+ //$rdf.log.debug(' sz actual subject -: ' + x)
+ continue;
+ }
+ }
+ this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas
+
+//////////// New bit for CONNECTED bnode loops:frootshash
+
+// This scans to see whether the serialization is gpoing to lead to a bnode loop
+// and at the same time accumulates a list of all bnodes mentioned.
+// This is in fact a cut down N3 serialization
+/*
+ tabulator.log.debug('serialize.js Looking for connected bnode loops\n')
+ for (var i=0; i<sts.length; i++) { // @@TBL
+ // dump('\t'+sts[i]+'\n');
+ }
+ var doneBnodesNT = {};
+ function dummyPropertyTree(subject, subjects, rootsHash) {
+ // dump('dummyPropertyTree('+subject+'...)\n');
+ var sts = subjects[sz.toStr(subject)]; // relevant statements
+ for (var i=0; i<sts.length; i++) {
+ dummyObjectTree(sts[i].object, subjects, rootsHash);
+ }
+ }
+
+ // Convert a set of statements into a nested tree of lists and strings
+ // @param force, "we know this is a root, do it anyway. It isn't a loop."
+ function dummyObjectTree(obj, subjects, rootsHash, force) {
+ // dump('dummyObjectTree('+obj+'...)\n');
+ if (obj.termType == 'bnode' && (subjects[sz.toStr(obj)] &&
+ (force || (rootsHash[obj.toNT()] == undefined )))) {// and there are statements
+ if (doneBnodesNT[obj.toNT()]) { // Ah-ha! a loop
+ throw "Serializer: Should be no loops "+obj;
+ }
+ doneBnodesNT[obj.toNT()] = true;
+ return dummyPropertyTree(obj, subjects, rootsHash);
+ }
+ return dummyTermToN3(obj, subjects, rootsHash);
+ }
+
+ // Scan for bnodes nested inside lists too
+ function dummyTermToN3(expr, subjects, rootsHash) {
+ if (expr.termType == 'bnode') doneBnodesNT[expr.toNT()] = true;
+ tabulator.log.debug('serialize: seen '+expr);
+ if (expr.termType == 'collection') {
+ for (i=0; i<expr.elements.length; i++) {
+ if (expr.elements[i].termType == 'bnode')
+ dummyObjectTree(expr.elements[i], subjects, rootsHash);
+ }
+ return;
+ }
+ }
+
+ // The tree for a subject
+ function dummySubjectTree(subject, subjects, rootsHash) {
+ // dump('dummySubjectTree('+subject+'...)\n');
+ if (subject.termType == 'bnode' && !incoming[subject])
+ return dummyObjectTree(subject, subjects, rootsHash, true); // Anonymous bnode subject
+ dummyTermToN3(subject, subjects, rootsHash);
+ dummyPropertyTree(subject, subjects, rootsHash);
+ }
+*/
+ // Now do the scan using existing roots
+ tabulator.log.debug('serialize.js Dummy serialize to check for missing nodes')
+ var rootsHash = {};
+ for (var i = 0; i< roots.length; i++) rootsHash[roots[i].toNT()] = true;
+/*
+ for (var i=0; i<roots.length; i++) {
+ var root = roots[i];
+ dummySubjectTree(root, subjects, rootsHash);
+ }
+ // dump('Looking for mising bnodes...\n')
+
+// Now in new roots for anythig not acccounted for
+// Now we check for any bndoes which have not been covered.
+// Such bnodes must be in isolated rings of pure bnodes.
+// They each have incoming link of 1.
+
+ tabulator.log.debug('serialize.js Looking for connected bnode loops\n')
+ for (;;) {
+ var bnt;
+ var found = null;
+ for (bnt in allBnodes) { // @@ Note: not repeatable. No canonicalisation
+ if (doneBnodesNT[bnt]) continue;
+ found = bnt; // Ah-ha! not covered
+ break;
+ }
+ if (found == null) break; // All done - no bnodes left out/
+ // dump('Found isolated bnode:'+found+'\n');
+ doneBnodesNT[bnt] = true;
+ var root = this.store.fromNT(found);
+ roots.push(root); // Add a new root
+ rootsHash[found] = true;
+ tabulator.log.debug('isolated bnode:'+found+', subjects[found]:'+subjects[found]+'\n');
+ if (subjects[found] == undefined) {
+ for (var i=0; i<sts.length; i++) {
+ // dump('\t'+sts[i]+'\n');
+ }
+ throw "Isolated node should be a subject" +found;
+ }
+ dummySubjectTree(root, subjects, rootsHash); // trace out the ring
+ }
+ // dump('Done bnode adjustments.\n')
+*/
+ return {'roots':roots, 'subjects':subjects,
+ 'rootsHash': rootsHash, 'incoming': incoming};
+}
+
+////////////////////////////////////////////////////////
+
+__Serializer.prototype.toN3 = function(f) {
+ return this.statementsToN3(f.statements);
+}
+
+__Serializer.prototype._notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~";
+__Serializer.prototype._notNameChars =
+ ( __Serializer.prototype._notQNameChars + ":" ) ;
+
+
+__Serializer.prototype.statementsToN3 = function(sts) {
+ var indent = 4;
+ var width = 80;
+ var sz = this;
+
+ var namespaceCounts = []; // which have been used
+
+ predMap = {
+ 'http://www.w3.org/2002/07/owl#sameAs': '=',
+ 'http://www.w3.org/2000/10/swap/log#implies': '=>',
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'a'
+ }
+
+
+
+
+ ////////////////////////// Arrange the bits of text
+
+ var spaces=function(n) {
+ var s='';
+ for(var i=0; i<n; i++) s+=' ';
+ return s
+ }
+
+ treeToLine = function(tree) {
+ var str = '';
+ for (var i=0; i<tree.length; i++) {
+ var branch = tree[i];
+ var s2 = (typeof branch == 'string') ? branch : treeToLine(branch);
+ if (i!=0 && s2 != ',' && s2 != ';' && s2 != '.') str += ' ';
+ str += s2;
+ }
+ return str;
+ }
+
+ // Convert a nested tree of lists and strings to a string
+ treeToString = function(tree, level) {
+ var str = '';
+ var lastLength = 100000;
+ if (!level) level = 0;
+ for (var i=0; i<tree.length; i++) {
+ var branch = tree[i];
+ if (typeof branch != 'string') {
+ var substr = treeToString(branch, level +1);
+ if (
+ substr.length < 10*(width-indent*level)
+ && substr.indexOf('"""') < 0) {// Don't mess up multiline strings
+ var line = treeToLine(branch);
+ if (line.length < (width-indent*level)) {
+ branch = ' '+line; // @@ Hack: treat as string below
+ substr = ''
+ }
+ }
+ if (substr) lastLength = 10000;
+ str += substr;
+ }
+ if (typeof branch == 'string') {
+ if (branch.length == '1' && str.slice(-1) == '\n') {
+ if (",.;".indexOf(branch) >=0) {
+ str = str.slice(0,-1) + branch + '\n'; // slip punct'n on end
+ lastLength += 1;
+ continue;
+ } else if ("])}".indexOf(branch) >=0) {
+ str = str.slice(0,-1) + ' ' + branch + '\n';
+ lastLength += 2;
+ continue;
+ }
+ }
+ if (lastLength < (indent*level+4)) { // continue
+ str = str.slice(0,-1) + ' ' + branch + '\n';
+ lastLength += branch.length + 1;
+ } else {
+ var line = spaces(indent*level) +branch;
+ str += line +'\n';
+ lastLength = line.length;
+ }
+
+ } else { // not string
+ }
+ }
+ return str;
+ };
+
+ ////////////////////////////////////////////// Structure for N3
+
+
+ // Convert a set of statements into a nested tree of lists and strings
+ function statementListToTree(statements) {
+ // print('Statement tree for '+statements.length);
+ var res = [];
+ var stats = sz.rootSubjects(statements);
+ var roots = stats.roots;
+ var results = []
+ for (var i=0; i<roots.length; i++) {
+ var root = roots[i];
+ results.push(subjectTree(root, stats))
+ }
+ return results;
+ }
+
+ // The tree for a subject
+ function subjectTree(subject, stats) {
+ if (subject.termType == 'bnode' && !stats.incoming[subject])
+ return objectTree(subject, stats, true).concat(["."]); // Anonymous bnode subject
+ return [ termToN3(subject, stats) ].concat([propertyTree(subject, stats)]).concat(["."]);
+ }
+
+
+ // The property tree for a single subject or anonymous node
+ function propertyTree(subject, stats) {
+ // print('Proprty tree for '+subject);
+ var results = []
+ var lastPred = null;
+ var sts = stats.subjects[sz.toStr(subject)]; // relevant statements
+ if (typeof sts == 'undefined') {
+ throw('Cant find statements for '+subject);
+ }
+ sts.sort();
+ var objects = [];
+ for (var i=0; i<sts.length; i++) {
+ var st = sts[i];
+ if (st.predicate.uri == lastPred) {
+ objects.push(',');
+ } else {
+ if (lastPred) {
+ results=results.concat([objects]).concat([';']);
+ objects = [];
+ }
+ results.push(predMap[st.predicate.uri] ?
+ predMap[st.predicate.uri] : termToN3(st.predicate, stats));
+ }
+ lastPred = st.predicate.uri;
+ objects.push(objectTree(st.object, stats));
+ }
+ results=results.concat([objects]);
+ return results;
+ }
+
+ function objectTree(obj, stats, force) {
+ if (obj.termType == 'bnode' &&
+ stats.subjects[sz.toStr(obj)] && // and there are statements
+ (force || stats.rootsHash[obj.toNT()] == undefined)) // and not a root
+ return ['['].concat(propertyTree(obj, stats)).concat([']']);
+ return termToN3(obj, stats);
+ }
+
+ function termToN3(expr, stats) {
+ switch(expr.termType) {
+ case 'bnode':
+ case 'variable': return expr.toNT();
+ case 'literal':
+ var str = stringToN3(expr.value);
+ if (expr.lang) str+= '@' + expr.lang;
+ if (expr.datatype) str+= '^^' + termToN3(expr.datatype, stats);
+ return str;
+ case 'symbol':
+ return symbolToN3(expr.uri);
+ case 'formula':
+ var res = ['{'];
+ res = res.concat(statementListToTree(expr.statements));
+ return res.concat(['}']);
+ case 'collection':
+ var res = ['('];
+ for (i=0; i<expr.elements.length; i++) {
+ res.push( [ objectTree(expr.elements[i], stats) ]);
+ }
+ res.push(')');
+ return res;
+
+ default:
+ throw "Internal: termToN3 cannot handle "+expr+" of termType+"+expr.termType
+ return ''+expr;
+ }
+ }
+
+ ////////////////////////////////////////////// Atomic Terms
+
+ // Deal with term level things and nesting with no bnode structure
+
+ function symbolToN3(uri) { // c.f. symbolString() in notation3.py
+ var j = uri.indexOf('#');
+ if (j<0 && sz.flags.indexOf('/') < 0) {
+ j = uri.lastIndexOf('/');
+ }
+ if (j >= 0 && sz.flags.indexOf('p') < 0) { // Can split at namespace
+ var canSplit = true;
+ for (var k=j+1; k<uri.length; k++) {
+ if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >=0) {
+ canSplit = false; break;
+ }
+ }
+ if (canSplit) {
+ var localid = uri.slice(j+1);
+ var namesp = uri.slice(0,j+1);
+ if (sz.defaultNamespace && sz.defaultNamespace == namesp
+ && sz.flags.indexOf('d') < 0) {// d -> suppress default
+ if (sz.flags.indexOf('k') >= 0 &&
+ sz.keyords.indexOf(localid) <0)
+ return localid;
+ return ':' + localid;
+ }
+ var prefix = sz.prefixes[namesp];
+ if (prefix) {
+ namespaceCounts[namesp] = true;
+ return prefix + ':' + localid;
+ }
+ if (uri.slice(0, j) == sz.base)
+ return '<#' + localid + '>';
+ // Fall though if can't do qname
+ }
+ }
+ if (sz.flags.indexOf('r') < 0 && sz.base)
+ uri = $rdf.Util.uri.refTo(sz.base, uri);
+ else if (sz.flags.indexOf('u') >= 0)
+ uri = backslashUify(uri);
+ else uri = hexify(uri);
+ return '<'+uri+'>';
+ }
+
+ function prefixDirectives() {
+ str = '';
+ if (sz.defaultNamespace)
+ str += '@prefix : <'+sz.defaultNamespace+'>.\n';
+ for (var ns in namespaceCounts) {
+ str += '@prefix ' + sz.prefixes[ns] + ': <'+ns+'>.\n';
+ }
+ return str + '\n';
+ }
+
+ // stringToN3: String escaping for N3
+ //
+ var forbidden1 = new RegExp(/[\\"\b\f\r\v\t\n\u0080-\uffff]/gm);
+ var forbidden3 = new RegExp(/[\\"\b\f\r\v\u0080-\uffff]/gm);
+ function stringToN3(str, flags) {
+ if (!flags) flags = "e";
+ var res = '', i=0, j=0;
+ var delim;
+ var forbidden;
+ if (str.length > 20 // Long enough to make sense
+ && str.slice(-1) != '"' // corner case'
+ && flags.indexOf('n') <0 // Force single line
+ && (str.indexOf('\n') >0 || str.indexOf('"') > 0)) {
+ delim = '"""';
+ forbidden = forbidden3;
+ } else {
+ delim = '"';
+ forbidden = forbidden1;
+ }
+ for(i=0; i<str.length;) {
+ forbidden.lastIndex = 0;
+ var m = forbidden.exec(str.slice(i));
+ if (m == null) break;
+ j = i + forbidden.lastIndex -1;
+ res += str.slice(i,j);
+ var ch = str[j];
+ if (ch=='"' && delim == '"""' && str.slice(j,j+3) != '"""') {
+ res += ch;
+ } else {
+ var k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)?
+ if (k >= 0) {
+ res += "\\" + 'bfrtvn\\"'[k];
+ } else {
+ if (flags.indexOf('e')>=0) {
+ res += '\\u' + ('000'+
+ ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4)
+ } else { // no 'e' flag
+ res += ch;
+ }
+ }
+ }
+ i = j+1;
+ }
+ return delim + res + str.slice(i) + delim
+ }
+
+ // Body of toN3:
+
+ var tree = statementListToTree(sts);
+ return prefixDirectives() + treeToString(tree, -1);
+
+}
+
+// String ecaping utilities
+
+function hexify(str) { // also used in parser
+// var res = '';
+// for (var i=0; i<str.length; i++) {
+// k = str.charCodeAt(i);
+// if (k>126 || k<33)
+// res += '%' + ('0'+n.toString(16)).slice(-2); // convert to upper?
+// else
+// res += str[i];
+// }
+// return res;
+ return encodeURI(str);
+}
+
+
+function backslashUify(str) {
+ var res = '';
+ for (var i=0; i<str.length; i++) {
+ k = str.charCodeAt(i);
+ if (k>65535)
+ res += '\\U' + ('00000000'+n.toString(16)).slice(-8); // convert to upper?
+ else if (k>126)
+ res += '\\u' + ('0000'+n.toString(16)).slice(-4);
+ else
+ res += str[i];
+ }
+ return res;
+}
+
+
+
+
+
+
+//////////////////////////////////////////////// XML serialization
+
+__Serializer.prototype.statementsToXML = function(sts) {
+ var indent = 4;
+ var width = 80;
+ var sz = this;
+
+ var namespaceCounts = []; // which have been used
+ namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true;
+
+ ////////////////////////// Arrange the bits of XML text
+
+ var spaces=function(n) {
+ var s='';
+ for(var i=0; i<n; i++) s+=' ';
+ return s
+ }
+
+ XMLtreeToLine = function(tree) {
+ var str = '';
+ for (var i=0; i<tree.length; i++) {
+ var branch = tree[i];
+ var s2 = (typeof branch == 'string') ? branch : XMLtreeToLine(branch);
+ str += s2;
+ }
+ return str;
+ }
+
+ // Convert a nested tree of lists and strings to a string
+ XMLtreeToString = function(tree, level) {
+ var str = '';
+ var lastLength = 100000;
+ if (!level) level = 0;
+ for (var i=0; i<tree.length; i++) {
+ var branch = tree[i];
+ if (typeof branch != 'string') {
+ var substr = XMLtreeToString(branch, level +1);
+ if (
+ substr.length < 10*(width-indent*level)
+ && substr.indexOf('"""') < 0) {// Don't mess up multiline strings
+ var line = XMLtreeToLine(branch);
+ if (line.length < (width-indent*level)) {
+ branch = ' '+line; // @@ Hack: treat as string below
+ substr = ''
+ }
+ }
+ if (substr) lastLength = 10000;
+ str += substr;
+ }
+ if (typeof branch == 'string') {
+ if (lastLength < (indent*level+4)) { // continue
+ str = str.slice(0,-1) + ' ' + branch + '\n';
+ lastLength += branch.length + 1;
+ } else {
+ var line = spaces(indent*level) +branch;
+ str += line +'\n';
+ lastLength = line.length;
+ }
+
+ } else { // not string
+ }
+ }
+ return str;
+ };
+
+ function statementListToXMLTree(statements) {
+ sz.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
+ var stats = sz.rootSubjects(statements);
+ var roots = stats.roots;
+ results = []
+ for (var i=0; i<roots.length; i++) {
+ root = roots[i];
+ results.push(subjectXMLTree(root, stats))
+ }
+ return results;
+ }
+
+ function escapeForXML(str) {
+ if (typeof str == 'undefined') return '@@@undefined@@@@';
+ return str.replace(/&/g, '&').replace(/</g, '<')
+ }
+
+ function relURI(term) {
+ return escapeForXML((sz.base) ? $rdf.Util.uri.refTo(this.base, term.uri) : term.uri);
+ }
+
+ // The tree for a subject
+ function subjectXMLTree(subject, stats) {
+ var start
+ if (subject.termType == 'bnode') {
+ if (!stats.incoming[subject]) { // anonymous bnode
+ var start = '<rdf:Description>';
+ } else {
+ var start = '<rdf:Description rdf:nodeID="'+subject.toNT().slice(2)+'">';
+ }
+ } else {
+ var start = '<rdf:Description rdf:about="'+ relURI(subject)+'">';
+ }
+
+ return [ start ].concat(
+ [propertyXMLTree(subject, stats)]).concat(["</rdf:Description>"]);
+ }
+ function collectionXMLTree(subject, stats) {
+ res = []
+ for (var i=0; i< subject.elements.length; i++) {
+ res.push(subjectXMLTree(subject.elements[i], stats));
+ }
+ return res;
+ }
+
+ // The property tree for a single subject or anonymos node
+ function propertyXMLTree(subject, stats) {
+ var results = []
+ var sts = stats.subjects[sz.toStr(subject)]; // relevant statements
+ if (sts == undefined) return results; // No relevant statements
+ sts.sort();
+ for (var i=0; i<sts.length; i++) {
+ var st = sts[i];
+ switch (st.object.termType) {
+ case 'bnode':
+ if(stats.rootsHash[st.object.toNT()]) { // This bnode has been done as a root -- no content here @@ what bout first time
+ results = results.concat(['<'+qname(st.predicate)+' rdf:nodeID="'+st.object.toNT().slice(2)+'">',
+ '</'+qname(st.predicate)+'>']);
+ } else {
+ results = results.concat(['<'+qname(st.predicate)+' rdf:parseType="Resource">',
+ propertyXMLTree(st.object, stats),
+ '</'+qname(st.predicate)+'>']);
+ }
+ break;
+ case 'symbol':
+ results = results.concat(['<'+qname(st.predicate)+' rdf:resource="'
+ + relURI(st.object)+'"/>']);
+ break;
+ case 'literal':
+ results = results.concat(['<'+qname(st.predicate)
+ + (st.object.datatype ? ' rdf:datatype="'+escapeForXML(st.object.datatype.uri)+'"' : '')
+ + (st.object.lang ? ' xml:lang="'+st.object.lang+'"' : '')
+ + '>' + escapeForXML(st.object.value)
+ + '</'+qname(st.predicate)+'>']);
+ break;
+ case 'collection':
+ results = results.concat(['<'+qname(st.predicate)+' rdf:parseType="Collection">',
+ collectionXMLTree(st.object, stats),
+ '</'+qname(st.predicate)+'>']);
+ break;
+ default:
+ throw "Can't serialize object of type "+st.object.termType +" into XML";
+
+ } // switch
+ }
+ return results;
+ }
+
+ function qname(term) {
+ var uri = term.uri;
+
+ var j = uri.indexOf('#');
+ if (j<0 && sz.flags.indexOf('/') < 0) {
+ j = uri.lastIndexOf('/');
+ }
+ if (j < 0) throw ("Cannot make qname out of <"+uri+">")
+
+ var canSplit = true;
+ for (var k=j+1; k<uri.length; k++) {
+ if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >=0) {
+ throw ('Invalid character "'+uri[k] +'" cannot be in XML qname for URI: '+uri);
+ }
+ }
+ var localid = uri.slice(j+1);
+ var namesp = uri.slice(0,j+1);
+ if (sz.defaultNamespace && sz.defaultNamespace == namesp
+ && sz.flags.indexOf('d') < 0) {// d -> suppress default
+ return localid;
+ }
+ var prefix = sz.prefixes[namesp];
+ if (!prefix) prefix = sz.makeUpPrefix(namesp);
+ namespaceCounts[namesp] = true;
+ return prefix + ':' + localid;
+// throw ('No prefix for namespace "'+namesp +'" for XML qname for '+uri+', namespaces: '+sz.prefixes+' sz='+sz);
+ }
+
+ // Body of toXML:
+
+ var tree = statementListToXMLTree(sts);
+ var str = '<rdf:RDF';
+ if (sz.defaultNamespace)
+ str += ' xmlns="'+escapeForXML(sz.defaultNamespace)+'"';
+ for (var ns in namespaceCounts) {
+ str += '\n xmlns:' + sz.prefixes[ns] + '="'+escapeForXML(ns)+'"';
+ }
+ str += '>';
+
+ var tree2 = [str, tree, '</rdf:RDF>']; //@@ namespace declrations
+ return XMLtreeToString(tree2, -1);
+
+
+} // End @@ body
+
+return Serializer;
+
+}();
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/sparql.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,663 @@
+//Converting between SPARQL queries and the $rdf query API
+
+/*
+
+function SQuery ()
+{
+ this.terms = [];
+ return this;
+}
+
+STerm.prototype.toString = STerm.val;
+SQuery.prototype.add = function (str) {this.terms.push()}*/
+
+$rdf.queryToSPARQL = function(query)
+{
+ var indent=0;
+ function getSelect (query)
+ {
+ var str=addIndent()+"SELECT ";
+ for (i=0;i<query.vars.length;i++)
+ str+=query.vars[i]+" ";
+ str+="\n";
+ return str;
+ }
+
+ function getPattern (pat)
+ {
+ var str = "";
+ var st = pat.statements;
+ for (x in st)
+ {
+ $rdf.log.debug("Found statement: "+st)
+ str+=addIndent()+st[x]+"\n";
+ }
+ return str;
+ }
+
+ function getConstraints (pat)
+ {
+ var str="";
+ for (v in pat.constraints)
+ {
+ var foo = pat.constraints[v]
+ str+=addIndent()+"FILTER ( "+foo.describe(v)+" ) "+"\n"
+ }
+ return str;
+ }
+
+ function getOptionals (pat)
+ {
+ var str = ""
+ for (var x=0;x<pat.optional.length;x++)
+ {
+ //alert(pat.optional.termType)
+ $rdf.log.debug("Found optional query")
+ str+= addIndent()+"OPTIONAL { "+"\n";
+ indent++;
+ str+= getPattern (pat.optional[x])
+ str+= getConstraints (pat.optional[x])
+ str+= getOptionals (pat.optional[x])
+ indent--;
+ str+=addIndent()+"}"+"\n";
+ }
+ return str;
+ }
+
+ function getWhere (pat)
+ {
+ var str = addIndent() + "WHERE \n" + "{ \n";
+ indent++;
+ str+= getPattern (pat);
+ str+= getConstraints (pat);
+ str+= getOptionals (pat);
+ indent--;
+ str+="}"
+ return str;
+ }
+
+ function addIndent()
+ {
+ var str="";
+ for (i=0;i<indent;i++)
+ str+=" ";
+ return str;
+ }
+
+ function getSPARQL (query)
+ {
+ return getSelect(query) + getWhere(query.pat);
+ }
+
+ return getSPARQL (query)
+}
+
+/**
+ * @SPARQL: SPARQL text that is converted to a query object which is returned.
+ * @testMode: testing flag. Prevents loading of sources.
+ */
+
+$rdf.SPARQLToQuery = function(SPARQL, testMode, kb)
+{
+ //AJAR_ClearTable();
+ var variableHash = []
+ function makeVar(name) {
+ if (variableHash[name])
+ return variableHash[name]
+ var newVar = kb.variable(name);
+ variableHash[name] = newVar;
+ return newVar
+ }
+
+ //term type functions
+ function isRealText(term) { return (typeof term == 'string' && term.match(/[^ \n\t]/)) }
+ function isVar(term) { return (typeof term == 'string' && term.match(/^[\?\$]/)) }
+ function fixSymbolBrackets(term) { if (typeof term == 'string') return term.replace(/^</,"<").replace(/>$/,">"); else return term }
+ function isSymbol(term) { return (typeof term == 'string' && term.match(/^<[^>]*>$/)) }
+ function isBnode(term) { return (typeof term == 'string' && (term.match(/^_:/)||term.match(/^$/))) }
+ function isPrefix(term) { return (typeof term == 'string' && term.match(/:$/)) }
+ function isPrefixedSymbol(term) { return (typeof term == 'string' && term.match(/^:|^[^_][^:]*:/)) }
+ function getPrefix(term) { var a = term.split(":"); return a[0] }
+ function getSuffix(term) { var a = term.split(":"); return a[1] }
+ function removeBrackets(term) { if (isSymbol(term)) {return term.slice(1,term.length-1)} else return term }
+ //takes a string and returns an array of strings and Literals in the place of literals
+ function parseLiterals (str)
+ {
+ //var sin = (str.indexOf(/[ \n]\'/)==-1)?null:str.indexOf(/[ \n]\'/), doub = (str.indexOf(/[ \n]\"/)==-1)?null:str.indexOf(/[ \n]\"/);
+ var sin = (str.indexOf("'")==-1)?null:str.indexOf("'"), doub = (str.indexOf('"')==-1)?null:str.indexOf('"');
+ //alert("S: "+sin+" D: "+doub);
+ if (!sin && !doub)
+ {
+ var a = new Array(1);
+ a[0]=str;
+ return a;
+ }
+ var res = new Array(2);
+ if (!sin || (doub && doub<sin)) {var br='"'; var ind = doub}
+ else if (!doub || (sin && sin<doub)) {var br="'"; var ind = sin}
+ else {$rdf.log.error ("SQARQL QUERY OOPS!"); return res}
+ res[0] = str.slice(0,ind);
+ var end = str.slice(ind+1).indexOf(br);
+ if (end==-1)
+ {
+ $rdf.log.error("SPARQL parsing error: no matching parentheses in literal "+str);
+ return str;
+ }
+ //alert(str.slice(end+ind+2).match(/^\^\^/))
+ if (str.slice(end+ind+2).match(/^\^\^/))
+ {
+ var end2 = str.slice(end+ind+2).indexOf(" ")
+ //alert(end2)
+ res[1]=kb.literal(str.slice(ind+1,ind+1+end),"",kb.sym(removeBrackets(str.slice(ind+4+end,ind+2+end+end2))))
+ //alert(res[1].datatype.uri)
+ res = res.concat(parseLiterals(str.slice(end+ind+3+end2)));
+ }
+ else if (str.slice(end+ind+2).match(/^@/))
+ {
+ var end2 = str.slice(end+ind+2).indexOf(" ")
+ //alert(end2)
+ res[1]=kb.literal(str.slice(ind+1,ind+1+end),str.slice(ind+3+end,ind+2+end+end2),null)
+ //alert(res[1].datatype.uri)
+ res = res.concat(parseLiterals(str.slice(end+ind+2+end2)));
+ }
+
+ else
+ {
+ res[1]=kb.literal(str.slice(ind+1,ind+1+end),"",null)
+ $rdf.log.info("Literal found: "+res[1]);
+ res = res.concat(parseLiterals(str.slice(end+ind+2))); //finds any other literals
+ }
+ return res;
+ }
+
+
+ function spaceDelimit (str)
+ {
+ var str = str.replace(/\(/g," ( ").replace(/\)/g," ) ").replace(/</g," <").replace(/>/g,"> ").replace(/{/g," { ").replace(/}/g," } ").replace(/[\t\n\r]/g," ").replace(/; /g," ; ").replace(/\. /g," . ").replace(/, /g," , ");
+ $rdf.log.info("New str into spaceDelimit: \n"+str)
+ var res=[];
+ var br = str.split(" ");
+ for (x in br)
+ {
+ if (isRealText(br[x]))
+ res = res.concat(br[x]);
+ }
+ return res;
+ }
+
+ function replaceKeywords(input) {
+ var strarr = input;
+ for (var x=0;x<strarr.length;x++)
+ {
+ if (strarr[x]=="a") strarr[x] = "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>";
+ if (strarr[x]=="is" && strarr[x+2]=="of")
+ {
+ strarr.splice(x,1);
+ strarr.splice(x+1,1) ;
+ var s = strarr[x-1];
+ strarr[x-1] = strarr[x+1];
+ strarr[x+1] = s;
+ }
+ }
+ return strarr;
+ }
+
+ function toTerms (input)
+ {
+ var res = []
+ for (var x=0;x<input.length;x++)
+ {
+ if (typeof input[x] != 'string') { res[x]=input[x]; continue }
+ input[x]=fixSymbolBrackets(input[x])
+ if (isVar(input[x]))
+ res[x] = makeVar(input[x].slice(1));
+ else if (isBnode(input[x]))
+ {
+ $rdf.log.info(input[x]+" was identified as a bnode.")
+ res[x] = kb.bnode();
+ }
+ else if (isSymbol(input[x]))
+ {
+ $rdf.log.info(input[x]+" was identified as a symbol.");
+ res[x] = kb.sym(removeBrackets(input[x]));
+ }
+ else if (isPrefixedSymbol(input[x]))
+ {
+ $rdf.log.info(input[x]+" was identified as a prefixed symbol");
+ if (prefixes[getPrefix(input[x])])
+ res[x] = kb.sym(input[x] = prefixes[getPrefix(input[x])]+getSuffix(input[x]));
+ else
+ {
+ $rdf.log.error("SPARQL error: "+input[x]+" with prefix "+getPrefix(input[x])+" does not have a correct prefix entry.")
+ res[x]=input[x]
+ }
+ }
+ else res[x]=input[x];
+ }
+ return res;
+ }
+
+ function tokenize (str)
+ {
+ var token1 = parseLiterals(str);
+ var token2=[];
+ for (x in token1)
+ {
+ if (typeof token1[x] == 'string')
+ token2=token2.concat(spaceDelimit(token1[x]));
+ else
+ token2=token2.concat(token1[x])
+ }
+ token2 = replaceKeywords(token2);
+ $rdf.log.info("SPARQL Tokens: "+token2);
+ return token2;
+ }
+
+ //CASE-INSENSITIVE
+ function arrayIndexOf (str,arr)
+ {
+ for (i=0; i<arr.length; i++)
+ {
+ if (typeof arr[i] != 'string') continue;
+ if (arr[i].toLowerCase()==str.toLowerCase())
+ return i;
+ }
+ //$rdf.log.warn("No instance of "+str+" in array "+arr);
+ return null;
+ }
+
+ //CASE-INSENSITIVE
+ function arrayIndicesOf (str,arr)
+ {
+ var ind = [];
+ for (i=0; i<arr.length; i++)
+ {
+ if (typeof arr[i] != 'string') continue;
+ if (arr[i].toLowerCase()==str.toLowerCase())
+ ind.push(i)
+ }
+ return ind;
+ }
+
+
+ function setVars (input,query)
+ {
+ $rdf.log.info("SPARQL vars: "+input);
+ for (x in input)
+ {
+ if (isVar(input[x]))
+ {
+ $rdf.log.info("Added "+input[x]+" to query variables from SPARQL");
+ var v = makeVar(input[x].slice(1));
+ query.vars.push(v);
+ v.label=input[x].slice(1);
+
+ }
+ else
+ $rdf.log.warn("Incorrect SPARQL variable in SELECT: "+input[x]);
+ }
+ }
+
+
+ function getPrefixDeclarations (input)
+ {
+
+ var prefInd = arrayIndicesOf ("PREFIX",input), res = [];
+ for (i in prefInd)
+ {
+ var a = input[prefInd[i]+1], b = input[prefInd[i]+2];
+ if (!isPrefix(a))
+ $rdf.log.error("Invalid SPARQL prefix: "+a);
+ else if (!isSymbol(b))
+ $rdf.log.error("Invalid SPARQL symbol: "+b);
+ else
+ {
+ $rdf.log.info("Prefix found: "+a+" -> "+b);
+ var pref = getPrefix(a), symbol = removeBrackets(b);
+ res[pref]=symbol;
+ }
+ }
+ return res;
+ }
+
+ function getMatchingBracket(arr,open,close)
+ {
+ $rdf.log.info("Looking for a close bracket of type "+close+" in "+arr);
+ var index = 0
+ for (i=0;i<arr.length;i++)
+ {
+ if (arr[i]==open) index++;
+ if (arr[i]==close) index--;
+ if (index<0) return i;
+ }
+ $rdf.log.error("Statement had no close parenthesis in SPARQL query");
+ return 0;
+ }
+
+
+
+ function constraintGreaterThan (value)
+ {
+ this.describe = function (varstr) { return varstr + " > "+value.toNT() }
+ this.test = function (term) {
+ if (term.value.match(/[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/))
+ return (parseFloat(term.value) > parseFloat(value));
+ else return (term.toNT() > value.toNT());
+ }
+ return this;
+ }
+
+ function constraintLessThan (value) //this is not the recommended usage. Should only work on literal, numeric, dateTime
+ {
+ this.describe = function (varstr) { return varstr + " < "+value.toNT() }
+ this.test = function (term) {
+ //this.describe = function (varstr) { return varstr + " < "+value }
+ if (term.value.match(/[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/))
+ return (parseFloat(term.value) < parseFloat(value));
+ else return (term.toNT() < value.toNT());
+ }
+ return this;
+ }
+
+ function constraintEqualTo (value) //This should only work on literals but doesn't.
+ {
+ this.describe = function (varstr) { return varstr + " = "+value.toNT() }
+ this.test = function (term) {
+ return value.sameTerm(term)
+ }
+ return this;
+ }
+
+ function constraintRegexp (value) //value must be a literal
+ {
+ this.describe = function (varstr) { return "REGEXP( '"+value+"' , "+varstr+" )"}
+ this.test=function(term) {
+ var str = value;
+ //str = str.replace(/^//,"").replace(//$/,"")
+ var rg = new RegExp(str);
+ if (term.value) return rg.test(term.value);
+ else return false;
+ }
+ }
+
+
+ function setConstraint(input,pat)
+ {
+ if (input.length == 3 && input[0].termType=="variable" && (input[2].termType=="symbol" || input[2].termType=="literal"))
+ {
+ if (input[1]=="=")
+ {
+ $rdf.log.debug("Constraint added: "+input)
+ pat.constraints[input[0]]=new constraintEqualTo(input[2])
+ }
+ else if (input[1]==">")
+ {
+ $rdf.log.debug("Constraint added: "+input)
+ pat.constraints[input[0]]=new constraintGreaterThan(input[2])
+ }
+ else if (input[1]=="<")
+ {
+ $rdf.log.debug("Constraint added: "+input)
+ pat.constraints[input[0]]=new constraintLessThan(input[2])
+ }
+ else
+ $rdf.log.warn("I don't know how to handle the constraint: "+input);
+ }
+ else if (input.length == 6 && typeof input[0] == 'string' && input[0].toLowerCase() == 'regexp'
+ && input[1] == '(' && input[5] == ')' && input[3] == ',' && input[4].termType == 'variable'
+ && input[2].termType == 'literal')
+ {
+ $rdf.log.debug("Constraint added: "+input)
+ pat.constraints[input[4]]=new constraintRegexp(input[2].value)
+ }
+
+ //$rdf.log.warn("I don't know how to handle the constraint: "+input);
+
+ //alert("length: "+input.length+" input 0 type: "+input[0].termType+" input 1: "+input[1]+" input[2] type: "+input[2].termType);
+ }
+
+
+
+ function setOptional (terms, pat)
+ {
+ $rdf.log.debug("Optional query: "+terms+" not yet implemented.");
+ var opt = kb.formula();
+ setWhere (terms, opt)
+ pat.optional.push(opt);
+ }
+
+ function setWhere (input,pat)
+ {
+ var terms = toTerms(input)
+ $rdf.log.debug("WHERE: "+terms)
+ //var opt = arrayIndicesOf("OPTIONAL",terms);
+ while (arrayIndexOf("OPTIONAL",terms))
+ {
+ opt = arrayIndexOf("OPTIONAL",terms)
+ $rdf.log.debug("OPT: "+opt+" "+terms[opt]+" in "+terms);
+ if (terms[opt+1]!="{") $rdf.log.warn("Bad optional opening bracket in word "+opt)
+ var end = getMatchingBracket(terms.slice(opt+2),"{","}")
+ if (end == -1) $rdf.log.error("No matching bracket in word "+opt)
+ else
+ {
+ setOptional(terms.slice(opt+2,opt+2+end),pat);
+ //alert(pat.statements[0].toNT())
+ opt = arrayIndexOf("OPTIONAL",terms)
+ end = getMatchingBracket(terms.slice(opt+2),"{","}")
+ terms.splice(opt,end+3)
+ }
+ }
+ $rdf.log.debug("WHERE after optionals: "+terms)
+ while (arrayIndexOf("FILTER",terms))
+ {
+ var filt = arrayIndexOf("FILTER",terms);
+ if (terms[filt+1]!="(") $rdf.log.warn("Bad filter opening bracket in word "+filt);
+ var end = getMatchingBracket(terms.slice(filt+2),"(",")")
+ if (end == -1) $rdf.log.error("No matching bracket in word "+filt)
+ else
+ {
+ setConstraint(terms.slice(filt+2,filt+2+end),pat);
+ filt = arrayIndexOf("FILTER",terms)
+ end = getMatchingBracket(terms.slice(filt+2),"(",")")
+ terms.splice(filt,end+3)
+ }
+ }
+ $rdf.log.debug("WHERE after filters and optionals: "+terms)
+ extractStatements (terms,pat)
+ }
+
+ function extractStatements (terms, formula)
+ {
+ var arrayZero = new Array(1); arrayZero[0]=-1; //this is just to add the beginning of the where to the periods index.
+ var per = arrayZero.concat(arrayIndicesOf(".",terms));
+ var stat = []
+ for (var x=0;x<per.length-1;x++)
+ stat[x]=terms.slice(per[x]+1,per[x+1])
+ //Now it's in an array of statements
+ for (x in stat) //THIS MUST BE CHANGED FOR COMMA, SEMICOLON
+ {
+ $rdf.log.info("s+p+o "+x+" = "+stat[x])
+ var subj = stat[x][0]
+ stat[x].splice(0,1)
+ var sem = arrayZero.concat(arrayIndicesOf(";",stat[x]))
+ sem.push(stat[x].length);
+ var stat2 = []
+ for (y=0;y<sem.length-1;y++)
+ stat2[y]=stat[x].slice(sem[y]+1,sem[y+1])
+ for (x in stat2)
+ {
+ $rdf.log.info("p+o "+x+" = "+stat[x])
+ var pred = stat2[x][0]
+ stat2[x].splice(0,1)
+ var com = arrayZero.concat(arrayIndicesOf(",",stat2[x]))
+ com.push(stat2[x].length);
+ var stat3 = []
+ for (y=0;y<com.length-1;y++)
+ stat3[y]=stat2[x].slice(com[y]+1,com[y+1])
+ for (x in stat3)
+ {
+ var obj = stat3[x][0]
+ $rdf.log.info("Subj="+subj+" Pred="+pred+" Obj="+obj)
+ formula.add(subj,pred,obj)
+ }
+ }
+ }
+ }
+
+ //*******************************THE ACTUAL CODE***************************//
+ $rdf.log.info("SPARQL input: \n"+SPARQL);
+ var q = new $rdf.Query();
+ var sp = tokenize (SPARQL); //first tokenize everything
+ var prefixes = getPrefixDeclarations(sp);
+ if (!prefixes["rdf"]) prefixes["rdf"]="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+ if (!prefixes["rdfs"]) prefixes["rdfs"]="http://www.w3.org/2000/01/rdf-schema#";
+ var selectLoc = arrayIndexOf("SELECT", sp), whereLoc = arrayIndexOf("WHERE", sp);
+ if (selectLoc<0 || whereLoc<0 || selectLoc>whereLoc)
+ {
+ $rdf.log.error("Invalid or nonexistent SELECT and WHERE tags in SPARQL query");
+ return false;
+ }
+ setVars (sp.slice(selectLoc+1,whereLoc),q);
+
+ setWhere (sp.slice(whereLoc+2,sp.length-1),q.pat);
+
+ if (testMode) return q;
+ for (x in q.pat.statements)
+ {
+ var st = q.pat.statements[x]
+ if (st.subject.termType == 'symbol'
+ /*&& sf.isPending(st.subject.uri)*/) { //This doesn't work.
+ //sf.requestURI(st.subject.uri,"sparql:"+st.subject) Kenny: I remove these two
+ if($rdf.sf) $rdf.sf.lookUpThing(st.subject,"sparql:"+st.subject);
+ }
+ if (st.object.termType == 'symbol'
+ /*&& sf.isPending(st.object.uri)*/) {
+ //sf.requestURI(st.object.uri,"sparql:"+st.object)
+ if($rdf.sf) $rdf.sf.lookUpThing(st.object,"sparql:"+st.object);
+ }
+ }
+ //alert(q.pat);
+ return q;
+ //checkVars()
+
+ //*******************************************************************//
+}
+
+$rdf.SPARQLResultsInterpreter = function (xml, callback, doneCallback)
+{
+
+ function isVar(term) { return (typeof term == 'string' && term.match(/^[\?\$]/)) }
+ function fixSymbolBrackets(term) { if (typeof term == 'string') return term.replace(/^</,"<").replace(/>$/,">"); else return term }
+ function isSymbol(term) { return (typeof term == 'string' && term.match(/^<[^>]*>$/)) }
+ function isBnode(term) { return (typeof term == 'string' && (term.match(/^_:/)||term.match(/^$/))) }
+ function isPrefix(term) { return (typeof term == 'string' && term.match(/:$/)) }
+ function isPrefixedSymbol(term) { return (typeof term == 'string' && term.match(/^:|^[^_][^:]*:/)) }
+ function getPrefix(term) { var a = term.split(":"); return a[0] }
+ function getSuffix(term) { var a = term.split(":"); return a[1] }
+ function removeBrackets(term) { if (isSymbol(term)) {return term.slice(1,term.length-1)} else return term }
+
+ function parsePrefix(attribute)
+ {
+ if (!attribute.name.match(/^xmlns/))
+ return false;
+
+ var pref = attribute.name.replace(/^xmlns/,"").replace(/^:/,"").replace(/ /g,"");
+ prefixes[pref]=attribute.value;
+ $rdf.log.info("Prefix: "+pref+"\nValue: "+attribute.value);
+ }
+
+ function handleP (str) //reconstructs prefixed URIs
+ {
+ if (isPrefixedSymbol(str))
+ var pref = getPrefix(str), suf = getSuffix(str);
+ else
+ var pref = "", suf = str;
+ if (prefixes[pref])
+ return prefixes[pref]+suf;
+ else
+ $rdf.log.error("Incorrect SPARQL results - bad prefix");
+ }
+
+ function xmlMakeTerm(node)
+ {
+ //alert("xml Node name: "+node.nodeName+"\nxml Child value: "+node.childNodes[0].nodeValue);
+ var val=node.childNodes[0]
+ for (var x=0; x<node.childNodes.length;x++)
+ if (node.childNodes[x].nodeType==3) { val=node.childNodes[x]; break; }
+
+ if (handleP(node.nodeName) == spns+"uri")
+ return kb.sym(val.nodeValue);
+ else if (handleP(node.nodeName) == spns+"literal")
+ return kb.literal(val.nodeValue);
+ else if (handleP(node.nodeName) == spns+"unbound")
+ return 'unbound'
+
+ else $rdf.log.warn("Don't know how to handle xml binding term "+node);
+ return false
+ }
+ function handleResult (result)
+ {
+ var resultBindings = [],bound=false;
+ for (var x=0;x<result.childNodes.length;x++)
+ {
+ //alert(result[x].nodeName);
+ if (result.childNodes[x].nodeType != 1) continue;
+ if (handleP(result.childNodes[x].nodeName) != spns+"binding") {$rdf.log.warn("Bad binding node inside result"); continue;}
+ var bind = result.childNodes[x];
+ var bindVar = makeVar(bind.getAttribute('name'));
+ var binding = null
+ for (var y=0;y<bind.childNodes.length;y++)
+ if (bind.childNodes[y].nodeType == 1) { binding = xmlMakeTerm(bind.childNodes[y]); break }
+ if (!binding) { $rdf.log.warn("Bad binding"); return false }
+ $rdf.log.info("var: "+bindVar+" binding: "+binding);
+ bound=true;
+ if (binding != 'unbound')
+ resultBindings[bindVar]=binding;
+ }
+
+ //alert(callback)
+ if (bound && callback) setTimeout(function(){callback(resultBindings)},0)
+ bindingList.push(resultBindings);
+ return;
+ }
+
+ //****MAIN CODE**********
+ var prefixes = [], bindingList=[], head, results, sparql = xml.childNodes[0], spns = "http://www.w3.org/2005/sparql-results#";
+ prefixes[""]="";
+
+ if (sparql.nodeName != 'sparql') { $rdf.log.error("Bad SPARQL results XML"); return }
+
+ for (var x=0;x<sparql.attributes.length;x++) //deals with all the prefixes beforehand
+ parsePrefix(sparql.attributes[x]);
+
+ for (var x=0;x<sparql.childNodes.length;x++) //looks for the head and results childNodes
+ {
+ $rdf.log.info("Type: "+sparql.childNodes[x].nodeType+"\nName: "+sparql.childNodes[x].nodeName+"\nValue: "+sparql.childNodes[x].nodeValue);
+
+ if (sparql.childNodes[x].nodeType==1 && handleP(sparql.childNodes[x].nodeName)== spns+"head")
+ head = sparql.childNodes[x];
+ else if (sparql.childNodes[x].nodeType==1 && handleP(sparql.childNodes[x].nodeName)==spns+"results")
+ results = sparql.childNodes[x];
+ }
+
+ if (!results && !head) { $rdf.log.error("Bad SPARQL results XML"); return }
+
+ for (var x=0;x<head.childNodes.length;x++) //@@does anything need to be done with these? Should we check against query vars?
+ {
+ if (head.childNodes[x].nodeType == 1 && handleP(head.childNodes[x].nodeName) == spns+"variable")
+ $rdf.log.info("Var: "+head.childNodes[x].getAttribute('name'))
+ }
+
+ for (var x=0;x<results.childNodes.length;x++)
+ {
+ if (handleP(results.childNodes[x].nodeName)==spns+"result")
+ {
+ $rdf.log.info("Result # "+x);
+ handleResult(results.childNodes[x]);
+ }
+ }
+
+ if (doneCallback) doneCallback();
+ return bindingList;
+ //****END OF MAIN CODE*****
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/sparqlUpdate.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,487 @@
+// Joe Presbrey <presbrey@mit.edu>
+// 2007-07-15
+// 2010-08-08 TimBL folded in Kenny's WEBDAV
+// 2010-12-07 TimBL addred local file write code
+
+$rdf.sparqlUpdate = function() {
+
+ var anonymize = function (obj) {
+ return (obj.toNT().substr(0,2) == "_:")
+ ? "?" + obj.toNT().substr(2)
+ : obj.toNT();
+ }
+
+ var anonymizeNT = function(stmt) {
+ return anonymize(stmt.subject) + " " +
+ anonymize(stmt.predicate) + " " +
+ anonymize(stmt.object) + " .";
+ }
+
+ var sparql = function(store) {
+ this.store = store;
+ this.ifps = {};
+ this.fps = {};
+ this.ns = {};
+ this.ns.link = $rdf.Namespace("http://www.w3.org/2007/ont/link#");
+ this.ns.http = $rdf.Namespace("http://www.w3.org/2007/ont/http#");
+ this.ns.httph = $rdf.Namespace("http://www.w3.org/2007/ont/httph#");
+ this.ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+ this.ns.rdfs = $rdf.Namespace("http://www.w3.org/2000/01/rdf-schema#");
+ this.ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+ this.ns.owl = $rdf.Namespace("http://www.w3.org/2002/07/owl#");
+ }
+
+
+ // Returns The method string SPARQL or DAV or LOCALFILE or false if known, undefined if not known.
+ //
+ // Files have to have a specific annotaton that they are machine written, for safety.
+ // We don't actually check for write access on files.
+ //
+ sparql.prototype.editable = function(uri, kb) {
+ // dump("sparql.prototype.editable: CALLED for "+uri+"\n")
+ if (uri.slice(0,8) == 'file:///') {
+ if (kb.holds(kb.sym(uri), tabulator.ns.rdf('type'), tabulator.ns.link('MachineEditableDocument')))
+ return 'LOCALFILE';
+ var sts = kb.statementsMatching(kb.sym(uri),undefined,undefined);
+
+ tabulator.log.warn("sparql.editable: Not MachineEditableDocument file "+uri+"\n");
+ tabulator.log.warn(sts.map(function(x){return x.toNT();}).join('\n'))
+ return false;
+ //@@ Would be nifty of course to see whether we actually have write acess first.
+ }
+
+ if (!kb) kb = this.store;
+ if (!uri) return false; // Eg subject is bnode, no knowm doc to write to
+ var request;
+ var definitive = false;
+ var requests = kb.each(undefined, this.ns.link("requestedURI"), $rdf.Util.uri.docpart(uri));
+ for (var r=0; r<requests.length; r++) {
+ request = requests[r];
+ if (request !== undefined) {
+ var response = kb.any(request, this.ns.link("response"));
+ if (request !== undefined) {
+ var author_via = kb.each(response, this.ns.httph("ms-author-via"));
+ if (author_via.length) {
+ for (var i = 0; i < author_via.length; i++) {
+ var method = author_via[i].value.trim();
+ if (method.indexOf('SPARQL') >=0 ) return 'SPARQL';
+ if (method.indexOf('DAV') >0 ) return 'DAV';
+// if (author_via[i].value == "SPARQL" || author_via[i].value == "DAV")
+ // dump("sparql.editable: Success for "+uri+": "+author_via[i] +"\n");
+ //return author_via[i].value;
+
+ }
+ }
+ var status = kb.each(response, this.ns.http("status"));
+ if (status.length) {
+ for (var i = 0; i < status.length; i++) {
+ if (status[i] == 200 || status[i] == 404) {
+ definitive = true;
+ // return false; // A definitive answer
+ }
+ }
+ }
+ } else {
+ tabulator.log.warn("sparql.editable: No response for "+uri+"\n");
+ }
+ }
+ }
+ if (requests.length == 0) {
+ tabulator.log.warn("sparql.editable: No request for "+uri+"\n");
+ } else {
+ if (definitive) return false; // We have got a request and it did NOT say editable => not editable
+ };
+
+ tabulator.log.warn("sparql.editable: inconclusive for "+uri+"\n");
+ return undefined; // We don't know (yet) as we haven't had a response (yet)
+ }
+
+ /////////// The identification of bnodes
+
+ sparql.prototype._statement_bnodes = function(st) {
+ return [st.subject, st.predicate, st.object].filter(function(x){return x.isBlank});
+ }
+
+ sparql.prototype._statement_array_bnodes = function(sts) {
+ var bnodes = [];
+ for (var i=0; i<sts.length;i++) bnodes = bnodes.concat(this._statement_bnodes(sts[i]));
+ bnodes.sort(); // in place sort - result may have duplicates
+ bnodes2 = [];
+ for (var j=0; j<bnodes.length; j++)
+ if (j==0 || !bnodes[j].sameTermAs(bnodes[j-1])) bnodes2.push(bnodes[j]);
+ return bnodes2;
+ }
+
+ sparql.prototype._cache_ifps = function() {
+ // Make a cached list of [Inverse-]Functional properties
+ // Call this once before calling context_statements
+ this.ifps = {};
+ var a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('InverseFunctionalProperty'))
+ for (var i=0; i<a.length; i++) {
+ this.ifps[a[i].uri] = true;
+ }
+ this.fps = {};
+ var a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('FunctionalProperty'))
+ for (var i=0; i<a.length; i++) {
+ this.fps[a[i].uri] = true;
+ }
+ }
+
+ sparql.prototype._bnode_context2 = function(x, source, depth) {
+ // Return a list of statements which indirectly identify a node
+ // Depth > 1 if try further indirection.
+ // Return array of statements (possibly empty), or null if failure
+ var sts = this.store.statementsMatching(undefined, undefined, x, source); // incoming links
+ for (var i=0; i<sts.length; i++) {
+ if (this.fps[sts[i].predicate.uri]) {
+ var y = sts[i].subject;
+ if (!y.isBlank)
+ return [ sts[i] ];
+ if (depth) {
+ var res = this._bnode_context2(y, source, depth-1);
+ if (res != null)
+ return res.concat([ sts[i] ]);
+ }
+ }
+ }
+ var sts = this.store.statementsMatching(x, undefined, undefined, source); // outgoing links
+ for (var i=0; i<sts.length; i++) {
+ if (this.ifps[sts[i].predicate.uri]) {
+ var y = sts[i].object;
+ if (!y.isBlank)
+ return [ sts[i] ];
+ if (depth) {
+ var res = this._bnode_context2(y, source, depth-1);
+ if (res != undefined)
+ return res.concat([ sts[i] ]);
+ }
+ }
+ }
+ return null; // Failure
+ }
+
+
+ sparql.prototype._bnode_context = function(x, source) {
+ // Return a list of statements which indirectly identify a node
+ // Breadth-first
+ for (var depth = 0; depth < 3; depth++) { // Try simple first
+ var con = this._bnode_context2(x, source, depth);
+ if (con != null) return con;
+ }
+ throw ('Unable to uniquely identify bnode: '+ x.toNT());
+ }
+
+ sparql.prototype._bnode_context = function(bnodes) {
+ var context = [];
+ if (bnodes.length) {
+ if (this.store.statementsMatching(st.subject.isBlank?undefined:st.subject,
+ st.predicate.isBlank?undefined:st.predicate,
+ st.object.isBlank?undefined:st.object,
+ st.why).length <= 1) {
+ context = context.concat(st);
+ } else {
+ this._cache_ifps();
+ for (x in bnodes) {
+ context = context.concat(this._bnode_context(bnodes[x], st.why));
+ }
+ }
+ }
+ return context;
+ }
+
+ sparql.prototype._statement_context = function(st) {
+ var bnodes = this._statement_bnodes(st);
+ return this._bnode_context(bnodes);
+ }
+
+ sparql.prototype._context_where = function(context) {
+ return (context == undefined || context.length == 0)
+ ? ""
+ : "WHERE { " + context.map(anonymizeNT).join("\n") + " }\n";
+ }
+
+ sparql.prototype._fire = function(uri, query, callback) {
+ if (!uri) throw "No URI given for remote editing operation: "+query;
+ tabulator.log.info("sparql: sending update to <"+uri+">\n query="+query+"\n");
+ var xhr = $rdf.Util.XMLHTTPFactory();
+
+ xhr.onreadystatechange = function() {
+ //dump("SPARQL update ready state for <"+uri+"> readyState="+xhr.readyState+"\n"+query+"\n");
+ if (xhr.readyState == 4) {
+ var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300));
+ if (!success) tabulator.log.error("sparql: update failed for <"+uri+"> status="+
+ xhr.status+", "+xhr.statusText+", body length="+xhr.responseText.length+"\n for query: "+query);
+ else tabulator.log.debug("sparql: update Ok for <"+uri+">");
+ callback(uri, success, xhr.responseText);
+ }
+ }
+
+ if(!tabulator.isExtension) {
+ try {
+ $rdf.Util.enablePrivilege("UniversalBrowserRead")
+ } catch(e) {
+ alert("Failed to get privileges: " + e)
+ }
+ }
+
+ xhr.open('POST', uri, true); // async=true
+ xhr.setRequestHeader('Content-type', 'application/sparql-query');
+ xhr.send(query);
+ }
+
+ // This does NOT update the statement.
+ // It returns an object whcih includes
+ // function which can be used to change the object of the statement.
+ //
+ sparql.prototype.update_statement = function(statement) {
+ if (statement && statement.why == undefined) return;
+
+ var sparql = this;
+ var context = this._statement_context(statement);
+
+ return {
+ statement: statement?[statement.subject, statement.predicate, statement.object, statement.why]:undefined,
+ statementNT: statement?anonymizeNT(statement):undefined,
+ where: sparql._context_where(context),
+
+ set_object: function(obj, callback) {
+ query = this.where;
+ query += "DELETE DATA { " + this.statementNT + " } ;\n";
+ query += "INSERT DATA { " +
+ anonymize(this.statement[0]) + " " +
+ anonymize(this.statement[1]) + " " +
+ anonymize(obj) + " " + " . }\n";
+
+ sparql._fire(this.statement[3].uri, query, callback);
+ }
+ }
+ }
+
+ sparql.prototype.insert_statement = function(st, callback) {
+ var st0 = st instanceof Array ? st[0] : st;
+ var query = this._context_where(this._statement_context(st0));
+
+ if (st instanceof Array) {
+ var stText="";
+ for (var i=0;i<st.length;i++) stText+=st[i]+'\n';
+ //query += "INSERT DATA { "+st.map(RDFStatement.prototype.toNT.call).join('\n')+" }\n";
+ //the above should work, but gives an error "called on imcompatible XUL...scope..."
+ query += "INSERT DATA { " + stText + " }\n";
+ } else {
+ query += "INSERT DATA { " +
+ anonymize(st.subject) + " " +
+ anonymize(st.predicate) + " " +
+ anonymize(st.object) + " " + " . }\n";
+ }
+
+ this._fire(st0.why.uri, query, callback);
+ }
+
+ sparql.prototype.delete_statement = function(st, callback) {
+ var query = this._context_where(this._statement_context(st));
+
+ query += "DELETE DATA { " + anonymizeNT(st) + " }\n";
+
+ this._fire(st instanceof Array?st[0].why.uri:st.why.uri, query, callback);
+ }
+
+ // This high-level function updates the local store iff the web is changed successfully.
+ //
+ // - deletions, insertions may be undefined or single statements or lists or formulae.
+ //
+ // - callback is called as callback(uri, success, errorbody)
+ //
+ sparql.prototype.update = function(deletions, insertions, callback) {
+ var kb = this.store;
+ tabulator.log.info("update called")
+ var ds = deletions == undefined ? []
+ : deletions instanceof $rdf.IndexedFormula ? deletions.statements
+ : deletions instanceof Array ? deletions : [ deletions ];
+ var is = insertions == undefined? []
+ : insertions instanceof $rdf.IndexedFormula ? insertions.statements
+ : insertions instanceof Array ? insertions : [ insertions ];
+ if (! (ds instanceof Array)) throw "Type Error "+(typeof ds)+": "+ds;
+ if (! (is instanceof Array)) throw "Type Error "+(typeof is)+": "+is;
+ var doc = ds.length ? ds[0].why : is[0].why;
+
+ ds.map(function(st){if (!doc.sameTerm(st.why)) throw "sparql update: destination "+doc+" inconsistent with ds "+st.why;});
+ is.map(function(st){if (!doc.sameTerm(st.why)) throw "sparql update: destination = "+doc+" inconsistent with st.why ="+st.why;});
+
+ var protocol = this.editable(doc.uri, kb);
+ if (!protocol) throw "Can't make changes in uneditable "+doc;
+
+ if (protocol.indexOf('SPARQL') >=0) {
+ var bnodes = []
+ if (ds.length) bnodes = this._statement_array_bnodes(ds);
+ if (is.length) bnodes = bnodes.concat(this._statement_array_bnodes(is));
+ var context = this._bnode_context(bnodes);
+ var whereClause = this._context_where(context);
+ var query = ""
+ if (whereClause.length) { // Is there a WHERE clause?
+ if (ds.length) {
+ query += "DELETE { ";
+ for (var i=0; i<ds.length;i++) query+= anonymizeNT(ds[i])+"\n";
+ query += " }\n";
+ }
+ if (is.length) {
+ query += "INSERT { ";
+ for (var i=0; i<is.length;i++) query+= anonymizeNT(is[i])+"\n";
+ query += " }\n";
+ }
+ query += whereClause;
+ } else { // no where clause
+ if (ds.length) {
+ query += "DELETE DATA { ";
+ for (var i=0; i<ds.length;i++) query+= anonymizeNT(ds[i])+"\n";
+ query += " } \n";
+ }
+ if (is.length) {
+ if (ds.length) query += " ; ";
+ query += "INSERT DATA { ";
+ for (var i=0; i<is.length;i++) query+= anonymizeNT(is[i])+"\n";
+ query += " }\n";
+ }
+ }
+ this._fire(doc.uri, query,
+ function(uri, success, body) {
+ tabulator.log.info("\t sparql: Return "+success+" for query "+query+"\n");
+ if (success) {
+ for (var i=0; i<ds.length;i++) kb.remove(ds[i]);
+ for (var i=0; i<is.length;i++)
+ kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
+ }
+ callback(uri, success, body);
+ });
+
+ } else if (protocol.indexOf('DAV') >=0) {
+
+ // The code below is derived from Kenny's UpdateCenter.js
+ var documentString;
+ var request = kb.any(doc, this.ns.link("request"));
+ if (!request) throw "No record of our HTTP GET request for document: "+doc; //should not happen
+ var response = kb.any(request, this.ns.link("response"));
+ if (!response) return null; // throw "No record HTTP GET response for document: "+doc;
+ var content_type = kb.the(response, this.ns.httph("content-type")).value;
+
+ //prepare contents of revised document
+ var newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy!
+ for (var i=0;i<ds.length;i++) $rdf.Util.RDFArrayRemove(newSts, ds[i]);
+ for (var i=0;i<is.length;i++) newSts.push(is[i]);
+
+ //serialize to te appropriate format
+ var sz = $rdf.Serializer(kb);
+ sz.suggestNamespaces(kb.namespaces);
+ sz.setBase(doc.uri);//?? beware of this - kenny (why? tim)
+ switch(content_type){
+ case 'application/rdf+xml':
+ documentString = sz.statementsToXML(newSts);
+ break;
+ case 'text/rdf+n3': // Legacy
+ case 'text/n3':
+ case 'text/turtle':
+ case 'application/x-turtle': // Legacy
+ case 'application/n3': // Legacy
+ documentString = sz.statementsToN3(newSts);
+ break;
+ default:
+ throw "Content-type "+content_type +" not supported for data write";
+ }
+
+ // Write the new version back
+
+ var candidateTarget = kb.the(response, this.ns.httph("content-location"));
+ if (candidateTarget) targetURI = Util.uri.join(candidateTarget.value, targetURI);
+ var xhr = Util.XMLHTTPFactory();
+ xhr.onreadystatechange = function (){
+ if (xhr.readyState == 4){
+ //formula from sparqlUpdate.js, what about redirects?
+ var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300));
+ if (success) {
+ for (var i=0; i<ds.length;i++) kb.remove(ds[i]);
+ for (var i=0; i<is.length;i++)
+ kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
+ }
+ callback(doc.uri, success, xhr.responseText);
+ }
+ };
+ xhr.open('PUT', targetURI, true);
+ //assume the server does PUT content-negotiation.
+ xhr.setRequestHeader('Content-type', content_type);//OK?
+ xhr.send(documentString);
+
+ } else if (protocol.indexOf('LOCALFILE') >=0) {
+ try {
+ tabulator.log.info("Writing back to local file\n");
+ // See http://simon-jung.blogspot.com/2007/10/firefox-extension-file-io.html
+ //prepare contents of revised document
+ var newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy!
+ for (var i=0;i<ds.length;i++) $rdf.Util.RDFArrayRemove(newSts, ds[i]);
+ for (var i=0;i<is.length;i++) newSts.push(is[i]);
+
+ //serialize to the appropriate format
+ var documentString;
+ var sz = $rdf.Serializer(kb);
+ sz.suggestNamespaces(kb.namespaces);
+ sz.setBase(doc.uri);//?? beware of this - kenny (why? tim)
+ var dot = doc.uri.lastIndexOf('.');
+ if (dot < 1) throw "Rewriting file: No filename extension: "+doc.uri;
+ var ext = doc.uri.slice(dot+1);
+ switch(ext){
+ case 'rdf':
+ case 'owl': // Just my experence ...@@ we should keep the format in which it was parsed
+ case 'xml':
+ documentString = sz.statementsToXML(newSts);
+ break;
+ case 'n3':
+ case 'nt':
+ case 'ttl':
+ documentString = sz.statementsToN3(newSts);
+ break;
+ default:
+ throw "File extension ."+ext +" not supported for data write";
+ }
+
+ // Write the new version back
+
+ //create component for file writing
+ dump("Writing back: <<<"+documentString+">>>\n")
+ var filename = doc.uri.slice(7); // chop off file:// leaving /path
+ //tabulator.log.warn("Writeback: Filename: "+filename+"\n")
+ var file = Components.classes["@mozilla.org/file/local;1"]
+ .createInstance(Components.interfaces.nsILocalFile);
+ file.initWithPath(filename);
+ if(!file.exists()) throw "Rewriting file <"+doc.uri+"> but it does not exist!";
+
+ //{
+ //file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420);
+ //}
+ //create file output stream and use write/create/truncate mode
+ //0x02 writing, 0x08 create file, 0x20 truncate length if exist
+ var stream = Components.classes["@mozilla.org/network/file-output-stream;1"]
+ .createInstance(Components.interfaces.nsIFileOutputStream);
+
+ stream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);
+
+ //write data to file then close output stream
+ stream.write(documentString, documentString.length);
+ stream.close();
+
+ for (var i=0; i<ds.length;i++) kb.remove(ds[i]);
+ for (var i=0; i<is.length;i++)
+ kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
+
+ callback(doc.uri, true, ""); // success!
+ } catch(e) {
+ callback(doc.uri, false,
+ "Exception trying to write back file <"+doc.uri+">\n"+
+ tabulator.Util.stackString(e))
+ }
+
+ } else throw "Unhandled edit method: '"+protocol+"' for "+doc;
+ };
+
+
+
+ return sparql;
+
+}();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/term.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,345 @@
+// These are the classes corresponding to the RDF and N3 data models
+//
+// Designed to look like rdflib and cwm designs.
+//
+// Issues: Should the names start with RDF to make them
+// unique as program-wide symbols?
+//
+// W3C open source licence 2005.
+//
+
+// Symbol
+
+$rdf.Empty = function() {
+ return this;
+};
+
+$rdf.Empty.prototype.termType = 'empty';
+$rdf.Empty.prototype.toString = function () { return "()" };
+$rdf.Empty.prototype.toNT = $rdf.Empty.prototype.toString;
+
+$rdf.Symbol = function( uri ) {
+ this.uri = uri;
+ this.value = uri; // -- why? -tim
+ return this;
+}
+
+$rdf.Symbol.prototype.termType = 'symbol';
+$rdf.Symbol.prototype.toString = function () { return ("<" + this.uri + ">"); };
+$rdf.Symbol.prototype.toNT = $rdf.Symbol.prototype.toString;
+
+// Some precalculated symbols
+$rdf.Symbol.prototype.XSDboolean = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#boolean');
+$rdf.Symbol.prototype.XSDdecimal = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#decimal');
+$rdf.Symbol.prototype.XSDfloat = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#float');
+$rdf.Symbol.prototype.XSDinteger = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#integer');
+$rdf.Symbol.prototype.XSDdateTime = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#dateTime');
+$rdf.Symbol.prototype.integer = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#integer'); // Used?
+
+// Blank Node
+
+if (typeof $rdf.NextId != 'undefined') {
+ $rdf.log.error('Attempt to re-zero existing blank node id counter at '+$rdf.NextId);
+} else {
+ $rdf.NextId = 0; // Global genid
+}
+$rdf.NTAnonymousNodePrefix = "_:n";
+
+$rdf.BlankNode = function ( id ) {
+ /*if (id)
+ this.id = id;
+ else*/
+ this.id = $rdf.NextId++
+ this.value = id ? id : this.id.toString();
+ return this
+};
+
+$rdf.BlankNode.prototype.termType = 'bnode';
+$rdf.BlankNode.prototype.toNT = function() {
+ return $rdf.NTAnonymousNodePrefix + this.id
+};
+$rdf.BlankNode.prototype.toString = $rdf.BlankNode.prototype.toNT;
+
+// Literal
+
+$rdf.Literal = function (value, lang, datatype) {
+ this.value = value
+ if (lang == "" || lang == null) this.lang = undefined;
+ else this.lang = lang; // string
+ if (datatype == null) this.datatype = undefined;
+ else this.datatype = datatype; // term
+ return this;
+}
+
+$rdf.Literal.prototype.termType = 'literal'
+$rdf.Literal.prototype.toString = function() {
+ return ''+this.value;
+};
+$rdf.Literal.prototype.toNT = function() {
+ var str = this.value
+ if (typeof str != 'string') {
+ if (typeof str == 'number') return ''+str;
+ throw Error("Value of RDF literal is not string: "+str)
+ }
+ str = str.replace(/\\/g, '\\\\'); // escape backslashes
+ str = str.replace(/\"/g, '\\"'); // escape quotes
+ str = str.replace(/\n/g, '\\n'); // escape newlines
+ str = '"' + str + '"' //';
+
+ if (this.datatype){
+ str = str + '^^' + this.datatype.toNT()
+ }
+ if (this.lang) {
+ str = str + "@" + this.lang;
+ }
+ return str;
+};
+
+$rdf.Collection = function() {
+ this.id = $rdf.NextId++; // Why need an id? For hashstring.
+ this.elements = [];
+ this.closed = false;
+};
+
+$rdf.Collection.prototype.termType = 'collection';
+
+$rdf.Collection.prototype.toNT = function() {
+ return $rdf.NTAnonymousNodePrefix + this.id
+};
+
+$rdf.Collection.prototype.toString = function() {
+ var str='(';
+ for (var i=0; i<this.elements.length; i++)
+ str+= this.elements[i] + ' ';
+ return str + ')';
+};
+
+$rdf.Collection.prototype.append = function (el) {
+ this.elements.push(el)
+}
+$rdf.Collection.prototype.unshift=function(el){
+ this.elements.unshift(el);
+}
+$rdf.Collection.prototype.shift=function(){
+ return this.elements.shift();
+}
+
+$rdf.Collection.prototype.close = function () {
+ this.closed = true
+}
+
+
+// Convert Javascript representation to RDF term object
+//
+$rdf.term = function(val) {
+ if (typeof val == 'object')
+ if (val instanceof Date) {
+ var d2=function(x) {return(''+(100+x)).slice(1,3)}; // format as just two digits
+ return new $rdf.Literal(
+ ''+ val.getUTCFullYear() + '-'+
+ d2(val.getUTCMonth()+1) +'-'+d2(val.getUTCDate())+
+ 'T'+d2(val.getUTCHours())+':'+d2(val.getUTCMinutes())+
+ ':'+d2(val.getUTCSeconds())+'Z',
+ undefined, $rdf.Symbol.prototype.XSDdateTime);
+
+ }
+ else if (val instanceof Array) {
+ var x = new $rdf.Collection();
+ for (var i=0; i<val.length; i++) x.append($rdf.term(val[i]));
+ return x;
+ }
+ else return val;
+ if (typeof val == 'string') return new $rdf.Literal(val);
+ if (typeof val == 'number') {
+ var dt;
+ if ((''+val).indexOf('e')>=0) dt = $rdf.Symbol.prototype.XSDfloat;
+ else if ((''+val).indexOf('.')>=0) dt = $rdf.Symbol.prototype.XSDdecimal;
+ else dt = $rdf.Symbol.prototype.XSDinteger;
+ return new $rdf.Literal(val, undefined, dt);
+ }
+ if (typeof val == 'boolean') return new $rdf.Literal(val?"1":"0", undefined,
+ $rdf.Symbol.prototype.XSDboolean);
+ if (typeof val == 'undefined') return undefined;
+ throw ("Can't make term from " + val + " of type " + typeof val);
+}
+
+// Statement
+//
+// This is a triple with an optional reason.
+//
+// The reason can point to provenece or inference
+//
+
+$rdf.Statement = function(subject, predicate, object, why) {
+ this.subject = $rdf.term(subject)
+ this.predicate = $rdf.term(predicate)
+ this.object = $rdf.term(object)
+ if (typeof why !='undefined') {
+ this.why = why;
+ }
+ return this;
+}
+
+$rdf.st= function(subject, predicate, object, why) {
+ return new $rdf.Statement(subject, predicate, object, why);
+};
+
+$rdf.Statement.prototype.toNT = function() {
+ return (this.subject.toNT() + " "
+ + this.predicate.toNT() + " "
+ + this.object.toNT() +" .");
+};
+
+$rdf.Statement.prototype.toString = $rdf.Statement.prototype.toNT;
+
+// Formula
+//
+// Set of statements.
+
+$rdf.Formula = function() {
+ this.statements = []
+ this.constraints = []
+ this.initBindings = []
+ this.optional = []
+ return this;
+};
+
+
+$rdf.Formula.prototype.termType = 'formula';
+$rdf.Formula.prototype.toNT = function() {
+ return "{" + this.statements.join('\n') + "}"
+};
+$rdf.Formula.prototype.toString = $rdf.Formula.prototype.toNT;
+
+$rdf.Formula.prototype.add = function(subj, pred, obj, why) {
+ this.statements.push(new $rdf.Statement(subj, pred, obj, why))
+}
+
+// Convenience methods on a formula allow the creation of new RDF terms:
+
+$rdf.Formula.prototype.sym = function(uri,name) {
+ if (name != null) {
+ throw "This feature (kb.sym with 2 args) is removed. Do not assume prefix mappings."
+ if (!$rdf.ns[uri]) throw 'The prefix "'+uri+'" is not set in the API';
+ uri = $rdf.ns[uri] + name
+ }
+ return new $rdf.Symbol(uri)
+}
+
+$rdf.sym = function(uri) { return new $rdf.Symbol(uri); };
+
+$rdf.Formula.prototype.literal = function(val, lang, dt) {
+ return new $rdf.Literal(val.toString(), lang, dt)
+}
+$rdf.lit = $rdf.Formula.prototype.literal;
+
+$rdf.Formula.prototype.bnode = function(id) {
+ return new $rdf.BlankNode(id)
+}
+
+$rdf.Formula.prototype.formula = function() {
+ return new $rdf.Formula()
+}
+
+$rdf.Formula.prototype.collection = function () { // obsolete
+ return new $rdf.Collection()
+}
+
+$rdf.Formula.prototype.list = function (values) {
+ li = new $rdf.Collection();
+ if (values) {
+ for(var i = 0; i<values.length; i++) {
+ li.append(values[i]);
+ }
+ }
+ return li;
+}
+
+/* Variable
+**
+** Variables are placeholders used in patterns to be matched.
+** In cwm they are symbols which are the formula's list of quantified variables.
+** In sparl they are not visibily URIs. Here we compromise, by having
+** a common special base URI for variables. Their names are uris,
+** but the ? nottaion has an implicit base uri of 'varid:'
+*/
+
+$rdf.Variable = function(rel) {
+ this.base = "varid:"; // We deem variabe x to be the symbol varid:x
+ this.uri = $rdf.Util.uri.join(rel, this.base);
+ return this;
+}
+
+$rdf.Variable.prototype.termType = 'variable';
+$rdf.Variable.prototype.toNT = function() {
+ if (this.uri.slice(0, this.base.length) == this.base) {
+ return '?'+ this.uri.slice(this.base.length);} // @@ poor man's refTo
+ return '?' + this.uri;
+};
+
+$rdf.Variable.prototype.toString = $rdf.Variable.prototype.toNT;
+$rdf.Variable.prototype.classOrder = 7;
+
+$rdf.variable = $rdf.Formula.prototype.variable = function(name) {
+ return new $rdf.Variable(name);
+};
+
+$rdf.Variable.prototype.hashString = $rdf.Variable.prototype.toNT;
+
+
+// The namespace function generator
+
+$rdf.Namespace = function (nsuri) {
+ return function(ln) { return new $rdf.Symbol(nsuri+(ln===undefined?'':ln)) }
+}
+
+$rdf.Formula.prototype.ns = function(nsuri) {
+ return function(ln) { return new $rdf.Symbol(nsuri+(ln===undefined?'':ln)) }
+}
+
+
+// Parse a single token
+//
+// The bnode bit should not be used on program-external values; designed
+// for internal work such as storing a bnode id in an HTML attribute.
+// This will only parse the strings generated by the vaious toNT() methods.
+
+$rdf.Formula.prototype.fromNT = function(str) {
+ var len = str.length
+ var ch = str.slice(0,1)
+ if (ch == '<') return $rdf.sym(str.slice(1,len-1))
+ if (ch == '"') {
+ var lang = undefined;
+ var dt = undefined;
+ var k = str.lastIndexOf('"');
+ if (k < len-1) {
+ if (str[k+1] == '@') lang = str.slice(k+2,len);
+ else if (str.slice(k+1,k+3) == '^^') dt = $rdf.fromNT(str.slice(k+3,len));
+ else throw "Can't convert string from NT: "+str
+ }
+ var str = (str.slice(1,k));
+ str = str.replace(/\\"/g, '"'); // unescape quotes '
+ str = str.replace(/\\n/g, '\n'); // unescape newlines
+ str = str.replace(/\\\\/g, '\\'); // unescape backslashes
+ return $rdf.lit(str, lang, dt);
+ }
+ if (ch == '_') {
+ var x = new $rdf.BlankNode();
+ x.id = parseInt(str.slice(3));
+ $rdf.NextId--
+ return x
+ }
+ if (ch == '?') {
+ var x = new $rdf.Variable(str.slice(1));
+ return x;
+ }
+ throw "Can't convert from NT: "+str;
+
+}
+$rdf.fromNT = $rdf.Formula.prototype.fromNT; // Not for inexpert user
+
+// Convenience - and more conventional name:
+
+$rdf.graph = function(){return new $rdf.IndexedFormula();};
+
+// ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/uri.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,145 @@
+// Implementing URI-specific functions
+//
+// See RFC 2386
+//
+// This is or was http://www.w3.org/2005/10/ajaw/uri.js
+// 2005 W3C open source licence
+//
+//
+// Take a URI given in relative or absolute form and a base
+// URI, and return an absolute URI
+//
+// See also http://www.w3.org/2000/10/swap/uripath.py
+//
+
+if (typeof $rdf.Util.uri == "undefined") { $rdf.Util.uri = {}; };
+
+$rdf.Util.uri.join = function (given, base) {
+ // if (typeof $rdf.log.debug != 'undefined') $rdf.log.debug(" URI given="+given+" base="+base)
+ var baseHash = base.indexOf('#')
+ if (baseHash > 0) base = base.slice(0, baseHash)
+ if (given.length==0) return base // before chopping its filename off
+ if (given.indexOf('#')==0) return base + given
+ var colon = given.indexOf(':')
+ if (colon >= 0) return given // Absolute URI form overrides base URI
+ var baseColon = base.indexOf(':')
+ if (base == "") return given;
+ if (baseColon < 0) {
+ alert("Invalid base: "+ base + ' in join with ' +given);
+ return given
+ }
+ var baseScheme = base.slice(0,baseColon+1) // eg http:
+ if (given.indexOf("//") == 0) // Starts with //
+ return baseScheme + given;
+ if (base.indexOf('//', baseColon)==baseColon+1) { // Any hostpart?
+ var baseSingle = base.indexOf("/", baseColon+3)
+ if (baseSingle < 0) {
+ if (base.length-baseColon-3 > 0) {
+ return base + "/" + given
+ } else {
+ return baseScheme + given
+ }
+ }
+ } else {
+ var baseSingle = base.indexOf("/", baseColon+1)
+ if (baseSingle < 0) {
+ if (base.length-baseColon-1 > 0) {
+ return base + "/" + given
+ } else {
+ return baseScheme + given
+ }
+ }
+ }
+
+ if (given.indexOf('/') == 0) // starts with / but not //
+ return base.slice(0, baseSingle) + given
+
+ var path = base.slice(baseSingle)
+ var lastSlash = path.lastIndexOf("/")
+ if (lastSlash <0) return baseScheme + given
+ if ((lastSlash >=0) && (lastSlash < (path.length-1)))
+ path = path.slice(0, lastSlash+1) // Chop trailing filename from base
+
+ path = path + given
+ while (path.match(/[^\/]*\/\.\.\//)) // must apply to result of prev
+ path = path.replace( /[^\/]*\/\.\.\//, '') // ECMAscript spec 7.8.5
+ path = path.replace( /\.\//g, '') // spec vague on escaping
+ path = path.replace( /\/\.$/, '/' )
+ return base.slice(0, baseSingle) + path
+}
+
+if (typeof tabulator != 'undefined' && tabulator.isExtension) {
+ $rdf.Util.uri.join2 = function (given, base){
+ var tIOService = Components.classes['@mozilla.org/network/io-service;1']
+ .getService(Components.interfaces.nsIIOService);
+
+ var baseURI = tIOService.newURI(base, null, null);
+ return tIOService.newURI(baseURI.resolve(given), null, null).spec;
+ }
+} else
+ $rdf.Util.uri.join2 = $rdf.Util.uri.join;
+
+// refTo: Make a URI relative to a given base
+//
+// based on code in http://www.w3.org/2000/10/swap/uripath.py
+//
+$rdf.Util.uri.commonHost = new RegExp("^[-_a-zA-Z0-9.]+:(//[^/]*)?/[^/]*$");
+
+$rdf.Util.uri.hostpart = function(u) { var m = /[^\/]*\/\/([^\/]*)\//.exec(u); return m? m[1]: '' };
+
+$rdf.Util.uri.refTo = function(base, uri) {
+ if (!base) return uri;
+ if (base == uri) return "";
+ var i =0; // How much are they identical?
+ while (i<uri.length && i < base.length)
+ if (uri[i] == base[i]) i++;
+ else break;
+ if (base.slice(0,i).match($rdf.Util.uri.commonHost)) {
+ var k = uri.indexOf('//');
+ if (k<0) k=-2; // no host
+ var l = uri.indexOf('/', k+2); // First *single* slash
+ if (uri.slice(l+1, l+2) != '/' && base.slice(l+1, l+2) != '/'
+ && uri.slice(0,l) == base.slice(0,l)) // common path to single slash
+ return uri.slice(l); // but no other common path segments
+ }
+ // fragment of base?
+ if (uri.slice(i, i+1) == '#' && base.length == i) return uri.slice(i);
+ while (i>0 && uri[i-1] != '/') i--;
+
+ if (i<3) return uri; // No way
+ if ((base.indexOf('//', i-2) > 0) || uri.indexOf('//', i-2) > 0)
+ return uri; // an unshared '//'
+ if (base.indexOf(':', i) >0) return uri; // unshared ':'
+ var n = 0;
+ for (var j=i; j<base.length; j++) if (base[j]=='/') n++;
+ if (n==0 && i < uri.length && uri[i] =='#') return './' + uri.slice(i);
+ if (n==0 && i == uri.length) return './';
+ var str = '';
+ for (var j=0; j<n; j++) str+= '../';
+ return str + uri.slice(i);
+}
+
+
+/** returns URI without the frag **/
+$rdf.Util.uri.docpart = function (uri) {
+ var i = uri.indexOf("#")
+ if (i < 0) return uri
+ return uri.slice(0,i)
+}
+
+/** The document in which something a thing defined **/
+$rdf.Util.uri.document = function (x) {
+ return $rdf.sym($rdf.Util.uri.docpart(x.uri));
+}
+
+/** return the protocol of a uri **/
+/** return null if there isn't one **/
+$rdf.Util.uri.protocol = function (uri) {
+ var index = uri.indexOf(':');
+ if (index >= 0)
+ return uri.slice(0, index);
+ else
+ return null;
+} //protocol
+
+//ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/util.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,386 @@
+/**
+* Utility functions for $rdf and the $rdf object itself
+ */
+
+if (typeof tabulator != 'undefined' && typeof tabulator.isExtension == 'undefined') tabulator.isExtension = false; // stand-alone library
+
+if( typeof $rdf == 'undefined' ) {
+ var $rdf = {};
+} else {
+ //dump("Internal error: RDF libray has already been loaded\n");
+ //dump("Internal error: $rdf type is "+typeof $rdf+"\n");
+ //dump("Internal error: $rdf.log type is "+typeof $rdf.log+"\n");
+ //dump("Internal error: $rdf.log.error type is "+typeof $rdf.log.error+"\n");
+ return $rdf;
+
+ throw "Internal error: RDF libray has already been loaded: $rdf already exists";
+};
+
+/**
+ * @class a dummy logger
+
+ Note to implement this using the Firefox error console see
+ https://developer.mozilla.org/en/nsIConsoleService
+ */
+
+//dump("@@ rdf/util.js test RESET RDF LOGGER $rdf.log.error)\n");
+if($rdf.log != undefined) {
+ //dump("WTF util.js:" + $rdf.log);
+ throw "Internal Error: $rdf.log already defined, util.js: " + $rdf.log;
+}
+
+$rdf.log = {
+ 'debug':function(x) {return;},
+ 'warn':function(x) {return;},
+ 'info':function(x) {return;},
+ 'error':function(x) {return;},
+ 'success':function(x) {return;},
+ 'msg':function(x) {return;}
+}
+
+
+/**
+* @class A utility class
+ */
+
+
+$rdf.Util = {
+ /** A simple debugging function */
+ 'output': function (o) {
+ var k = document.createElement('div')
+ k.textContent = o
+ document.body.appendChild(k)
+ },
+ /**
+ * A standard way to add callback functionality to an object
+ **
+ ** Callback functions are indexed by a 'hook' string.
+ **
+ ** They return true if they want to be called again.
+ **
+ */
+ 'callbackify': function (obj,callbacks) {
+ obj.callbacks = {}
+ for (var x=callbacks.length-1; x>=0; x--) {
+ obj.callbacks[callbacks[x]] = []
+ }
+
+ obj.addHook = function (hook) {
+ if (!obj.callbacks[hook]) { obj.callbacks[hook] = [] }
+ }
+
+ obj.addCallback = function (hook, func) {
+ obj.callbacks[hook].push(func)
+ }
+
+ obj.removeCallback = function (hook, funcName) {
+ for (var i=0;i<obj.callbacks[hook].length;i++){
+ //alert(obj.callbacks[hook][i].name);
+ if (obj.callbacks[hook][i].name==funcName){
+
+ obj.callbacks[hook].splice(i,1);
+ return true;
+ }
+ }
+ return false;
+ }
+ obj.insertCallback=function (hook,func){
+ obj.callbacks[hook].unshift(func);
+ }
+ obj.fireCallbacks = function (hook, args) {
+ var newCallbacks = []
+ var replaceCallbacks = []
+ var len = obj.callbacks[hook].length
+ // $rdf.log.info('!@$ Firing '+hook+' call back with length'+len);
+ for (var x=len-1; x>=0; x--) {
+ // $rdf.log.info('@@ Firing '+hook+' callback '+ obj.callbacks[hook][x])
+ if (obj.callbacks[hook][x].apply(obj,args)) {
+ newCallbacks.push(obj.callbacks[hook][x])
+ }
+ }
+
+ for (var x=newCallbacks.length-1; x>=0; x--) {
+ replaceCallbacks.push(newCallbacks[x])
+ }
+
+ for (var x=len; x<obj.callbacks[hook].length; x++) {
+ replaceCallbacks.push(obj.callbacks[hook][x])
+ }
+
+ obj.callbacks[hook] = replaceCallbacks
+ }
+ },
+
+ /**
+ * A standard way to create XMLHttpRequest objects
+ */
+ 'XMLHTTPFactory': function () {
+ if (typeof module != 'undefined' && module && module.exports) { //Node.js
+ var XMLHttpRequest = require("XMLHttpRequest").XMLHttpRequest;
+ return new XMLHttpRequest()
+ }
+ if (typeof tabulator != 'undefined' && tabulator.isExtension) {
+ return Components.
+ classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
+ createInstance().QueryInterface(Components.interfaces.nsIXMLHttpRequest);
+ } else if (window.XMLHttpRequest) {
+ return new window.XMLHttpRequest()
+ }
+ else if (window.ActiveXObject) {
+ try {
+ return new ActiveXObject("Msxml2.XMLHTTP")
+ } catch (e) {
+ return new ActiveXObject("Microsoft.XMLHTTP")
+ }
+ }
+ else {
+ return false
+ }
+ },
+
+ 'DOMParserFactory': function () {
+ if(tabulator && tabulator.isExtension) {
+ return Components.classes["@mozilla.org/xmlextras/domparser;1"]
+ .getService(Components.interfaces.nsIDOMParser);
+ } else if ( window.DOMParser ){
+ return new DOMParser();
+ } else if ( window.ActiveXObject ) {
+ return new ActiveXObject( "Microsoft.XMLDOM" );
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Returns a hash of headers and values
+ **
+ ** @@ Bug: Assumes that each header only occurs once
+ ** Also note that a , in a header value is just the same as having two headers.
+ */
+ 'getHTTPHeaders': function (xhr) {
+ var lines = xhr.getAllResponseHeaders().split("\n")
+ var headers = {}
+ var last = undefined
+ for (var x=0; x<lines.length; x++) {
+ if (lines[x].length > 0) {
+ var pair = lines[x].split(': ')
+ if (typeof pair[1] == "undefined") { // continuation
+ headers[last] += "\n"+pair[0]
+ } else {
+ last = pair[0].toLowerCase()
+ headers[last] = pair[1]
+ }
+ }
+ }
+ return headers
+ },
+
+ 'dtstamp': function () {
+ var now = new Date();
+ var year = now.getYear() + 1900;
+ var month = now.getMonth() + 1;
+ var day = now.getDate();
+ var hour = now.getUTCHours();
+ var minute = now.getUTCMinutes();
+ var second = now.getSeconds();
+ if (month < 10) month = "0" + month;
+ if (day < 10) day = "0" + day;
+ if (hour < 10) hour = "0" + hour;
+ if (minute < 10) minute = "0" + minute;
+ if (second < 10) second = "0" + second;
+ return year + "-" + month + "-" + day + "T"
+ + hour + ":" + minute + ":" + second + "Z";
+ },
+
+ 'enablePrivilege': ((typeof netscape != 'undefined') && netscape.security.PrivilegeManager.enablePrivilege) || function() { return; },
+ 'disablePrivilege': ((typeof netscape != 'undefined') && netscape.security.PrivilegeManager.disablePrivilege) || function() { return; },
+
+
+
+ 'RDFArrayRemove': function(a, x) { //removes all statements equal to x from a
+ for(var i=0; i<a.length; i++) {
+ //TODO: This used to be the following, which didnt always work..why
+ //if(a[i] == x)
+ if (a[i].subject.sameTerm( x.subject ) &&
+ a[i].predicate.sameTerm( x.predicate ) &&
+ a[i].object.sameTerm( x.object ) &&
+ a[i].why.sameTerm( x.why )) {
+ a.splice(i,1);
+ return;
+ }
+ }
+ throw "RDFArrayRemove: Array did not contain " + x;
+ },
+
+ 'string_startswith': function(str, pref) { // missing library routines
+ return (str.slice(0, pref.length) == pref);
+ },
+
+ // This is the callback from the kb to the fetcher which is used to
+ // load ontologies of the data we load.
+ 'AJAR_handleNewTerm': function(kb, p, requestedBy) {
+ var sf = null;
+ if( typeof kb.sf != 'undefined' ) {
+ sf = kb.sf;
+ } else {
+ return;
+ }
+ if (p.termType != 'symbol') return;
+ var docuri = $rdf.Util.uri.docpart(p.uri);
+ var fixuri;
+ if (p.uri.indexOf('#') < 0) { // No hash
+
+ // @@ major hack for dbpedia Categories, which spread indefinitely
+ if ($rdf.Util.string_startswith(p.uri, 'http://dbpedia.org/resource/Category:')) return;
+
+ /*
+ if (string_startswith(p.uri, 'http://xmlns.com/foaf/0.1/')) {
+ fixuri = "http://dig.csail.mit.edu/2005/ajar/ajaw/test/foaf"
+ // should give HTTP 303 to ontology -- now is :-)
+ } else
+ */
+ if ($rdf.Util.string_startswith(p.uri, 'http://purl.org/dc/elements/1.1/')
+ || $rdf.Util.string_startswith(p.uri, 'http://purl.org/dc/terms/')) {
+ fixuri = "http://dublincore.org/2005/06/13/dcq";
+ //dc fetched multiple times
+ } else if ($rdf.Util.string_startswith(p.uri, 'http://xmlns.com/wot/0.1/')) {
+ fixuri = "http://xmlns.com/wot/0.1/index.rdf";
+ } else if ($rdf.Util.string_startswith(p.uri, 'http://web.resource.org/cc/')) {
+ // $rdf.log.warn("creative commons links to html instead of rdf. doesn't seem to content-negotiate.");
+ fixuri = "http://web.resource.org/cc/schema.rdf";
+ }
+ }
+ if (fixuri) {
+ docuri = fixuri
+ }
+ if (sf && sf.getState(docuri) != 'unrequested') return;
+
+ if (fixuri) { // only give warning once: else happens too often
+ $rdf.log.warn("Assuming server still broken, faking redirect of <" + p.uri +
+ "> to <" + docuri + ">")
+ }
+ sf.requestURI(docuri, requestedBy);
+ }, //AJAR_handleNewTerm
+ 'ArrayIndexOf': function(arr, item, i) {
+ i || (i = 0);
+ var length = arr.length;
+ if (i < 0) i = length + i;
+ for (; i < length; i++)
+ if (arr[i] === item) return i;
+ return -1;
+ }
+
+};
+
+///////////////////// Parse XML
+//
+// Returns: A DOM
+//
+
+$rdf.Util.parseXML = function(str) {
+ var dparser;
+ if ((typeof tabulator != 'undefined' && tabulator.isExtension)) {
+ dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService(
+ Components.interfaces.nsIDOMParser);
+ } else if (typeof module != 'undefined' ){ // Node.js
+ var jsdom = require('jsdom');
+ return jsdom.jsdom(str, undefined, {} );// html, level, options
+ } else {
+ dparser = new DOMParser()
+ }
+ return dparser.parseFromString(str, 'application/xml');
+};
+
+
+//////////////////////String Utility
+// substitutes given terms for occurrnces of %s
+// not well named. Used??? - tim
+//
+$rdf.Util.string = {
+ //C++, python style %s -> subs
+ 'template': function(base, subs){
+ var baseA = base.split("%s");
+ var result = "";
+ for (var i=0;i<subs.length;i++){
+ subs[i] += '';
+ result += baseA[i] + subs[i];
+ }
+ return result + baseA.slice(subs.length).join();
+ }
+};
+
+// from http://dev.jquery.com/browser/trunk/jquery/src/core.js
+// Overlap with JQuery -- we try to keep the rdflib.js and jquery libraries separate at the moment.
+$rdf.Util.extend = function () {
+ // copy reference to target object
+ var target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false,
+ options, name, src, copy;
+
+ // Handle a deep copy situation
+ if (typeof target === "boolean") {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if (typeof target !== "object" && !jQuery.isFunction(target)) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if (length === i) {
+ target = this;
+ --i;
+ }
+
+ for (; i < length; i++) {
+ // Only deal with non-null/undefined values
+ if ((options = arguments[i]) != null) {
+ // Extend the base object
+ for (name in options) {
+ src = target[name];
+ copy = options[name];
+
+ // Prevent never-ending loop
+ if (target === copy) {
+ continue;
+ }
+
+ // Recurse if we're merging object values
+ if (deep && copy && typeof copy === "object" && !copy.nodeType) {
+ var clone;
+
+ if (src) {
+ clone = src;
+ } else if (jQuery.isArray(copy)) {
+ clone = [];
+ } else if (jQuery.isObject(copy)) {
+ clone = {};
+ } else {
+ clone = copy;
+ }
+
+ // Never move original objects, clone them
+ target[name] = jQuery.extend(deep, clone, copy);
+
+ // Don't bring in undefined values
+ } else if (copy !== undefined) {
+ target[name] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/rdflib.js/web.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,1178 @@
+/************************************************************
+ *
+ * Project: rdflib, part of Tabulator project
+ *
+ * File: web.js
+ *
+ * Description: contains functions for requesting/fetching/retracting
+ * This implements quite a lot of the web architecture.
+ * A fetcher is bound to a specific knowledge base graph, into which
+ * it loads stuff and into which it writes its metadata
+ * @@ The metadata should be optionally a separate graph
+ *
+ * - implements semantics of HTTP headers, Internet Content Types
+ * - selects parsers for rdf/xml, n3, rdfa, grddl
+ *
+ * needs: util.js uri.js term.js match.js rdfparser.js rdfa.js n3parser.js
+ * identity.js rdfs.js sparql.js jsonparser.js
+ *
+ * Was: js/tab/sources.js
+ ************************************************************/
+
+/**
+ * Things to test: callbacks on request, refresh, retract
+ * loading from HTTP, HTTPS, FTP, FILE, others?
+ */
+
+$rdf.Fetcher = function(store, timeout, async) {
+ this.store = store
+ this.thisURI = "http://dig.csail.mit.edu/2005/ajar/ajaw/rdf/sources.js" + "#SourceFetcher" // -- Kenny
+// this.timeout = timeout ? timeout : 300000
+ this.timeout = timeout ? timeout : 30000
+ this.async = async != null ? async : true
+ this.appNode = this.store.bnode(); // Denoting this session
+ this.store.fetcher = this; //Bi-linked
+ this.requested = {}
+ this.lookedUp = {}
+ this.handlers = []
+ this.mediatypes = {}
+ var sf = this
+ var kb = this.store;
+ var ns = {} // Convenience namespaces needed in this module:
+ // These are delibertely not exported as the user application should
+ // make its own list and not rely on the prefixes used here,
+ // and not be tempted to add to them, and them clash with those of another
+ // application.
+ ns.link = $rdf.Namespace("http://www.w3.org/2007/ont/link#");
+ ns.http = $rdf.Namespace("http://www.w3.org/2007/ont/http#");
+ ns.httph = $rdf.Namespace("http://www.w3.org/2007/ont/httph#");
+ ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+ ns.rdfs = $rdf.Namespace("http://www.w3.org/2000/01/rdf-schema#");
+ ns.dc = $rdf.Namespace("http://purl.org/dc/elements/1.1/");
+
+ $rdf.Fetcher.RDFXMLHandler = function(args) {
+ if (args) {
+ this.dom = args[0]
+ }
+ this.recv = function(xhr) {
+ xhr.handle = function(cb) {
+ var kb = sf.store;
+ if (!this.dom) this.dom = $rdf.Util.parseXML(xhr.responseText);
+/* {
+ var dparser;
+ if ((typeof tabulator != 'undefined' && tabulator.isExtension)) {
+ dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService(Components.interfaces.nsIDOMParser);
+ } else {
+ dparser = new DOMParser()
+ }
+ //strange things happen when responseText is empty
+ this.dom = dparser.parseFromString(xhr.responseText, 'application/xml')
+ }
+*/
+ var root = this.dom.documentElement;
+ //some simple syntax issue should be dealt here, I think
+ if (root.nodeName == 'parsererror') { //@@ Mozilla only See issue/issue110
+ sf.failFetch(xhr, "Badly formed XML in " + xhr.uri.uri); //have to fail the request
+ throw new Error("Badly formed XML in " + xhr.uri.uri); //@@ Add details
+ }
+ // Find the last URI we actual URI in a series of redirects
+ // (xhr.uri.uri is the original one)
+ var lastRequested = kb.any(xhr.req, ns.link('requestedURI'));
+ //dump('lastRequested 1:'+lastRequested+'\n')
+ if (!lastRequested) {
+ //dump("Eh? No last requested for "+xhr.uri+"\n");
+ lastRequested = xhr.uri;
+ } else {
+ lastRequested = kb.sym(lastRequested.value);
+ //dump('lastRequested 2:'+lastRequested+'\n')
+ }
+ //dump('lastRequested 3:'+lastRequested+'\n')
+ var parser = new $rdf.RDFParser(kb);
+ sf.addStatus(xhr.req, 'parsing as RDF/XML...');
+ parser.parse(this.dom, lastRequested.uri, lastRequested);
+ kb.add(lastRequested, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode);
+ cb();
+ }
+ }
+ }
+ $rdf.Fetcher.RDFXMLHandler.term = this.store.sym(this.thisURI + ".RDFXMLHandler")
+ $rdf.Fetcher.RDFXMLHandler.toString = function() {
+ return "RDFXMLHandler"
+ }
+ $rdf.Fetcher.RDFXMLHandler.register = function(sf) {
+ sf.mediatypes['application/rdf+xml'] = {}
+ }
+ $rdf.Fetcher.RDFXMLHandler.pattern = new RegExp("application/rdf\\+xml");
+
+ // This would much better use on-board XSLT engine. @@
+ $rdf.Fetcher.doGRDDL = function(kb, doc, xslturi, xmluri) {
+ sf.requestURI('http://www.w3.org/2005/08/' + 'online_xslt/xslt?' + 'xslfile=' + escape(xslturi) + '&xmlfile=' + escape(xmluri), doc)
+ }
+
+ $rdf.Fetcher.XHTMLHandler = function(args) {
+ if (args) {
+ this.dom = args[0]
+ }
+ this.recv = function(xhr) {
+ xhr.handle = function(cb) {
+ if (!this.dom) {
+ var dparser;
+ if (typeof tabulator != 'undefined' && tabulator.isExtension) {
+ dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService(Components.interfaces.nsIDOMParser);
+ } else {
+ dparser = new DOMParser()
+ }
+ this.dom = dparser.parseFromString(xhr.responseText, 'application/xml')
+ }
+ var kb = sf.store;
+
+ // dc:title
+ var title = this.dom.getElementsByTagName('title')
+ if (title.length > 0) {
+ kb.add(xhr.uri, ns.dc('title'), kb.literal(title[0].textContent), xhr.uri)
+ // $rdf.log.info("Inferring title of " + xhr.uri)
+ }
+
+ // link rel
+ var links = this.dom.getElementsByTagName('link');
+ for (var x = links.length - 1; x >= 0; x--) {
+ sf.linkData(xhr, links[x].getAttribute('rel'), links[x].getAttribute('href'));
+ }
+
+ //GRDDL
+ var head = this.dom.getElementsByTagName('head')[0]
+ if (head) {
+ var profile = head.getAttribute('profile');
+ if (profile && $rdf.Util.uri.protocol(profile) == 'http') {
+ // $rdf.log.info("GRDDL: Using generic " + "2003/11/rdf-in-xhtml-processor.");
+ $rdf.Fetcher.doGRDDL(kb, xhr.uri, "http://www.w3.org/2003/11/rdf-in-xhtml-processor", xhr.uri.uri)
+/* sf.requestURI('http://www.w3.org/2005/08/'
+ + 'online_xslt/xslt?'
+ + 'xslfile=http://www.w3.org'
+ + '/2003/11/'
+ + 'rdf-in-xhtml-processor'
+ + '&xmlfile='
+ + escape(xhr.uri.uri),
+ xhr.uri)
+ */
+ } else {
+ // $rdf.log.info("GRDDL: No GRDDL profile in " + xhr.uri)
+ }
+ }
+ kb.add(xhr.uri, ns.rdf('type'), ns.link('WebPage'), sf.appNode);
+ // Do RDFa here
+ //var p = $rdf.RDFaParser(kb, xhr.uri.uri);
+ $rdf.rdfa.parse(this.dom, kb, xhr.uri.uri); // see rdfa.js
+ }
+ }
+ }
+ $rdf.Fetcher.XHTMLHandler.term = this.store.sym(this.thisURI + ".XHTMLHandler")
+ $rdf.Fetcher.XHTMLHandler.toString = function() {
+ return "XHTMLHandler"
+ }
+ $rdf.Fetcher.XHTMLHandler.register = function(sf) {
+ sf.mediatypes['application/xhtml+xml'] = {
+ 'q': 0.3
+ }
+ }
+ $rdf.Fetcher.XHTMLHandler.pattern = new RegExp("application/xhtml")
+
+
+ /******************************************************/
+
+ $rdf.Fetcher.XMLHandler = function() {
+ this.recv = function(xhr) {
+ xhr.handle = function(cb) {
+ var kb = sf.store
+ var dparser;
+ if (typeof tabulator != 'undefined' && tabulator.isExtension) {
+ dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService(Components.interfaces.nsIDOMParser);
+ } else {
+ dparser = new DOMParser()
+ }
+ var dom = dparser.parseFromString(xhr.responseText, 'application/xml')
+
+ // XML Semantics defined by root element namespace
+ // figure out the root element
+ for (var c = 0; c < dom.childNodes.length; c++) {
+ // is this node an element?
+ if (dom.childNodes[c].nodeType == 1) {
+ // We've found the first element, it's the root
+ var ns = dom.childNodes[c].namespaceURI;
+
+ // Is it RDF/XML?
+ if (ns != undefined && ns == ns['rdf']) {
+ sf.addStatus(xhr.req, "Has XML root element in the RDF namespace, so assume RDF/XML.")
+ sf.switchHandler('RDFXMLHandler', xhr, cb, [dom])
+ return
+ }
+ // it isn't RDF/XML or we can't tell
+ // Are there any GRDDL transforms for this namespace?
+ // @@ assumes ns documents have already been loaded
+ var xforms = kb.each(kb.sym(ns), kb.sym("http://www.w3.org/2003/g/data-view#namespaceTransformation"));
+ for (var i = 0; i < xforms.length; i++) {
+ var xform = xforms[i];
+ // $rdf.log.info(xhr.uri.uri + " namespace " + ns + " has GRDDL ns transform" + xform.uri);
+ $rdf.Fetcher.doGRDDL(kb, xhr.uri, xform.uri, xhr.uri.uri);
+ }
+ break
+ }
+ }
+
+ // Or it could be XHTML?
+ // Maybe it has an XHTML DOCTYPE?
+ if (dom.doctype) {
+ // $rdf.log.info("We found a DOCTYPE in " + xhr.uri)
+ if (dom.doctype.name == 'html' && dom.doctype.publicId.match(/^-\/\/W3C\/\/DTD XHTML/) && dom.doctype.systemId.match(/http:\/\/www.w3.org\/TR\/xhtml/)) {
+ sf.addStatus(xhr.req,"Has XHTML DOCTYPE. Switching to XHTML Handler.\n")
+ sf.switchHandler('XHTMLHandler', xhr, cb)
+ return
+ }
+ }
+
+ // Or what about an XHTML namespace?
+ var html = dom.getElementsByTagName('html')[0]
+ if (html) {
+ var xmlns = html.getAttribute('xmlns')
+ if (xmlns && xmlns.match(/^http:\/\/www.w3.org\/1999\/xhtml/)) {
+ sf.addStatus(xhr.req, "Has a default namespace for " + "XHTML. Switching to XHTMLHandler.\n")
+ sf.switchHandler('XHTMLHandler', xhr, cb)
+ return
+ }
+ }
+
+ // At this point we should check the namespace document (cache it!) and
+ // look for a GRDDL transform
+ // @@ Get namespace document <n>, parse it, look for <n> grddl:namespaceTransform ?y
+ // Apply ?y to dom
+ // We give up. What dialect is this?
+ sf.failFetch(xhr, "Unsupported dialect of XML: not RDF or XHTML namespace, etc.\n"+xhr.responseText.slice(0,80));
+ }
+ }
+ }
+ $rdf.Fetcher.XMLHandler.term = this.store.sym(this.thisURI + ".XMLHandler")
+ $rdf.Fetcher.XMLHandler.toString = function() {
+ return "XMLHandler"
+ }
+ $rdf.Fetcher.XMLHandler.register = function(sf) {
+ sf.mediatypes['text/xml'] = {
+ 'q': 0.2
+ }
+ sf.mediatypes['application/xml'] = {
+ 'q': 0.2
+ }
+ }
+ $rdf.Fetcher.XMLHandler.pattern = new RegExp("(text|application)/(.*)xml")
+
+ $rdf.Fetcher.HTMLHandler = function() {
+ this.recv = function(xhr) {
+ xhr.handle = function(cb) {
+ var rt = xhr.responseText
+ // We only handle XHTML so we have to figure out if this is XML
+ // $rdf.log.info("Sniffing HTML " + xhr.uri + " for XHTML.");
+
+ if (rt.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/)) {
+ sf.addStatus(xhr.req, "Has an XML declaration. We'll assume " +
+ "it's XHTML as the content-type was text/html.\n")
+ sf.switchHandler('XHTMLHandler', xhr, cb)
+ return
+ }
+
+ // DOCTYPE
+ // There is probably a smarter way to do this
+ if (rt.match(/.*<!DOCTYPE\s+html[^<]+-\/\/W3C\/\/DTD XHTML[^<]+http:\/\/www.w3.org\/TR\/xhtml[^<]+>/)) {
+ sf.addStatus(xhr.req, "Has XHTML DOCTYPE. Switching to XHTMLHandler.\n")
+ sf.switchHandler('XHTMLHandler', xhr, cb)
+ return
+ }
+
+ // xmlns
+ if (rt.match(/[^(<html)]*<html\s+[^<]*xmlns=['"]http:\/\/www.w3.org\/1999\/xhtml["'][^<]*>/)) {
+ sf.addStatus(xhr.req, "Has default namespace for XHTML, so switching to XHTMLHandler.\n")
+ sf.switchHandler('XHTMLHandler', xhr, cb)
+ return
+ }
+
+
+ // dc:title //no need to escape '/' here
+ var titleMatch = (new RegExp("<title>([\\s\\S]+?)</title>", 'im')).exec(rt);
+ if (titleMatch) {
+ var kb = sf.store;
+ kb.add(xhr.uri, ns.dc('title'), kb.literal(titleMatch[1]), xhr.uri); //think about xml:lang later
+ kb.add(xhr.uri, ns.rdf('type'), ns.link('WebPage'), sf.appNode);
+ cb(); //doneFetch, not failed
+ return;
+ }
+
+ sf.failFetch(xhr, "Sorry, can't yet parse non-XML HTML")
+ }
+ }
+ }
+ $rdf.Fetcher.HTMLHandler.term = this.store.sym(this.thisURI + ".HTMLHandler")
+ $rdf.Fetcher.HTMLHandler.toString = function() {
+ return "HTMLHandler"
+ }
+ $rdf.Fetcher.HTMLHandler.register = function(sf) {
+ sf.mediatypes['text/html'] = {
+ 'q': 0.3
+ }
+ }
+ $rdf.Fetcher.HTMLHandler.pattern = new RegExp("text/html")
+
+ /***********************************************/
+
+ $rdf.Fetcher.TextHandler = function() {
+ this.recv = function(xhr) {
+ xhr.handle = function(cb) {
+ // We only speak dialects of XML right now. Is this XML?
+ var rt = xhr.responseText
+
+ // Look for an XML declaration
+ if (rt.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/)) {
+ sf.addStatus(xhr.req, "Warning: "+xhr.uri + " has an XML declaration. We'll assume "
+ + "it's XML but its content-type wasn't XML.\n")
+ sf.switchHandler('XMLHandler', xhr, cb)
+ return
+ }
+
+ // Look for an XML declaration
+ if (rt.slice(0, 500).match(/xmlns:/)) {
+ sf.addStatus(xhr.req, "May have an XML namespace. We'll assume "
+ + "it's XML but its content-type wasn't XML.\n")
+ sf.switchHandler('XMLHandler', xhr, cb)
+ return
+ }
+
+ // We give up finding semantics - this is not an error, just no data
+ sf.addStatus(xhr.req, "Plain text document, no known RDF semantics.");
+ sf.doneFetch(xhr, [xhr.uri.uri]);
+// sf.failFetch(xhr, "unparseable - text/plain not visibly XML")
+// dump(xhr.uri + " unparseable - text/plain not visibly XML, starts:\n" + rt.slice(0, 500)+"\n")
+
+ }
+ }
+ }
+ $rdf.Fetcher.TextHandler.term = this.store.sym(this.thisURI + ".TextHandler")
+ $rdf.Fetcher.TextHandler.toString = function() {
+ return "TextHandler"
+ }
+ $rdf.Fetcher.TextHandler.register = function(sf) {
+ sf.mediatypes['text/plain'] = {
+ 'q': 0.1
+ }
+ }
+ $rdf.Fetcher.TextHandler.pattern = new RegExp("text/plain")
+
+ /***********************************************/
+
+ $rdf.Fetcher.N3Handler = function() {
+ this.recv = function(xhr) {
+ xhr.handle = function(cb) {
+ // Parse the text of this non-XML file
+ var rt = xhr.responseText
+ var p = $rdf.N3Parser(kb, kb, xhr.uri.uri, xhr.uri.uri, null, null, "", null)
+ // p.loadBuf(xhr.responseText)
+ try {
+ p.loadBuf(xhr.responseText)
+
+ } catch (e) {
+ var msg = ("Error trying to parse " + xhr.uri + ' as Notation3:\n' + e)
+ // dump(msg+"\n")
+ sf.failFetch(xhr, msg)
+ return;
+ }
+
+ sf.addStatus(xhr.req, 'N3 parsed: ' + p.statementCount + ' statements in ' + p.lines + ' lines.')
+ sf.store.add(xhr.uri, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode);
+ args = [xhr.uri.uri]; // Other args needed ever?
+ sf.doneFetch(xhr, args)
+ }
+ }
+ }
+ $rdf.Fetcher.N3Handler.term = this.store.sym(this.thisURI + ".N3Handler")
+ $rdf.Fetcher.N3Handler.toString = function() {
+ return "N3Handler"
+ }
+ $rdf.Fetcher.N3Handler.register = function(sf) {
+ sf.mediatypes['text/n3'] = {
+ 'q': '1.0'
+ } // as per 2008 spec
+ sf.mediatypes['text/rdf+n3'] = {
+ 'q': 1.0
+ } // pre 2008 spec
+ sf.mediatypes['application/x-turtle'] = {
+ 'q': 1.0
+ } // pre 2008
+ sf.mediatypes['text/turtle'] = {
+ 'q': 1.0
+ } // pre 2008
+ }
+ $rdf.Fetcher.N3Handler.pattern = new RegExp("(application|text)/(x-)?(rdf\\+)?(n3|turtle)")
+
+
+ /***********************************************/
+
+
+
+
+
+ $rdf.Util.callbackify(this, ['request', 'recv', 'load', 'fail', 'refresh', 'retract', 'done'])
+
+ this.addProtocol = function(proto) {
+ sf.store.add(sf.appNode, ns.link("protocol"), sf.store.literal(proto), this.appNode)
+ }
+
+ this.addHandler = function(handler) {
+ sf.handlers.push(handler)
+ handler.register(sf)
+ }
+
+ this.switchHandler = function(name, xhr, cb, args) {
+ var kb = this.store; var handler = null;
+ for (var i=0; i<this.handlers.length; i++) {
+ if (''+this.handlers[i] == name) {
+ handler = this.handlers[i];
+ }
+ }
+ if (handler == undefined) {
+ throw 'web.js: switchHandler: name='+name+' , this.handlers ='+this.handlers+'\n' +
+ 'switchHandler: switching to '+handler+'; sf='+sf +
+ '; typeof $rdf.Fetcher='+typeof $rdf.Fetcher +
+ ';\n\t $rdf.Fetcher.HTMLHandler='+$rdf.Fetcher.HTMLHandler+'\n' +
+ '\n\tsf.handlers='+sf.handlers+'\n'
+ }
+ (new handler(args)).recv(xhr);
+ xhr.handle(cb)
+ }
+
+ this.addStatus = function(req, status) {
+ //<Debug about="parsePerformance">
+ var now = new Date();
+ status = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "." + now.getMilliseconds() + "] " + status;
+ //</Debug>
+ var kb = this.store
+ kb.the(req, ns.link('status')).append(kb.literal(status))
+ }
+
+ // Record errors in the system on failure
+ // Returns xhr so can just do return this.failfetch(...)
+ this.failFetch = function(xhr, status) {
+ this.addStatus(xhr.req, status)
+ kb.add(xhr.uri, ns.link('error'), status)
+ this.requested[$rdf.Util.uri.docpart(xhr.uri.uri)] = false
+ this.fireCallbacks('fail', [xhr.requestedURI])
+ xhr.abort()
+ return xhr
+ }
+
+ this.linkData = function(xhr, rel, uri) {
+ var x = xhr.uri;
+ if (!uri) return;
+ // See http://www.w3.org/TR/powder-dr/#httplink for describedby 2008-12-10
+ if (rel == 'alternate' || rel == 'seeAlso' || rel == 'meta' || rel == 'describedby') {
+ var join = $rdf.Util.uri.join2;
+ var obj = kb.sym(join(uri, xhr.uri.uri))
+ if (obj.uri != xhr.uri) {
+ kb.add(xhr.uri, ns.rdfs('seeAlso'), obj, xhr.uri);
+ // $rdf.log.info("Loading " + obj + " from link rel in " + xhr.uri);
+ }
+ }
+ };
+
+
+ this.doneFetch = function(xhr, args) {
+ this.addStatus(xhr.req, 'done')
+ // $rdf.log.info("Done with parse, firing 'done' callbacks for " + xhr.uri)
+ this.requested[xhr.uri.uri] = 'done'; //Kenny
+ this.fireCallbacks('done', args)
+ }
+
+ this.store.add(this.appNode, ns.rdfs('label'), this.store.literal('This Session'), this.appNode);
+
+ ['http', 'https', 'file', 'chrome'].map(this.addProtocol); // ftp?
+ [$rdf.Fetcher.RDFXMLHandler, $rdf.Fetcher.XHTMLHandler, $rdf.Fetcher.XMLHandler, $rdf.Fetcher.HTMLHandler, $rdf.Fetcher.TextHandler, $rdf.Fetcher.N3Handler, ].map(this.addHandler)
+
+
+
+ /** Note two nodes are now smushed
+ **
+ ** If only one was flagged as looked up, then
+ ** the new node is looked up again, which
+ ** will make sure all the URIs are dereferenced
+ */
+ this.nowKnownAs = function(was, now) {
+ if (this.lookedUp[was.uri]) {
+ if (!this.lookedUp[now.uri]) this.lookUpThing(now, was)
+ } else if (this.lookedUp[now.uri]) {
+ if (!this.lookedUp[was.uri]) this.lookUpThing(was, now)
+ }
+ }
+
+
+
+
+
+// Looks up something.
+//
+// Looks up all the URIs a things has.
+// Parameters:
+//
+// term: canonical term for the thing whose URI is to be dereferenced
+// rterm: the resource which refered to this (for tracking bad links)
+// force: Load the data even if loaded before
+// callback: is called as callback(uri, success, errorbody)
+
+ this.lookUpThing = function(term, rterm, force, callback) {
+ var uris = kb.uris(term) // Get all URIs
+ var failed = false;
+ var outstanding;
+ if (typeof uris != 'undefined') {
+
+ if (callback) {
+ // @@@@@@@ not implemented
+ }
+ for (var i = 0; i < uris.length; i++) {
+ this.lookedUp[uris[i]] = true;
+ this.requestURI($rdf.Util.uri.docpart(uris[i]), rterm, force)
+ }
+ }
+ return uris.length
+ }
+
+
+/* Ask for a doc to be loaded if necessary then call back
+ **/
+ this.nowOrWhenFetched = function(uri, referringTerm, callback) {
+ var sta = this.getState(uri);
+ if (sta == 'fetched') return callback();
+ this.addCallback('done', function(uri2) {
+ if (uri2 == uri) callback();
+ return (uri2 != uri); // Call me again?
+ });
+ if (sta == 'unrequested') this.requestURI(
+ uri, referringTerm, false);
+ }
+
+
+
+
+
+ /** Requests a document URI and arranges to load the document.
+ ** Parameters:
+ ** term: term for the thing whose URI is to be dereferenced
+ ** rterm: the resource which refered to this (for tracking bad links)
+ ** force: Load the data even if loaded before
+ ** Return value:
+ ** The xhr object for the HTTP access
+ ** null if the protocol is not a look-up protocol,
+ ** or URI has already been loaded
+ */
+ this.requestURI = function(docuri, rterm, force) { //sources_request_new
+ if (docuri.indexOf('#') >= 0) { // hash
+ throw ("requestURI should not be called with fragid: " + uri)
+ }
+
+ var pcol = $rdf.Util.uri.protocol(docuri);
+ if (pcol == 'tel' || pcol == 'mailto' || pcol == 'urn') return null; // No look-up operaion on these, but they are not errors
+ var force = !! force
+ var kb = this.store
+ var args = arguments
+ // var term = kb.sym(docuri)
+ var docterm = kb.sym(docuri)
+ // dump("requestURI: dereferencing " + docuri)
+ //this.fireCallbacks('request',args)
+ if (!force && typeof(this.requested[docuri]) != "undefined") {
+ // dump("We already have requested " + docuri + ". Skipping.\n")
+ return null
+ }
+
+ this.fireCallbacks('request', args); //Kenny: fire 'request' callbacks here
+ // dump( "web.js: Requesting uri: " + docuri + "\n" );
+ this.requested[docuri] = true
+
+ if (rterm) {
+ if (rterm.uri) { // A link betwen URIs not terms
+ kb.add(docterm.uri, ns.link("requestedBy"), rterm.uri, this.appNode)
+ }
+ }
+
+ if (rterm) {
+ // $rdf.log.info('SF.request: ' + docuri + ' refd by ' + rterm.uri)
+ }
+ else {
+ // $rdf.log.info('SF.request: ' + docuri + ' no referring doc')
+ };
+
+ var xhr = $rdf.Util.XMLHTTPFactory()
+ var req = xhr.req = kb.bnode()
+ xhr.uri = docterm;
+ xhr.requestedURI = args[0];
+ var requestHandlers = kb.collection()
+ var sf = this
+
+ var now = new Date();
+ var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] ";
+
+ kb.add(req, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + docuri), this.appNode)
+ kb.add(req, ns.link("requestedURI"), kb.literal(docuri), this.appNode)
+ kb.add(req, ns.link('status'), kb.collection(), sf.req)
+
+ // This should not be stored in the store, but in the JS data
+ if (typeof kb.anyStatementMatching(this.appNode, ns.link("protocol"), $rdf.Util.uri.protocol(docuri)) == "undefined") {
+ // update the status before we break out
+ this.failFetch(xhr, "Unsupported protocol: "+$rdf.Util.uri.protocol(docuri))
+ return xhr
+ }
+
+ xhr.onerror = function(event) {
+ sf.failFetch(xhr, "XHR Error: "+event)
+ }
+
+ // Set up callbacks
+ xhr.onreadystatechange = function() {
+
+ var handleResponse = function() {
+ if (xhr.handleResponseDone) return;
+ xhr.handleResponseDone = true;
+ var handler = null;
+ var thisReq = xhr.req // Might have changes by redirect
+ sf.fireCallbacks('recv', args)
+ var kb = sf.store;
+ var response = kb.bnode();
+ kb.add(thisReq, ns.link('response'), response);
+ kb.add(response, ns.http('status'), kb.literal(xhr.status), response)
+ kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response)
+
+ xhr.headers = {}
+ if ($rdf.Util.uri.protocol(xhr.uri.uri) == 'http' || $rdf.Util.uri.protocol(xhr.uri.uri) == 'https') {
+ xhr.headers = $rdf.Util.getHTTPHeaders(xhr)
+ for (var h in xhr.headers) { // trim below for Safari - adds a CR!
+ kb.add(response, ns.httph(h), xhr.headers[h].trim(), response)
+ }
+ }
+
+ if (xhr.status >= 400) { // For extra dignostics, keep the reply
+ if (xhr.responseText.length > 10) {
+ kb.add(response, ns.http('content'), kb.literal(xhr.responseText), response);
+ // dump("HTTP >= 400 responseText:\n"+xhr.responseText+"\n"); // @@@@
+ }
+ sf.failFetch(xhr, "HTTP error for " +xhr.uri + ": "+ xhr.status + ' ' + xhr.statusText);
+ return;
+ }
+
+
+
+ var loc = xhr.headers['content-location'];
+
+
+
+ // deduce some things from the HTTP transaction
+ var addType = function(cla) { // add type to all redirected resources too
+ var prev = thisReq;
+ if (loc) {
+ var docURI = kb.any(prev, ns.link('requestedURI'));
+ if (docURI != loc) {
+ kb.add(kb.sym(doc), ns.rdf('type'), cla, sf.appNode);
+ }
+ }
+ for (;;) {
+ var doc = kb.sym(kb.any(prev, ns.link('requestedURI')))
+ kb.add(doc, ns.rdf('type'), cla, sf.appNode);
+ prev = kb.any(undefined, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), prev);
+ if (!prev) break;
+ var response = kb.any(prev, kb.sym('http://www.w3.org/2007/ont/link#response'));
+ if (!response) break;
+ var redirection = kb.any(response, kb.sym('http://www.w3.org/2007/ont/http#status'));
+ if (!redirection) break;
+ if (redirection != '301' && redirection != '302') break;
+ }
+ }
+ if (xhr.status == 200) {
+ addType(ns.link('Document'));
+ var ct = xhr.headers['content-type'];
+ if (!ct) throw ('No content-type on 200 response for ' + xhr.uri)
+ else {
+ if (ct.indexOf('image/') == 0) addType(kb.sym('http://purl.org/dc/terms/Image'));
+ }
+ }
+
+ if ($rdf.Util.uri.protocol(xhr.uri.uri) == 'file' || $rdf.Util.uri.protocol(xhr.uri.uri) == 'chrome') {
+ switch (xhr.uri.uri.split('.').pop()) {
+ case 'rdf':
+ case 'owl':
+ xhr.headers['content-type'] = 'application/rdf+xml';
+ break;
+ case 'n3':
+ case 'nt':
+ case 'ttl':
+ xhr.headers['content-type'] = 'text/n3';
+ break;
+ default:
+ xhr.headers['content-type'] = 'text/xml';
+ }
+ }
+
+ // If we have alread got the thing at this location, abort
+ if (loc) {
+ var udoc = $rdf.Util.uri.join(xhr.uri.uri, loc)
+ if (!force && udoc != xhr.uri.uri && sf.requested[udoc]) {
+ // should we smush too?
+ // $rdf.log.info("HTTP headers indicate we have already" + " retrieved " + xhr.uri + " as " + udoc + ". Aborting.")
+ sf.doneFetch(xhr, args)
+ xhr.abort()
+ return
+ }
+ sf.requested[udoc] = true
+ }
+
+
+ for (var x = 0; x < sf.handlers.length; x++) {
+ if (xhr.headers['content-type'] && xhr.headers['content-type'].match(sf.handlers[x].pattern)) {
+ handler = new sf.handlers[x]()
+ requestHandlers.append(sf.handlers[x].term) // FYI
+ break
+ }
+ }
+
+ var link = xhr.headers['link']; // Only one?
+ if (link) {
+ var rel = null;
+ var arg = link.replace(/ /g, '').split(';');
+ for (var i = 0; i < arg.length; i++) {
+ lr = arg[i].split('=');
+ if (lr[0] == 'rel') rel = lr[1];
+ }
+ if (rel) // Treat just like HTML link element
+ sf.linkData(xhr, rel, arg[0]);
+ }
+
+
+ if (handler) {
+ handler.recv(xhr)
+ } else {
+ sf.failFetch(xhr, "Unhandled content type: " + xhr.headers['content-type']+
+ ", readyState = "+xhr.readyState);
+ return;
+ }
+ };
+
+ // DONE: 4
+ // HEADERS_RECEIVED: 2
+ // LOADING: 3
+ // OPENED: 1
+ // UNSENT: 0
+ switch (xhr.readyState) {
+ case 0:
+ var uri = xhr.uri.uri, newURI;
+ if (this.crossSiteProxyTemplate && document && document.location) { // In mashup situation
+ var hostpart = $rdf.Util.uri.hostpart;
+ var here = '' + document.location;
+ if (hostpart(here) && hostpart(uri) && hostpart(here) != hostpart(uri)) {
+ newURI = uri.replace('{uri}', encodeURIComponent(uri));
+ sf.addStatus(xhr.req, "BLOCKED -> Cross-site Proxy to <" + newURI + ">");
+ if (xhr.aborted) return;
+
+ var kb = sf.store;
+ var oldreq = xhr.req;
+ kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), oldreq);
+
+
+ ////////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate?
+ var newreq = xhr.req = kb.bnode() // Make NEW reqest for everything else
+ kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req);
+
+ var now = new Date();
+ var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] ";
+ kb.add(newreq, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + newURI), this.appNode)
+ kb.add(newreq, ns.link('status'), kb.collection(), sf.req);
+ kb.add(newreq, ns.link("requestedURI"), kb.literal(newURI), this.appNode);
+
+ var response = kb.bnode();
+ kb.add(oldreq, ns.link('response'), response);
+ // kb.add(response, ns.http('status'), kb.literal(xhr.status), response);
+ // if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response)
+
+ xhr.abort()
+ xhr.aborted = true
+
+ sf.addStatus(oldreq, 'done') // why
+ sf.fireCallbacks('done', args) // Are these args right? @@@
+ sf.requested[xhr.uri.uri] = 'redirected';
+
+ var xhr2 = sf.requestURI(newURI, xhr.uri);
+ if (xhr2 && xhr2.req) kb.add(xhr.req,
+ kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'),
+ xhr2.req, sf.appNode); return;
+ }
+ }
+ sf.failFetch(xhr, "HTTP Blocked. (ReadyState 0) Cross-site violation for <"+
+ docuri+">");
+ break;
+
+ case 3:
+ // Intermediate state -- 3 may OR MAY NOT be called, selon browser.
+ handleResponse();
+ break
+ case 4:
+ // Final state
+ handleResponse();
+ // Now handle
+ if (xhr.handle) {
+ if (sf.requested[xhr.uri.uri] === 'redirected') {
+ break;
+ }
+ sf.fireCallbacks('load', args)
+ xhr.handle(function() {
+ sf.doneFetch(xhr, args)
+ })
+ } else {
+ sf.failFetch(xhr, "HTTP failed unusually. (no handler set) (cross-site violation?) for <"+
+ docuri+">");
+ }
+ break
+ } // switch
+ }
+
+ // Get privileges for cross-domain XHR
+ if (!(typeof tabulator != 'undefined' && tabulator.isExtension)) {
+ try {
+ $rdf.Util.enablePrivilege("UniversalXPConnect UniversalBrowserRead")
+ } catch (e) {
+ this.failFetch(xhr, "Failed to get (UniversalXPConnect UniversalBrowserRead) privilege to read different web site: " + docuri);
+ return xhr;
+ }
+ }
+
+ // Map the URI to a localhost proxy if we are running on localhost
+ // This is used for working offline, e.g. on planes.
+ // Is the script istelf is running in localhost, then access all data in a localhost mirror.
+ // Do not remove without checking with TimBL :)
+ var uri2 = docuri;
+ if (typeof tabulator != 'undefined' && tabulator.preferences.get('offlineModeUsingLocalhost')) {
+ // var here = '' + document.location // This was fro online version
+ //if (here.slice(0, 17) == 'http://localhost/') {
+ //uri2 = 'http://localhost/' + uri2.slice(7, uri2.length)
+ if (uri2.slice(0,7) == 'http://' && uri2.slice(7,17) != 'localhost/') uri2 = 'http://localhost/' + uri2.slice(7);
+ // dump("URI mapped to " + uri2)
+ }
+
+
+ // Setup the request
+ try {
+ xhr.open('GET', uri2, this.async)
+ } catch (er) {
+ return this.failFetch(xhr, "XHR open for GET failed for <"+uri2+">:\n\t" + er);
+ }
+
+ // Set redirect callback and request headers -- alas Firefox Extension Only
+
+ if (typeof tabulator != 'undefined' && tabulator.isExtension &&
+ $rdf.Util.uri.protocol(xhr.uri.uri) == 'http' ||
+ $rdf.Util.uri.protocol(xhr.uri.uri) == 'https') {
+ try {
+ xhr.channel.notificationCallbacks = {
+ getInterface: function(iid) {
+ if (!(typeof tabulator != 'undefined' && tabulator.isExtension)) {
+ $rdf.Util.enablePrivilege("UniversalXPConnect")
+ }
+ if (iid.equals(Components.interfaces.nsIChannelEventSink)) {
+ return {
+
+ onChannelRedirect: function(oldC, newC, flags) {
+ if (!(typeof tabulator != 'undefined' && tabulator.isExtension)) {
+ $rdf.Util.enablePrivilege("UniversalXPConnect")
+ }
+ if (xhr.aborted) return;
+ var kb = sf.store;
+ var newURI = newC.URI.spec;
+ var oldreq = xhr.req;
+ sf.addStatus(xhr.req, "Redirected: " + xhr.status + " to <" + newURI + ">");
+ kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), xhr.req);
+
+
+
+ ////////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate?
+ var newreq = xhr.req = kb.bnode() // Make NEW reqest for everything else
+ // xhr.uri = docterm
+ // xhr.requestedURI = args[0]
+ // var requestHandlers = kb.collection()
+
+ // kb.add(kb.sym(newURI), ns.link("request"), req, this.appNode)
+ kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req);
+
+ var now = new Date();
+ var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] ";
+ kb.add(newreq, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + newURI), this.appNode)
+ kb.add(newreq, ns.link('status'), kb.collection(), sf.req)
+ kb.add(newreq, ns.link("requestedURI"), kb.literal(newURI), this.appNode)
+ ///////////////
+
+
+ //// $rdf.log.info('@@ sources onChannelRedirect'+
+ // "Redirected: "+
+ // xhr.status + " to <" + newURI + ">"); //@@
+ var response = kb.bnode();
+ // kb.add(response, ns.http('location'), newURI, response); Not on this response
+ kb.add(oldreq, ns.link('response'), response);
+ kb.add(response, ns.http('status'), kb.literal(xhr.status), response);
+ if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response)
+
+ if (xhr.status - 0 != 303) kb.HTTPRedirects[xhr.uri.uri] = newURI; // same document as
+ if (xhr.status - 0 == 301 && rterm) { // 301 Moved
+ var badDoc = $rdf.Util.uri.docpart(rterm.uri);
+ var msg = 'Warning: ' + xhr.uri + ' has moved to <' + newURI + '>.';
+ if (rterm) {
+ msg += ' Link in <' + badDoc + ' >should be changed';
+ kb.add(badDoc, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg, sf.appNode);
+ }
+ // dump(msg+"\n");
+ }
+ xhr.abort()
+ xhr.aborted = true
+
+ sf.addStatus(oldreq, 'done') // why
+ sf.fireCallbacks('done', args) // Are these args right? @@@
+ sf.requested[xhr.uri.uri] = 'redirected';
+
+ var hash = newURI.indexOf('#');
+ if (hash >= 0) {
+ var msg = ('Warning: ' + xhr.uri + ' HTTP redirects to' + newURI + ' which should not contain a "#" sign');
+ // dump(msg+"\n");
+ kb.add(xhr.uri, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg)
+ newURI = newURI.slice(0, hash);
+ }
+ var xhr2 = sf.requestURI(newURI, xhr.uri);
+ if (xhr2 && xhr2.req) kb.add(xhr.req,
+ kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'),
+ xhr2.req, sf.appNode);
+
+ // else dump("No xhr.req available for redirect from "+xhr.uri+" to "+newURI+"\n")
+ },
+
+ // See https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIChannelEventSink
+ asyncOnChannelRedirect: function(oldC, newC, flags, callback) {
+ if (!(typeof tabulator != 'undefined' && tabulator.isExtension)) {
+ $rdf.Util.enablePrivilege("UniversalXPConnect")
+ }
+ if (xhr.aborted) return;
+ var kb = sf.store;
+ var newURI = newC.URI.spec;
+ var oldreq = xhr.req;
+ sf.addStatus(xhr.req, "Redirected: " + xhr.status + " to <" + newURI + ">");
+ kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), xhr.req);
+
+
+
+ ////////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate?
+ var newreq = xhr.req = kb.bnode() // Make NEW reqest for everything else
+ // xhr.uri = docterm
+ // xhr.requestedURI = args[0]
+ // var requestHandlers = kb.collection()
+
+ // kb.add(kb.sym(newURI), ns.link("request"), req, this.appNode)
+ kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req);
+
+ var now = new Date();
+ var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] ";
+ kb.add(newreq, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + newURI), this.appNode)
+ kb.add(newreq, ns.link('status'), kb.collection(), sf.req)
+ kb.add(newreq, ns.link("requestedURI"), kb.literal(newURI), this.appNode)
+ ///////////////
+
+
+ //// $rdf.log.info('@@ sources onChannelRedirect'+
+ // "Redirected: "+
+ // xhr.status + " to <" + newURI + ">"); //@@
+ var response = kb.bnode();
+ // kb.add(response, ns.http('location'), newURI, response); Not on this response
+ kb.add(oldreq, ns.link('response'), response);
+ kb.add(response, ns.http('status'), kb.literal(xhr.status), response);
+ if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response)
+
+ if (xhr.status - 0 != 303) kb.HTTPRedirects[xhr.uri.uri] = newURI; // same document as
+ if (xhr.status - 0 == 301 && rterm) { // 301 Moved
+ var badDoc = $rdf.Util.uri.docpart(rterm.uri);
+ var msg = 'Warning: ' + xhr.uri + ' has moved to <' + newURI + '>.';
+ if (rterm) {
+ msg += ' Link in <' + badDoc + ' >should be changed';
+ kb.add(badDoc, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg, sf.appNode);
+ }
+ // dump(msg+"\n");
+ }
+ xhr.abort()
+ xhr.aborted = true
+
+ sf.addStatus(oldreq, 'done') // why
+ sf.fireCallbacks('done', args) // Are these args right? @@@
+ sf.requested[xhr.uri.uri] = 'redirected';
+
+ var hash = newURI.indexOf('#');
+ if (hash >= 0) {
+ var msg = ('Warning: ' + xhr.uri + ' HTTP redirects to' + newURI + ' which should not contain a "#" sign');
+ // dump(msg+"\n");
+ kb.add(xhr.uri, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg)
+ newURI = newURI.slice(0, hash);
+ }
+ var xhr2 = sf.requestURI(newURI, xhr.uri);
+ if (xhr2 && xhr2.req) kb.add(xhr.req,
+ kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'),
+ xhr2.req, sf.appNode);
+
+ // else dump("No xhr.req available for redirect from "+xhr.uri+" to "+newURI+"\n")
+ } // asyncOnChannelRedirect
+ }
+ }
+ return Components.results.NS_NOINTERFACE
+ }
+ }
+ } catch (err) {
+ return sf.failFetch(xhr,
+ "@@ Couldn't set callback for redirects: " + err);
+ }
+
+ try {
+ var acceptstring = ""
+ for (var type in this.mediatypes) {
+ var attrstring = ""
+ if (acceptstring != "") {
+ acceptstring += ", "
+ }
+ acceptstring += type
+ for (var attr in this.mediatypes[type]) {
+ acceptstring += ';' + attr + '=' + this.mediatypes[type][attr]
+ }
+ }
+ xhr.setRequestHeader('Accept', acceptstring)
+ // $rdf.log.info('Accept: ' + acceptstring)
+
+ // See http://dig.csail.mit.edu/issues/tabulator/issue65
+ //if (requester) { xhr.setRequestHeader('Referer',requester) }
+ } catch (err) {
+ throw ("Can't set Accept header: " + err)
+ }
+ }
+
+ // Fire
+ try {
+ xhr.send(null)
+ } catch (er) {
+ return this.failFetch(xhr, "XHR send failed:" + er);
+ }
+ this.addStatus(xhr.req, "HTTP Request sent.");
+
+ // Drop privs
+ if (!(typeof tabulator != 'undefined' && tabulator.isExtension)) {
+ try {
+ $rdf.Util.disablePrivilege("UniversalXPConnect UniversalBrowserRead")
+ } catch (e) {
+ throw ("Can't drop privilege: " + e)
+ }
+ }
+
+ setTimeout(function() {
+ if (xhr.readyState != 4 && sf.isPending(xhr.uri.uri)) {
+ sf.failFetch(xhr, "requestTimeout")
+ }
+ }, this.timeout)
+ return xhr
+ }
+
+// this.requested[docuri]) != "undefined"
+
+ this.objectRefresh = function(term) {
+ var uris = kb.uris(term) // Get all URIs
+ if (typeof uris != 'undefined') {
+ for (var i = 0; i < uris.length; i++) {
+ this.refresh(this.store.sym($rdf.Util.uri.docpart(uris[i])));
+ //what about rterm?
+ }
+ }
+ }
+
+ this.unload = function(term) {
+ this.store.removeMany(undefined, undefined, undefined, term)
+ delete this.requested[term.uri]; // So it can be loaded again
+ }
+
+ this.refresh = function(term) { // sources_refresh
+ this.unload(term);
+ this.fireCallbacks('refresh', arguments)
+ this.requestURI(term.uri, undefined, true)
+ }
+
+ this.retract = function(term) { // sources_retract
+ this.store.removeMany(undefined, undefined, undefined, term)
+ if (term.uri) {
+ delete this.requested[$rdf.Util.uri.docpart(term.uri)]
+ }
+ this.fireCallbacks('retract', arguments)
+ }
+
+ this.getState = function(docuri) { // docState
+ if (typeof this.requested[docuri] != "undefined") {
+ if (this.requested[docuri]) {
+ if (this.isPending(docuri)) {
+ return "requested"
+ } else {
+ return "fetched"
+ }
+ } else {
+ return "failed"
+ }
+ } else {
+ return "unrequested"
+ }
+ }
+
+ //doing anyStatementMatching is wasting time
+ this.isPending = function(docuri) { // sources_pending
+ //if it's not pending: false -> flailed 'done' -> done 'redirected' -> redirected
+ return this.requested[docuri] == true;
+ }
+}
+
+$rdf.fetcher = function(store, timeout, async) { return new $rdf.Fetcher(store, timeout, async) };
+
+// Parse a string and put the result into the graph kb
+$rdf.parse = function parse(str, kb, base, contentType) {
+ try {
+ /*
+ parseXML = function(str) {
+ var dparser;
+ if ((typeof tabulator != 'undefined' && tabulator.isExtension)) {
+ dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService(
+ Components.interfaces.nsIDOMParser);
+ } else if (typeof module != 'undefined' ){ // Node.js
+ var jsdom = require('jsdom');
+ return jsdom.jsdom(str, undefined, {} );// html, level, options
+ } else {
+ dparser = new DOMParser()
+ }
+ return dparser.parseFromString(str, 'application/xml');
+ }
+ */
+ if (contentType == 'text/n3' || contentType == 'text/turtle') {
+ var p = $rdf.N3Parser(kb, kb, base, base, null, null, "", null)
+ p.loadBuf(str);
+ return;
+ }
+
+ if (contentType == 'application/rdf+xml') {
+ var parser = new $rdf.RDFParser(kb);
+ parser.parse($rdf.Util.parseXML(str), base, kb.sym(base));
+ return;
+ }
+
+ if (contentType == 'application/rdfa') { // @@ not really a valid mime type
+ $rdf.rdfa.parse($rdf.Util.parseXML(str), kb, base); // see rdfa.js
+ return;
+ }
+ } catch(e) {
+ throw "Error trying to parse <"+base+"> as "+contentType+":\n"+e;
+ }
+ throw "Don't know how to parse "+contentType+" yet";
+
+};
+
+
+// ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/NoWebId.xhtml Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (c) 2011 Henry Story (bblfish.net)
+ ~ under the MIT licence defined at
+ ~ http://www.opensource.org/licenses/mit-license.html
+ ~
+ -->
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head id="head">
+ <title>WebId Tests</title>
+ <script src="/public/logout.js" type="text/javascript"/>
+ </head>
+<body>
+ <h1>WebID Authentication Report</h1>
+
+ <p>This page describes in detail the state of your <a href="http://webid.info/spec">WebID authentication</a>
+ session on <span class="date">Thu Nov 17 08:31:53 PST 2011.</span> </p>
+
+ <p>We received no certificate from you. <a href="" onclick="return logout()">try again</a>
+ (works on IE and Firefox)</p>
+
+
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/WebId.xhtml Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,106 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head id="head">
+ <title>WebId Tests</title>
+ <script src="/public/logout.js" type="text/javascript"/>
+ <style type="text/css">
+ .outcome_passed {color: green}
+ .outcome_failed { color: red}
+ .outcome_untested {color: orange}
+ </style>
+ </head>
+<body>
+ <h1>WebID Authentication Report</h1>
+ <p>This page describes in detail the state of your <a href="http://webid.info/spec">WebID authentication</a> session
+ on <span class="date">Thu Nov 17 08:31:53 PST 2011.</span> </p>
+
+ <p><a href="" onclick="return logout()">logout</a> -- (only works on IE and Firefox)</p>
+
+ <h2>WebID</h2>
+ <div class="webid_tests">
+ <p><span class="san_number">2</span> Subject Alternative Names were found in your Certificate. <span class="san_verified">Of these we verified
+ <span class="san_verified_no">245</span>.</span></p>
+ <table width="100%" rules="groups">
+ <tbody class="webid_test">
+ <tr><td colspan="2">Verification of <span class="webid">http://bblfish.net/#me</span>?</td> </tr>
+ <tr><td class="tst_res">result</td><td class="tst_res_txt">found 1 valid ID</td></tr>
+ <tr class="webid_cause"><td>cause</td><td class="cause_txt"></td></tr>
+ </tbody>
+ </table>
+ </div>
+
+ <h2>Certificate</h2>
+
+ <table width="100%" rules="groups">
+ <tbody class="cert_test">
+ <tr><td colspan="2" class="tst_question">Could at least one WebID claim be verified?</td> </tr>
+ <tr><td class="tst_res">passed</td><td class="tst_res_txt">found 1 valid principals</td></tr>
+ </tbody>
+ </table>
+
+ <pre id="cert" class="certificate">
+ [
+[
+ Version: V3
+ Subject: CN=bblfish card, UID="http://bblfish.net/people/henry/card#me", OU=The Community Of Self Signers, O="FOAF+SSL"
+ Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
+
+ Key: Sun RSA public key, 2048 bits
+ modulus: 29276035035233808417997195473778175708233314700694241553008612528653781013623122865570033487009536689247533331761722724660608054531558090663455411500325187338854460881301515279078846015120633986716818977529842189338176012229254648239522297497009662210454225806222613866046067793530738567337748639961376015224198752644381326876084270910516940108410574284271163097309003672549551471387551533430789028823217042638678304885964246676816153930097022404865758197235094201678987827523441881216134115935329236878612750489032605710888040354783823145723591295889526935774242920905400540513434433523747939289419807546467215299433
+ public exponent: 65537
+ Validity: [From: Mon Mar 28 16:06:50 CEST 2011,
+ To: Sun Mar 18 17:06:50 CET 2012]
+ Issuer: CN=Not a Certification Authority, OU=The Community of Self Signers, O="FOAF+SSL"
+ SerialNumber: [ 67ce0006 f8638fb8 6a1685aa 4acbc116]
+
+Certificate Extensions: 5
+[1]: ObjectId: 2.5.29.14 Criticality=false
+SubjectKeyIdentifier [
+KeyIdentifier [
+0000: CE 84 32 EF 53 A7 2B 25 BC A8 4E DB A0 E1 E9 2E ..2.S.+%..N.....
+0010: B8 CD D9 A4 ....
+]
+]
+
+[2]: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
+NetscapeCertType [
+ SSL client
+ S/MIME
+]
+
+[3]: ObjectId: 2.5.29.17 Criticality=true
+SubjectAlternativeName [
+ URIName: http://bblfish.net/people/henry/card#me
+]
+
+[4]: ObjectId: 2.5.29.15 Criticality=true
+KeyUsage [
+ DigitalSignature
+ Non_repudiation
+ Key_Encipherment
+ Key_Agreement
+ Key_CertSign
+]
+
+[5]: ObjectId: 2.5.29.19 Criticality=true
+BasicConstraints:[
+ CA:false
+ PathLen: undefined
+]
+
+]
+ Algorithm: [SHA1withRSA]
+ Signature:
+0000: 7D 24 C5 20 43 60 60 0C 6A 1E 1C 96 8C E7 8E C9 .$. C``.j.......
+0010: E0 94 63 4C 09 37 76 CC FB 71 9D 60 C5 52 3B 83 ..cL.7v..q.`.R;.
+0020: D9 85 A1 73 C4 17 77 F9 3B 4F 51 A5 55 97 4B 7D ...s..w.;OQ.U.K.
+0030: 3D 7B E7 F0 FB 8D 8A 57 11 51 FB 53 23 BC 0D 39 =......W.Q.S#..9
+0040: ED B6 50 1E 3E 60 EA 6E CA 53 FA F7 29 57 5A 2B ..P.>`.n.S..)WZ+
+0050: 52 B5 A5 31 32 7B 84 0C CF 12 FF 5A 04 E1 EB 64 R..12......Z...d
+0060: FC 8A 0D E5 09 3B 42 60 C0 05 B1 39 4F CD 0F 7E .....;B`...9O...
+0070: 3B 4A C8 37 95 36 C5 B7 48 EB 67 10 CB 1C BC 42 ;J.7.6..H.g....B
+
+]
+ </pre>
+
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/WebIdService.login.xhtml Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2011 Henry Story (bblfish.net)
+ ~ under the MIT licence defined at
+ ~ http://www.opensource.org/licenses/mit-license.html
+ ~
+ ~ Permission is hereby granted, free of charge, to any person obtaining a copy of
+ ~ this software and associated documentation files (the "Software"), to deal in the
+ ~ Software without restriction, including without limitation the rights to use, copy,
+ ~ modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ ~ and to permit persons to whom the Software is furnished to do so, subject to the
+ ~ following conditions:
+ ~
+ ~ The above copyright notice and this permission notice shall be included in all
+ ~ copies or substantial portions of the Software.
+ ~
+ ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ ~ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ ~ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ ~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ ~ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ ~ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head id="head">
+ <title>WebId Identity Provider Info Page</title>
+ <script src="/public/logout.js" type="text/javascript" />
+</head>
+<body>
+
+<p>Welcome <span class="user_name">Henry Story</span></p>
+
+<table>
+ <tr>
+ <td>
+ <a class="rp_url" href="http://bblfish.net/?webid=http%3A%2F%2Fbblfish.net%2Fpeople%2Fhenry%2Fcard%23me&ts=2011-12-04T01%3A16%3A58-0800&sig=GgxhFmf__2M0aQDjFU4Yg1bfjk90npXOUo6Mn_5xL4Z7H5mVP1BpDmoBorFT5uVvkDWOaSRU6ka2oo04GgoIsL9xODiYej7u0Cg-lEnA8aqL_7_X2pv1j3C6nPj-huZctEDi3QmmggtKsOVRp_0q8l9mmqIU-TBRyLjkk3mk6yUcWyAUu-pMP6DHqV-XVwys5Y3UYmeM3lPqOS_6wdd-qS-GkSZadtJEXu-IPUBEFWrVzGEx_Bu-WWWqbU5r0N6iY5PxmsZkKCSSdxfjGV-kjtHNcTQFbSlaGPkKeEEAPDLtoxxpBdaRUy4oO6biAW5tfp_eId_sfVHxLhaxqU9jnA">
+ <button>login to <span class="rp_name">bblfish.net</span></button>
+ </a>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <img class="mugshot" src="http://farm1.static.flickr.com/164/373663745_e2066a4950.jpg" alt="mugshot"/>
+ </td>
+ </tr>
+</table>
+
+<p>Or would you rather use a different Identity? <a href="" onclick="return logout()">logout</a> -- (only works on IE and Firefox)</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/hello.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <title>Template Title</title>
+</head>
+<body>
+ <h1 class="title">Template Title</h1>
+ <p> hi</p>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/hello.ssp Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <title>${title}</title>
+</head>
+<body>
+ <h1>again ${title}</h1>
+ <p> hi</p>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/webidp/WebIdService.about.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<!--
+ ~ Copyright (c) 2011 Henry Story (bblfish.net)
+ ~ under the MIT licence defined at
+ ~ http://www.opensource.org/licenses/mit-license.html
+ -->
+<html>
+<head>
+ <title>WebID Authentication Service</title>
+ <script src="/public/logout.js" type="text/javascript"></script>
+ <!-- using unfiltered urls just because of super big hurry, replace them with local variants by new year -->
+ <link type="text/css" media="screen, projection" rel="stylesheet" href="http://unfiltered.databinder.net/css/blueprint/screen.css"/>
+ <link type="text/css" media="screen and (min-device-width: 800px), projection" rel="stylesheet" href="http://unfiltered.databinder.net/css/blueprint/grid.css"/>
+ <link type="text/css" media="print" rel="stylesheet" href="http://unfiltered.databinder.net/css/blueprint/print.css"/>
+ <!--[if lt IE 8]>
+ <link rel="stylesheet" href="http://unfiltered.databinder.net/css/blueprint/ie.css" type="text/css" media="screen, projection"/>
+ <![endif]-->
+ <link type="text/css" media="screen, projection" rel="stylesheet" href="http://unfiltered.databinder.net/css/pamflet.css"/>
+ <link type="text/css" media="print" rel="stylesheet" href="http://unfiltered.databinder.net/css/pamflet-print.css"/>
+ <link type="text/css" media="screen and (min-device-width: 800px), projection" rel="stylesheet" href="http://unfiltered.databinder.net/css/pamflet-grid.css"/>
+
+ <script src="js/jquery-1.6.2.min.js"></script>
+ <script src="js/pamflet.js"></script>
+ <script type="text/javascript" src="http://unfiltered.databinder.net/js/prettify/prettify.js"></script><script type="text/javascript" src="js/prettify/lang-scala.js"></script><link type="text/css" rel="stylesheet" href="css/prettify.css"/><script type="text/javascript"><!--
+ window.onload=function() { prettyPrint(); };
+ --></script>
+ <meta charset="utf-8"></meta>
+ <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
+</head>
+<body>
+
+
+<a class="page prev nav" href="Plans+and+Intents.html">
+ <span class="space"></span>
+ <span class="flip">☯</span>
+</a><a class="page next nav" href="Project+Setup.html">
+ <span class="space"></span>
+ <span>☯</span>
+</a>
+
+<div class="container">
+ <div class="span-16 prepend-1 append-1">
+ <div class="top nav span-16 title">
+ <span>WebID Identity Provider</span>
+ </div>
+ </div>
+ <div class="span-16 prepend-1 append-1 contents">
+ <p>This is a simple Identity Provider for <a href="http://webid.info/spec">WebID</a>. It is meant to help
+ sites that would like to provide WebID authentication to their users quickly. .</p>
+
+ <p>If you are hosting such a site then you can rely on this service to help authenticate your users with WebID,
+ without your needing to set up https on your server. When you are satisfied of its usefulness you can deploy
+ it to your site.</p>
+
+ <p>There are two stages to get going. First you need to create the login button linking to this service. Then
+ you need to
+ understand how to interpret what will be returned, so that you can write a script to authenticate
+ your users with the given WebID - ie, set a cookie for them.</p>
+
+ <h2>Create your login link</h2>
+
+ <p>Create a login button or link that points to this service. This needs to contain an attribute as a URL to a
+ script on your site so that we can send you the response. This will be done by redirecting the user's
+ browser
+ with a signed response containing his WebID. To create such a link enter the URL of your login service
+ here:</p>
+
+ <form action="" method="get">Requesting auth service URL: <br/>
+ <input name="rs" size="80" type="text"/>
+ <input type="submit" value="Use this Service"/>
+ </form>
+ <p>By clicking on the form you will land on a page whose URL is the one you should enter into your
+ login button/link. You will also see what identity you were logged in as, and given some options to change
+ it.
+ </p>
+
+ <h2>Understanding the response</h2>
+
+ <p>The redirected to URL is constructed on the following pattern: </p>
+ <pre><b>$relyingService?webid=$webid&ts=$timeStamp</b>&sig=$URLSignature</pre>
+ <p>Where the above variables have the following meanings: </p>
+ <ul>
+ <li><code>$relyingService</code> is the URL passed by the server in
+ the initial request as the <code>rs</code> parameter, and is the service to which the response is sent.
+ </li>
+ <li><code>$webid</code> is the WebID of the user connecting.</li>
+ <li><code>$timeStamp</code> is a time stamp in XML Schema format
+ (same as used by Atom). This is needed to reduce the ease of developing
+ replay attacks.
+ </li>
+ <li><code>$URLSignature</code> is the signature of the whole URL
+ in bold above using the public key shown below, and encoded in a
+ <a href="http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html#encodeBase64URLSafeString%28byte[]%29">URL
+ friendly base64</a> encoding.
+ </li>
+ </ul>
+
+ <h3>Error responses</h3>
+
+ <p>In case of error the service gets redirected to <code>$relyingService?error=$code</code>Where
+ $code can be either one of</p>
+ <ul>
+ <li><code>nocert</code>: when the client has no cert.</li>
+ <li><code>noVerifiedWebId</code>: no verified WebId was found in the certificate</li>
+ <li><code>noWebId</code>: todo: show this error when there are no webids at all</li>
+ <li><code>IdPError</code>: for some error in the IdP setup. Warn
+ the IdP administrator!
+ </li>
+ <li>other messages, not standardised yet</li>
+ </ul>
+
+ <h2>Verifiying the WebId</h2>
+
+ <p>In order for the Relying Party to to be comfortable that the returned WebId
+ was not altered in transit, the whole URL is signed by this server as
+ shown above. Here are the public keys and algorithms this us using:</p>
+
+
+ <p>The signature uses the RSA with SHA-1 algorithm.</p>
+
+ <p>The public key used by this service that verifies the signature is: </p>
+
+ <ul>
+ <li>Key Type:
+ <pre>http://www.w3.org/ns/auth/rsa#RSAPublicKey</pre>
+ </li>
+ <li>public exponent (decimal):
+ <pre class="exponent">65537</pre>
+ </li>
+ <li>modulus (decimal):<br/>
+ <pre class="modulus">84:56:e8:8b:04:b9:1f:3b:10:00:07:ab:18:e8:fc:66:4e:aa:bc:47:f6:
+41:56:ab:96:6f:9c:d5:fc:5d:e9:fd:ce:a1:0f:5e:ce:26:f5:2e:35:e2:
+b7:0f:b3:db:17:0b:1b:c9:73:69:39:8a:39:4d:23:c3:b2:99:a7:a5:8b:
+5b:a8:2a:84:05:a3:d8:14:35:2e:49:7d:47:b6:80:52:90:37:ca:99:39:
+da:08:a4:f2:ef:f9:26:25:a9:4e:dd:44:57:df:43:3f:95:cd:cf:34:3f:
+41:58:e4:bc:19:63:ad:8f:b5:65:e3:3e:5e:d2:b3:19:f6:ca:ed:e5:a1:
+e7:cd:f1:9f:70:04:ea:66:a9:ad:77:cb:02:8d:c1:8d:45:89:39:07:b4:
+54:71:98:82:b0:55:39:c4:50:ad:24:3a:df:8f:df:fa:39:36:da:d9:98:
+65:1c:dd:4d:3f:d9:09:a7:5e:2d:de:cd:af:22:1e:25:b1:2e:d1:6d:74:
+e4:96:2f:2a:87:5a:c1:23:37:ff:38:ed:e1:f5:c5:20:fc:81:cf:cb:c7:
+1e:61:d1:77:6b:32:0d:6a:94:cb:8e:98:55:07:ea:09:f5:01:75:79:07:
+6e:f5:50:06:d0:1f:bd:11:94:85:86:c5:42:6f:76:e9:a9:fa:cf:db:91:
+13:92:c2:69:
+</pre>
+ </li>
+ </ul>
+ </div>
+</div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/webidp/WebIdService.auth.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!--
+ ~ Copyright (c) 2011 Henry Story (bblfish.net)
+ ~ under the MIT licence defined at
+ ~ http://www.opensource.org/licenses/mit-license.html
+ -->
+<html>
+<head>
+ <title>WebID Authentication Service</title>
+ <link rel="stylesheet" type="text/css" href="idp/production.min.css"/>
+ <script src="/public/logout.js" type="text/javascript"></script>
+ <script src="idp/jquery.1.7.1.min.js"></script>
+ <script>
+ $(needyLogin);
+ </script>
+</head>
+
+<body class="form">
+
+
+<div id="wrapper">
+ <header id="header" class="cf">
+ <div class="wrapper">
+ <img id="logo" src="idp/icon.png"/>
+ </div>
+ </header>
+
+ <div id="content">
+ <section id="formWrap">
+ <form id="login" class="webidform" novalidate="" action="WebIdService.auth.html" method="POST">
+ <div id="favicon">
+ <div class="vertical">
+ <a class="response auth" href="http://webid.fcns.eu/"><span class="button sitename" id="sitename">webid.fcns.eu</span></a>
+ </div>
+ </div>
+ <div id="signIn">
+ <div class="arrow"></div>
+ <div class="table">
+ <div class="vertical contents">
+ <div class="form_section">
+ <span class="authenticated">
+ <p><b>Name:</b> <span class="user_name">Bblfish</span></p>
+ <img class="mugshot" height="100px" src="http://bblfish.net/pix/bfish.small.east.jpg" alt="User avatar"/>
+ </span>
+ <div class="submit cf">
+ <input type="submit" class="light" tabindex="3" value="change id" onclick="logout()"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </form>
+ </section>
+
+ <section id="wait" style="display: none; ">
+ <div class="table">
+ <div class="vertical contents">
+ <h2>Communicating with server</h2>
+
+ <p>Just a moment while we talk with the server.</p>
+ </div>
+ </div>
+ </section>
+
+
+ <section id="error">
+ <div class="table">
+ <div class="vertical contents">
+ </div>
+ </div>
+ </section>
+
+ </div>
+
+</div>
+<!-- END OF SITE_WRAPPER -->
+
+<footer>
+ WebID for a distributed Secure Social Web ... Now !
+</footer>
+<!-- END OF FOOTER -->
+
+
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/webidp/WebIdService.badcert.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<!--
+ ~ Copyright (c) 2011 Henry Story (bblfish.net)
+ ~ under the MIT licence defined at
+ ~ http://www.opensource.org/licenses/mit-license.html
+ -->
+<html>
+<head>
+ <title>WebID Authentication Service</title>
+ <link rel="stylesheet" type="text/css" href="idp/production.min.css"/>
+ <script src="idp/jquery.1.7.1.min.js"></script>
+ <script src="/public/logout.js" type="text/javascript"></script>
+ <script>
+ $(needyLogin);
+ </script>
+
+</head>
+
+<body class="form">
+
+<div id="wrapper">
+<header id="header" class="cf">
+ <div class="wrapper">
+ <img id="logo" src="idp/icon.png"/>
+ </div>
+</header>
+
+
+<div id="content">
+ <section id="formWrap">
+ <form id="login" class="webidform" novalidate="" action="WebIdService.auth.html" method="POST">
+ <div id="favicon">
+ <div class="vertical">
+ <a class="response" href="http://webid.fcns.eu/"><strong class="sitename" id="sitename">webid.fcns.eu</strong></a>
+ </div>
+ </div>
+ <div id="signIn">
+ <div class="arrow"></div>
+ <div class="table">
+ <div class="vertical contents">
+ <strong class="error">Certificate missing a WebID</strong> (<a href="/test/WebId">details</a>)
+ <div class="form_section">
+ <img class="depiction" src="idp/profile_anonymous.png"/>
+ <div class="submit cf">
+ <input type="submit" class="button" tabindex="3" value="try again" onclick="logout()"/>
+ <button class="newuser" tabindex="3">verify email</button>
+ <button class="returning" tabindex="3">select email</button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </form>
+ </section>
+
+
+ <section id="wait" style="display: none; ">
+ <div class="table">
+ <div class="vertical contents">
+ <h2>Communicating with server</h2>
+ <p>Just a moment while we talk with the server.</p>
+ </div>
+ </div>
+ </section>
+
+
+ <section id="error">
+ <div class="table">
+ <div class="vertical contents">
+ </div>
+ </div>
+ </section>
+
+</div>
+
+</div> <!-- END OF SITE_WRAPPER -->
+
+ <footer>
+ WebID for a distributed Secure Social Web ... Now !
+ </footer> <!-- END OF FOOTER -->
+
+
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/webidp/WebIdService.entry.html Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<!--
+ ~ Copyright (c) 2011 Henry Story (bblfish.net)
+ ~ under the MIT licence defined at
+ ~ http://www.opensource.org/licenses/mit-license.html
+ -->
+<html>
+<head>
+ <title>WebID Authentication Service</title>
+ <link rel="stylesheet" type="text/css" href="idp/production.min.css"/>
+ <script src="/public/logout.js" type="text/javascript"></script>
+ <script src="idp/jquery.1.7.1.min.js"></script>
+ <script src="idp/util.js" type="text/javascript"></script>
+ <script>
+ $(needyLogin);
+ </script>
+</head>
+
+<body class="form">
+
+<div id="wrapper">
+<header id="header" class="cf">
+ <div class="wrapper">
+ <img id="logo" src="idp/icon.png"/>
+ </div>
+</header>
+
+
+<div id="content">
+ <section id="formWrap">
+ <form id="login" class="webidform" novalidate="" action="WebIdService.badcert.html" method="POST">
+ <div id="favicon">
+ <div class="vertical">
+ <a class="response" href="http://webid.fcns.eu/"><strong class="sitename" id="sitename">webid.fcns.eu</strong></a>
+ </div>
+ </div>
+ <div id="signIn">
+ <div class="arrow"></div>
+ <div class="table">
+ <div class="vertical contents">
+ <img class="depiction" src="idp/profile_anonymous.png"/>
+ <div class="form_section">
+ <div class="submit cf">
+ <input type="submit" class="button" tabindex="3" value="sign in"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </form>
+ </section>
+
+ <section id="wait" style="display: none; ">
+ <div class="table">
+ <div class="vertical contents">
+ <h2>Communicating with server</h2>
+ <p>Just a moment while we talk with the server.</p>
+ </div>
+ </div>
+ </section>
+
+
+ <section id="error">
+ <div class="table">
+ <div class="vertical contents">
+ </div>
+ </div>
+ </section>
+
+</div>
+
+</div> <!-- END OF SITE_WRAPPER -->
+
+ <footer>
+ WebID ready for the Secure Social Web
+ </footer> <!-- END OF FOOTER -->
+
+
+</body>
+</html>
Binary file src/main/resources/template/webidp/idp/auth_arrow.png has changed
Binary file src/main/resources/template/webidp/idp/bg.png has changed
Binary file src/main/resources/template/webidp/idp/icon.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/webidp/idp/jquery.1.7.1.min.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,4 @@
+/*! jQuery v1.7.1 jquery.com | jquery.org/license */
+(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};
+ f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function()
+ {for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/webidp/idp/production.min.css Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,806 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla BrowserID.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Lloyd Hilaiel <lloyd@hilaiel.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/** Adapted for WebID, by Henry Story */
+
+* {
+ margin: 0;
+ padding: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -o-box-sizing: border-box;
+ box-sizing: border-box
+}
+
+html, body {
+ height: 100%
+}
+
+body {
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ line-height: 21px;
+ background-image: url('bg.png');
+ overflow-y: scroll
+}
+
+.cf:after {
+ content: ".";
+ display: block;
+ clear: both;
+ visibility: hidden;
+ line-height: 0;
+ height: 0
+}
+
+html[xmlns] .cf {
+ display: block
+}
+
+* html .cf {
+ height: 1%
+}
+
+.sans {
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif
+}
+
+.serif {
+ font-family: 'Droid Serif', Georgia, serif
+}
+
+.mono {
+ font-family: 'Monaco', monospace
+}
+
+.tooltip {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ background: #000;
+ background: rgba(0, 0, 0, .7);
+ color: #fff;
+ border-radius: 5px;
+ padding: 2px 15px;
+ border: 2px solid #000;
+ font-weight: bold;
+ display: none;
+ max-width: 275px;
+ z-index: 5
+}
+
+a {
+ color: #222;
+ text-decoration: none
+}
+
+a:hover, button:hover {
+ text-decoration: underline
+}
+
+p:last-child {
+ margin-bottom: 0 !important
+}
+
+input[type=email], input[type=password] {
+ width: 100%;
+ font-size: 14px;
+ padding: 5px;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #a3a29d #c6c3b4 #c6c3b4 #a3a29d;
+ outline: 0;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -o-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5);
+ -moz-box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5);
+ -o-box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5);
+ box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5)
+}
+
+input[type=email]:focus, input[type=password]:focus {
+ border: 1px solid #549fdc;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0;
+ -webkit-box-shadow: 0 0 0 1px #549fdc inset;
+ -moz-box-shadow: 0 0 0 1px #549fdc inset;
+ -o-box-shadow: 0 0 0 1px #549fdc inset;
+ box-shadow: 0 0 0 1px #549fdc inset
+}
+
+input[type=email]:disabled, input[type=password]:disabled {
+ background-color: #f0f0f0;
+ color: #4f4f4f
+}
+
+input[type=radio], input[type=checkbox] {
+ cursor: pointer
+}
+
+img.depiction {
+ float: left;
+}
+
+a.auth {
+ text-decoration: none;
+}
+
+span[class~="sitename"] {
+ text-decoration: none;
+ font-size: 28px;
+ height: 52px;
+ padding: 7px 25px;
+ float: none;
+ vertical-align: middle;
+ border: 1px solid #37a6ff;
+ font-family: 'Droid Serif', Georgia, serif;
+ color: #fff;
+ text-shadow: -1px -1px 0 #37a6ff;
+ text-transform: lowercase;
+ cursor: pointer;
+ -webkit-box-shadow: 0 0 0 1px #76c2ff inset;
+ -moz-box-shadow: 0 0 0 1px #76c2ff inset;
+ -o-box-shadow: 0 0 0 1px #76c2ff inset;
+ box-shadow: 0 0 0 1px #76c2ff inset;
+ -webkit-border-radius: 8px;
+ -moz-border-radius: 8px;
+ -o-border-radius: 8px;
+ border-radius: 8px;
+ background-color: #37a6ff;
+ background-image: -moz-linear-gradient(center top, #76c2ff 0, #37a6ff 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #76c2ff), color-stop(100%, #37a6ff))
+}
+
+
+button, .button {
+ font-size: 14px;
+ height: 28px;
+ padding: 0 10px;
+ float: right;
+ vertical-align: middle;
+ border: 1px solid #37a6ff;
+ font-family: 'Droid Serif', Georgia, serif;
+ color: #fff;
+ text-shadow: -1px -1px 0 #37a6ff;
+ text-transform: lowercase;
+ cursor: pointer;
+ -webkit-box-shadow: 0 0 0 1px #76c2ff inset;
+ -moz-box-shadow: 0 0 0 1px #76c2ff inset;
+ -o-box-shadow: 0 0 0 1px #76c2ff inset;
+ box-shadow: 0 0 0 1px #76c2ff inset;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -o-border-radius: 5px;
+ border-radius: 5px;
+ background-color: #37a6ff;
+ background-image: -moz-linear-gradient(center top, #76c2ff 0, #37a6ff 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #76c2ff), color-stop(100%, #37a6ff))
+}
+
+button:hover, button:focus, .button:hover, .button:focus {
+ background-color: #76c2ff;
+ background-image: -moz-linear-gradient(center top, #76c2ff 50%, #37a6ff 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(50%, #76c2ff), color-stop(100%, #37a6ff))
+}
+
+button:active, .button:active {
+ background-color: #006ec6;
+ border: 1px solid #003e70;
+ color: #eee;
+ text-shadow: -1px -1px 0 #006ec6;
+ -webkit-box-shadow: 0 0 5px #003763 inset;
+ -moz-box-shadow: 0 0 5px #003763 inset;
+ -o-box-shadow: 0 0 5px #003763 inset;
+ box-shadow: 0 0 5px #003763 inset;
+ background-image: -moz-linear-gradient(center top, #3aa7ff 0, #006ec6 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #3aa7ff), color-stop(100%, #006ec6))
+}
+
+button::-moz-focus-inner, .button::-moz-focus-inner {
+ padding: 0;
+ border: 0
+}
+
+
+button[disabled] {
+ opacity: .5
+}
+
+hr {
+ height: 1px;
+ border: 0;
+ background-color: #eee;
+ width: 700px
+}
+
+.right {
+ text-align: right
+}
+
+h1 {
+ font-size: 24px;
+ font-weight: normal;
+ text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5)
+}
+
+header ul li {
+ display: inline-block;
+ float: left
+}
+
+header a {
+ color: #222
+}
+
+header a.home {
+ width: 80px;
+ height: 21px;
+ background-image: url('icon.png');
+ display: block;
+ background-position: left 4px;
+ background-repeat: no-repeat
+}
+
+footer {
+ color: #aaa
+}
+
+footer a {
+ color: #aaa
+}
+
+footer ul li {
+ display: inline-block;
+ float: left;
+ margin: 0 10px 0 0
+}
+
+footer .help {
+ float: right;
+ color: #62615f;
+ cursor: help
+}
+
+.cancelVerify {
+ font-weight: bold
+}
+
+h2 {
+ margin-bottom: 20px;
+ font-size: 150%;
+ color: #222;
+ font-weight: bold
+}
+
+#wrapper {
+ min-width: 640px;
+ position: relative
+}
+
+.table {
+ display: table;
+ width: 100%
+}
+
+.vertical {
+ height: 250px;
+ display: table-cell;
+ vertical-align: middle;
+ width: 100%
+}
+
+#content {
+ position: relative;
+ height: 250px;
+ overflow: hidden
+}
+
+section {
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ z-index: 0
+}
+
+section>.contents {
+ display: table-cell;
+ vertical-align: middle;
+ height: 250px
+}
+
+#wait {
+ text-align: center;
+ z-index: 1;
+ background-image: url("bg.png")
+}
+
+#error {
+ position: absolute;
+ text-align: center;
+ display: none;
+ z-index: 2;
+ background-color: #fff
+}
+
+#error ul, #error li {
+ list-style-type: none
+}
+
+#wait strong, #error strong {
+ color: #222;
+ font-weight: bold
+}
+
+#error.unsupported .vertical {
+ width: 630px;
+ margin: 0 auto;
+ display: block
+}
+
+#error.unsupported .vertical>div {
+ display: table-cell;
+ vertical-align: middle;
+ padding: 0 10px;
+ height: 250px
+}
+
+#error #moreInfo {
+ display: none
+}
+
+#error a {
+ color: #549fdc;
+ text-decoration: underline
+}
+
+#error #borderbox {
+ border-left: 1px solid #777;
+ padding: 20px 0
+}
+
+#error #borderbox img {
+ border: 0
+}
+
+#error #alternative .lighter {
+ color: #777
+}
+
+#formWrap {
+ background-color: #fff;
+ background-image: none;
+ display: block
+}
+
+#signIn {
+ background-image: url('bg.png');
+ position: absolute;
+ left: 0;
+ top: 0
+}
+
+#signIn .table {
+ width: 325px;
+ margin-right: 40px
+}
+
+.arrow {
+ width: 40px;
+ height: 250px;
+ display: block;
+ position: absolute;
+ right: 0;
+ top: 0;
+ background-image: url('auth_arrow.png');
+ background-repeat: no-repeat;
+ background-position: center;
+ background-color: #fff
+}
+
+#favicon {
+ position: absolute;
+ left: 375px;
+ top: 0;
+ right: 0;
+ z-index: 10
+}
+
+#favicon strong {
+ font-size: 1.5em
+}
+
+#favicon img {
+ display: block;
+ margin: 0 auto 10px
+}
+
+#favicon .vertical {
+ display: block;
+ line-height: 250px;
+ text-align: center;
+ overflow: hidden;
+ text-overflow: ellipsis
+}
+
+div#required_email {
+ padding-top: .7em;
+ font-size: 1.2em;
+ font-weight: bold
+}
+
+#signIn .vertical {
+ padding: 0 20px
+}
+
+#signIn .vertical ul {
+ list-style-type: none;
+ position: relative
+}
+
+#signIn .vertical ul li {
+ margin-top: 10px
+}
+
+#signIn .vertical ul li:first-child {
+ margin-top: 0
+}
+
+#signIn .submit {
+ line-height: 28px;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0
+}
+
+#signIn .submit>p {
+ line-height: 13px;
+ clear: right;
+ text-align: center
+}
+
+#signIn label.half, .half {
+ width: 50%;
+ display: inline-block;
+ float: left
+}
+
+#forgotPassword {
+ color: #888784;
+ text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5);
+ font-size: 11px
+}
+
+#signIn button.create {
+ font-size: 14px;
+ height: 28px;
+ padding: 0 10px;
+ float: right
+}
+
+label {
+ display: block;
+ color: #62615f;
+ text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5)
+}
+
+label.selectable {
+ cursor: pointer
+}
+
+.inputs>li>label {
+ color: #333
+}
+
+.inputs>li>label.preselected {
+ font-weight: bold
+}
+
+.inputs>li:only-child>label.selectable {
+ cursor: default
+}
+
+.learn {
+ display: inline-block;
+ font-size: 12px;
+ color: #62615f;
+ text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5)
+}
+
+footer .learn a {
+ color: #549fdc
+}
+
+.checkregistration p {
+ color: #62615f;
+ text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5)
+}
+
+header {
+ padding: 20px;
+ font-weight: bold;
+ background-color: rgba(0, 0, 0, 0.05);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.15);
+ -webkit-box-shadow: 0 -5px 5px -5px rgba(0, 0, 0, 0.1) inset;
+ -moz-box-shadow: 0 -5px 5px -5px rgba(0, 0, 0, 0.1) inset;
+ -o-box-shadow: 0 -5px 5px -5px rgba(0, 0, 0, 0.1) inset;
+ box-shadow: 0 -5px 5px -5px rgba(0, 0, 0, 0.1) inset
+}
+
+header ul {
+ display: block;
+ float: left
+}
+
+header ul li {
+ margin: 0 10px 0 0;
+ color: #222;
+ text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.5)
+}
+
+header, footer {
+ display: block;
+ width: 100%;
+ border-top: 1px solid rgba(0, 0, 0, 0.05)
+}
+
+footer {
+ padding: 20px
+}
+
+.inputs {
+ margin: 1em 0 .5em;
+ padding: 0 1em;
+ line-height: 18px
+}
+
+.pickemail .inputs {
+ max-height: 110px;
+ overflow-y: auto;
+ position: relative
+}
+
+.form_section {
+ height: 176px;
+ position: relative
+}
+
+.add {
+ font-size: 80%
+}
+
+.inputs>li:only-child input[type=radio] {
+ display: none
+}
+
+label[for=remember] {
+ display: inline;
+ margin-left: 13px
+}
+
+#thisIsNotMe {
+ margin-right: 10px;
+ float: right
+}
+
+#useNewEmail {
+ margin-left: .8em
+}
+
+.pickemail .vertical a {
+ background-color: #f0efed;
+ color: #4e4e4e;
+ font-size: .75em;
+ padding: 0 5px;
+ display: inline-block;
+ line-height: 18px
+}
+
+.submit>button {
+ margin: 0 5px 0 0
+}
+
+#newEmail {
+ -moz-box-flex: 1
+}
+
+.newuser, .forgot, .returning {
+ display: none
+}
+
+#create_text_section {
+ color: #222
+}
+
+#checkemail {
+ text-align: center
+}
+
+@media screen and (max-width:640px) {
+ #wrapper {
+ min-width: 320px;
+ width: 100%;
+ margin: 0 auto
+ }
+
+ header, footer {
+ padding: 5px 20px
+ }
+
+ header ul li:nth-child(2) {
+ display: none
+ }
+
+ button {
+ height: 40px;
+ font-size: 18px
+ }
+
+ input[type=email], input[type=password] {
+ font-size: 17px
+ }
+
+ section {
+ position: static;
+ overflow: visible
+ }
+
+ .inputs>li>label {
+ font-size: 18px
+ }
+
+ .vertical>strong {
+ font-size: 20px
+ }
+
+ #signIn, #favicon {
+ display: block;
+ width: 100%;
+ position: relative;
+ padding: 10px
+ }
+
+ #signIn {
+ max-width: none;
+ padding: 10px
+ }
+
+ #signIn .table {
+ width: 100%;
+ margin: 0
+ }
+
+ #signIn form {
+ padding: 0
+ }
+
+ #favicon {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+ background-image: url('bg.png');
+ text-align: center;
+ left: 0
+ }
+
+ #favicon img {
+ width: 32px;
+ height: auto;
+ display: inline;
+ margin: 0;
+ vertical-align: middle
+ }
+
+ #favicon .vertical {
+ height: auto;
+ line-height: 20px
+ }
+
+ #formWrap {
+ background-color: transparent
+ }
+
+ .error #formWrap, .error #wait, .waiting #formWrap {
+ display: none
+ }
+
+ .arrow {
+ display: none
+ }
+
+ #checkemail p {
+ height: 250px
+ }
+
+ #signIn .vertical {
+ padding-bottom: 0
+ }
+
+ #signIn .vertical ul li {
+ margin-top: 20px
+ }
+
+ #signIn .submit {
+ position: static
+ }
+
+ #signIn .submit>p {
+ font-size: 14px
+ }
+
+ label[for=remember] {
+ display: block;
+ font-size: 15px;
+ margin: 13px
+ }
+
+ #content, .form_section, .pickemail .inputs, .vertical {
+ height: auto;
+ max-height: none;
+ overflow: visible
+ }
+
+ .pickemail .vertical a {
+ font-size: 1.2em
+ }
+
+ #useNewEmail {
+ margin-top: 18px
+ }
+
+ #error .vertical, #wait .vertical {
+ height: 250px
+ }
+
+ #error .vertical {
+ width: auto
+ }
+
+ #error .vertical>div {
+ display: block;
+ height: auto;
+ padding: 10px
+ }
+
+ #error #borderbox {
+ border-left: none;
+ padding: 0
+ }
\ No newline at end of file
Binary file src/main/resources/template/webidp/idp/profile_anonymous.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/template/webidp/idp/util.js Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ */
+
+function isNeedBrowser() {
+ var need = false
+ if ($.browser.opera) var need = true
+ var userAgent = navigator.userAgent.toString().toLowerCase();
+ if ((userAgent.indexOf('safari') != -1) && !(userAgent.indexOf('chrome') != -1)) {
+ need = true //we are in safari
+ }
+ return need
+}
+
+/*
+ * Opera and Safari (on OSX at least) only serve a certificate if requested in NEED mode (as opposed to TLS WANT)
+ * (looking for clear specs on this distinction). In NEED mode if the browser does not have a certificate or if
+ * the client does not send one, the web page just shows an UGLY empty error page that no human would understand.
+ * This is horrible user experience. Instead we therefore do the request over AJAX, and show a nicely put together
+ * error message instead.
+ * todo: Clearly the error message could be built using a function call
+ */
+function needyLogin(){
+ $('#login').submit(function(event){
+ logout();
+ if (isNeedBrowser()) {
+ var url = $('#login').attr('action');
+ $('body').load(url+ '#wrapper',{post:'yes'},function(response, status, xhr) {
+ if (status == 'error') {
+ alert('You probably don\'t have a WebID enabled Certificate. It is worth getting one.' );
+ return false
+ }
+ });
+ return false
+ } else return true
+ });
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/Authoritative.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb
+
+import unfiltered.request._
+import java.security.cert.Certificate
+import javax.servlet.http.HttpServletRequest
+import unfiltered.netty.ReceivedMessage
+import org.eclipse.jetty.util.URIUtil
+import java.net.{MalformedURLException, URL}
+
+object Authoritative {
+
+ val r = """^(.*)\.(\w{0,4})$""".r
+
+ // all of this would be unnecessary if req.uri would really return the full URI
+ // we should try to push for that to be done at unfiltered layer
+ def reqURL[T](m: Manifest[T], r: HttpRequest[T]): String = {
+ if (m <:< manifest[HttpServletRequest]) reqUrlServlet(r.asInstanceOf[HttpRequest[HttpServletRequest]])
+ else if (m <:< manifest[ReceivedMessage]) reqUrlNetty(r.asInstanceOf[HttpRequest[ReceivedMessage]])
+ else "" //todo: should perhaps throw an exception here.
+ }
+
+ def unapply[T](req: HttpRequest[T]) (implicit m: Manifest[T]) : Option[(URL, Representation)] = {
+ val uri = reqURL(m, req)
+ val suffixOpt = uri match {
+ case r(_, suffix) => Some(suffix)
+ case _ if uri endsWith "/" => Some("/")
+ case _ => None
+ }
+ Some((new URL(uri), Representation(suffixOpt, Accept(req))))
+ }
+
+
+ private def reqUrlServlet[T <: HttpServletRequest](req: HttpRequest[T]): String = {
+ req.underlying.getRequestURL.toString
+ }
+
+ private def reqUrlNetty[T <: ReceivedMessage](req: HttpRequest[T]): String = {
+ try {
+ val u = new URL(req.uri)
+ new URL(u.getProtocol,u.getHost,u.getPort,u.getPath).toExternalForm
+ } catch {
+ case e: MalformedURLException => {
+ val url: StringBuffer = new StringBuffer (48)
+ val scheme = if (req.isSecure) "https" else "http"
+ val hostport = {//we assume there was some checking done earlier, and that we can rely on this
+ val host = req.headers ("Host")
+ if (host.hasNext) host.next () else "localhost"
+ }
+ url.append (scheme)
+ url.append ("://")
+ url.append (hostport)
+ url.append(req.uri)
+ url.toString
+ }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/EchoPlan.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb
+
+import io.BufferedSource
+import unfiltered.Cycle
+import unfiltered.netty.ReceivedMessage
+import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
+import unfiltered.request.{HttpRequest, Path}
+import org.jboss.netty.handler.codec.http.HttpResponse
+import unfiltered.response.{Ok, PlainTextContent, ResponseString}
+
+
+/**
+ * Useful Echo Server, for debugging
+ *
+ * @author hjs
+ * @created: 19/10/2011
+ */
+trait EchoPlan[Req,Res] {
+ import collection.JavaConversions._
+
+ /**
+ * unfiltered is missing a method to get the header names from the request, so this method is required
+ * @param req
+ * @return
+ */
+ def headers(req: HttpRequest[Req]): Iterator[String]
+
+ def intent : Cycle.Intent[Req, Res] = {
+ case req@Path(path) if path startsWith "/test/http/echo" => {
+ Ok ~> PlainTextContent ~> {
+ val header = for (headerName <- headers(req);
+ headerValue <- req.headers(headerName)
+ ) yield {
+ headerName + ": " + headerValue +"\r\n"
+ }
+ ResponseString(header.mkString+ "\r\n" + new BufferedSource(req.inputStream).mkString)
+ }
+ }
+ }
+}
+
+/**
+ * this is a trait so that it can be mixed in with different threading policies
+ */
+trait NettyEchoPlan extends EchoPlan[ReceivedMessage,HttpResponse] {
+ import scala.collection.JavaConverters.collectionAsScalaIterableConverter
+
+ def headers(req: HttpRequest[ReceivedMessage]) = req.underlying.request.getHeaderNames.asScala.toIterator
+}
+
+
+object JettyEchoPlan extends EchoPlan[HttpServletRequest,HttpServletResponse] {
+ import scala.collection.JavaConverters.enumerationAsScalaIteratorConverter
+ import java.util.Enumeration
+ def headers(req: HttpRequest[HttpServletRequest]) = Option(req.underlying.getHeaderNames).
+ map(enum=> enumerationAsScalaIteratorConverter[String](enum.asInstanceOf[Enumeration[String]]).asScala).
+ get
+}
--- a/src/main/scala/Filesystem.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/main/scala/Filesystem.scala Wed May 23 23:47:37 2012 +0200
@@ -1,68 +1,172 @@
package org.w3.readwriteweb
-import org.w3.readwriteweb.util._
-
import java.io._
import java.net.URL
import org.slf4j.{Logger, LoggerFactory}
-import com.hp.hpl.jena.rdf.model._
+import com.hp.hpl.jena.rdf.model.{Resource => _, _}
import com.hp.hpl.jena.shared.JenaException
-import sys.error
-import scalaz._
+
+import scalaz.{Resource => _, _}
import Scalaz._
+import scala.sys
+
+import com.hp.hpl.jena.vocabulary.RDF
+import org.w3.readwriteweb.Image
+
class Filesystem(
baseDirectory: File,
val basePath: String,
- val lang: String = "RDF/XML-ABBREV")(mode: RWWMode) extends ResourceManager {
-
- val logger:Logger = LoggerFactory.getLogger(this.getClass)
-
- def sanityCheck():Boolean = baseDirectory.exists
+ val lang: Lang)(mode: RWWMode) extends ResourceManager {
- def resource(url:URL):Resource = new Resource {
- val relativePath:String = url.getPath.replaceAll("^"+basePath.toString+"/?", "")
- val fileOnDisk = new File(baseDirectory, relativePath)
+ val logger: Logger = LoggerFactory.getLogger(this.getClass)
- private def createFileOnDisk():Unit = {
- // create parent directory if needed
+ def sanityCheck(): Boolean =
+ baseDirectory.exists && baseDirectory.isDirectory
+
+ def resource(url: URL): Resource = new Resource {
+ def name() = url
+
+ val relativePath: String = url.getPath.replaceAll("^" + basePath.toString + "/?", "")
+ val fileOnDisk = new File(baseDirectory, relativePath)
+ lazy val parent = fileOnDisk.getParentFile
+
+ private def parentMustExist(): Unit = {
val parent = fileOnDisk.getParentFile
- if (! parent.exists) println(parent.mkdirs)
- val r = fileOnDisk.createNewFile()
- logger.debug("Create file %s with success: %s" format (fileOnDisk.getAbsolutePath, r.toString))
+ if (!parent.exists) sys.error("Parent directory %s does not exist" format parent.getAbsolutePath)
+ if (!parent.isDirectory) sys.error("Parent %s is not a directory" format parent.getAbsolutePath)
}
- def get(): Validation[Throwable, Model] = {
+ private def createDirectoryOnDisk(): Unit = {
+ parentMustExist()
+ val r = fileOnDisk.mkdir()
+ if (!r) sys.error("Could not create %s" format fileOnDisk.getAbsolutePath)
+ logger.debug("%s successfully created: %s" format(fileOnDisk.getAbsolutePath, r.toString))
+ }
+
+ private def createFileOnDisk(): Unit = {
+ parentMustExist()
+ val r = fileOnDisk.createNewFile()
+ logger.debug("%s successfully created: %s" format(fileOnDisk.getAbsolutePath, r.toString))
+ }
+
+ def get(unused: CacheControl.Value = CacheControl.CacheFirst): Validation[Throwable, Model] = {
val model = ModelFactory.createDefaultModel()
- if (fileOnDisk.exists()) {
- val fis = new FileInputStream(fileOnDisk)
- try {
- val reader = model.getReader(lang)
- reader.read(model, fis, url.toString)
- } catch {
- case je:JenaException => error("@@@")
+
+ //for files: other possible ontologies to use would be
+ // "Linked Data Basic Profile 1.0" http://www.w3.org/Submission/2012/02/
+ // "the posix ontology" used by data.fm http://www.w3.org/ns/posix/stat#
+ if (fileOnDisk.isDirectory) {
+ val sioc = "http://rdfs.org/sioc/ns#"
+ val dirRes = model.createResource(name.toString)
+ dirRes.addProperty(RDF.`type`, model.createResource(sioc + "Container"))
+ for (f <- fileOnDisk.listFiles()) {
+ val furl = new URL(name, f.getName)
+ val item = model.createResource(furl.toString)
+ dirRes.addProperty(model.createProperty(sioc + "container_of"), item)
+ if (f.isDirectory) item.addProperty(RDF.`type`, model.createResource(sioc + "Container"))
+ else item.addProperty(RDF.`type`, model.createResource(sioc + "Item"))
}
- fis.close()
model.success
} else {
- mode match {
- case AllResourcesAlreadyExist => model.success
- case ResourcesDontExistByDefault => new FileNotFoundException().fail
+ val guessLang = fileOnDisk.getName match {
+ case Authoritative.r(_, suffix) => Representation.fromSuffix(suffix) match {
+ case RDFRepr(rdfLang) => rdfLang
+ case _ => lang
+ }
+ case _ => lang
+ }
+ if (fileOnDisk.exists()) {
+ val fis = new FileInputStream(fileOnDisk)
+ try {
+ val reader = model.getReader(guessLang.jenaLang)
+ reader.read(model, fis, url.toString)
+ } catch {
+ case je: JenaException => throw je
+ }
+ fis.close()
+ model.success
+ } else {
+ mode match {
+ case AllResourcesAlreadyExist => model.success
+ case ResourcesDontExistByDefault => new FileNotFoundException().fail
+ }
}
}
}
- def save(model:Model):Validation[Throwable, Unit] =
+ def getStream = try {
+ new BufferedInputStream(new FileInputStream(fileOnDisk)).success
+ } catch {
+ case fe: FileNotFoundException => fe.fail
+ case se: SecurityException => se.fail
+ }
+
+ def putStream(in: InputStream): Validation[Throwable, Unit] = {
+ val out = new FileOutputStream(fileOnDisk)
+ val buf = new Array[Byte](4096)
try {
- createFileOnDisk()
+ val good = Iterator continually in.read(buf) takeWhile (-1 !=) foreach { bytesRead =>
+ out.write(buf,0,bytesRead)
+ }
+ good.success
+ } catch {
+ case ioe: IOException => ioe.fail
+ }
+
+ }
+
+
+ def save(model: Model): Validation[Throwable, Unit] =
+ try {
+ parent.mkdirs()
val fos = new FileOutputStream(fileOnDisk)
- val writer = model.getWriter(lang)
+ val writer = model.getWriter(lang.jenaLang)
writer.write(model, fos, url.toString)
fos.close().success
} catch {
case t => t.fail
}
+ def createDirectory: Validation[Throwable, Unit] =
+ try {
+ createDirectoryOnDisk().success
+// val fos = new FileOutputStream(fileOnDisk)
+// val writer = model.getWriter(lang.contentType)
+// writer.write(model, fos, url.toString)
+// fos.close().success
+ } catch {
+ case t => t.fail
+ }
+
+ def delete: Validation[Throwable, Unit] = try {
+ if (fileOnDisk.delete()) ().success
+ else new Exception("Failed to delete file "+fileOnDisk).fail
+ } catch {
+ case e: SecurityException => e.fail
+ }
+
+ def create(contentType: Representation): Validation[Throwable, Resource] = {
+ if (!fileOnDisk.exists())
+ new Throwable("Must first create " + name()).fail
+ else if (!fileOnDisk.isDirectory)
+ new Throwable("Can only create a resource in a directory/collection which this is not " + name()).fail
+ else try {
+ //todo: the class hierarchy of content types needs to be improved.
+ val suffix = contentType match {
+ case RDFRepr(lang) => lang.suffix
+ case ImageRepr(tpe) => tpe.suffix
+ case l => lang.suffix
+ }
+ val path = File.createTempFile("res", suffix, fileOnDisk)
+ resource(new URL(name(), path.getName)).success
+ } catch {
+ case ioe: IOException => ioe.fail
+ }
+ }
+
}
+
+}
-}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/GraphCache.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,188 @@
+ /*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb
+
+import com.hp.hpl.jena.rdf.model.Model
+import org.w3.readwriteweb.util._
+import java.net.{ConnectException, URL}
+import scalaz.{Scalaz, Validation}
+import java.util.concurrent.TimeUnit
+import com.google.common.cache.{LoadingCache, CacheLoader, CacheBuilder, Cache}
+import com.weiglewilczek.slf4s.Logging
+import javax.net.ssl.SSLContext
+import org.apache.http.conn.scheme.Scheme
+import java.security.NoSuchAlgorithmException
+import org.apache.http.conn.ssl.{TrustStrategy, SSLSocketFactory}
+import java.security.cert.X509Certificate
+import java.io.{InputStream, File, FileOutputStream}
+import org.apache.http.conn.params.ConnRoutePNames
+import org.apache.http.{HttpHost, MethodNotSupportedException}
+
+
+/**
+ * Fetch resources on the Web and cache them
+ * ( at a later point this would include saving them to an indexed quad store )
+ *
+ * @author Henry Story
+ * @created: 12/10/2011
+ *
+ */
+object GraphCache extends ResourceManager with Logging {
+ import dispatch._
+ import Scalaz._
+
+ //use shellac's rdfa parser
+ new net.rootdev.javardfa.jena.RDFaReader //import rdfa parser
+
+
+ //this is a simple but quite stupid web cache so that graphs can stay in memory and be used a little
+ // bit across sessions
+ val cache: LoadingCache[URL,Validation[Throwable,Model]] =
+ CacheBuilder.newBuilder()
+ .expireAfterAccess(5, TimeUnit.MINUTES)
+ .softValues()
+// .expireAfterWrite(30, TimeUnit.MINUTES)
+ .build(new CacheLoader[URL, Validation[Throwable,Model]] {
+ def load(url: URL) = getUrl(url)
+ })
+
+ val http = new Http with thread.Safety {
+ import org.apache.http.params.CoreConnectionPNames
+ client.getParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 3000)
+ client.getParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, 15000)
+ Option(System.getProperty("http.proxy")).map{ uriStr =>
+ val url = new URL(uriStr)
+ val proxy = new HttpHost(url.getHost, url.getPort, url.getProtocol);
+ client.getParams.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy)
+ }
+ }
+
+
+
+ Option(System.getProperty("rww.clientTLSsecurity")).map {
+ case "noCA" => {
+ val sf = new SSLSocketFactory(new TrustStrategy {
+ def isTrusted(chain: Array[X509Certificate], authType: String) = true
+ });
+ insecure(sf)
+ }
+ case "noDomain" => {
+ val sf = new SSLSocketFactory(new TrustStrategy {
+ def isTrusted(chain: Array[X509Certificate], authType: String) = true
+ }, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+ insecure(sf);
+ }
+ case "secure" => Unit
+ }
+
+
+ def insecure(sf: SSLSocketFactory): Unit = {
+ val scheme = new Scheme("https", 443, sf)
+ http.client.getConnectionManager().getSchemeRegistry().register(scheme)
+ }
+
+ def basePath = null //should be cache dir?
+
+ def sanityCheck() = true //cache dire exists? But is this needed for functioning?
+
+ def resource(u : URL) = new org.w3.readwriteweb.Resource {
+ import CacheControl._
+ def name() = u
+ def get(cacheControl: CacheControl.Value) = cacheControl match {
+ case CacheOnly => {
+ val res = cache.getIfPresent(u)
+ if (null==res) NoCachEntry.fail
+ else res
+ }
+ case CacheFirst => cache.get(u)
+ case NoCache => {
+ val res = getUrl(u)
+ cache.put(u,res) //todo: should this only be done if say the returned value is not an error?
+ res
+ }
+ }
+ // when fetching information from the web creating directories does not make sense
+ //perhaps the resource manager should be split into read/write sections?
+ def save(model: Model) = throw new MethodNotSupportedException("not implemented")
+
+ def createDirectory = throw new MethodNotSupportedException("not implemented")
+
+ def delete = throw new MethodNotSupportedException("not implemented")
+
+ def create(ct: Representation) = throw new MethodNotSupportedException("not implemented")
+
+ def getStream = throw new MethodNotSupportedException("not implemented")
+
+ def putStream(in: InputStream) = throw new MethodNotSupportedException("not implemented")
+ }
+
+ private def getUrl(u: URL) = {
+
+ // note we prefer rdf/xml and turtle over html, as html does not always contain rdfa, and we prefer those over n3,
+ // as we don't have a full n3 parser. Better would be to have a list of available parsers for whatever rdf framework is
+ // installed (some claim to do n3 when they only really do turtle)
+ // we can't currently accept */* as we don't have GRDDL implemented
+ val request = url(u.toString) <:< Map("Accept"->
+ "application/rdf+xml,text/turtle,application/xhtml+xml;q=0.8,text/html;q=0.7,text/n3;q=0.2")
+ logger.info("fetching "+u.toExternalForm)
+
+ //we need to tell the model about the content type
+ val handler: Handler[Validation[Throwable, Model]] = Handler(request,{
+ (code,res,ent) =>
+ val encoding = res.getHeaders("Content-Type").headOption match {
+ case Some(mime) => {
+ Lang(mime.getValue.split(";")(0)) getOrElse Lang.default
+ }
+ case None => RDFXML //todo: it would be better to try to do a bit of guessing in this case by looking at content
+ }
+ val loc = code match {
+ case 301 => res.getHeaders("Content-Location").headOption match {
+ case Some(loc) => new URL(u,loc.getValue)
+ case None => new URL(u.getProtocol,u.getAuthority,u.getPort,u.getPath)
+ }
+ case _ => u
+ }
+ ent match {
+ case Some(e) => modelFromInputStream(e.getContent,loc,encoding)
+ case None => new Exception("response %s for %s has no entity".format(code, u)).fail
+ }
+ })
+
+ try {
+ val future = http(handler)
+ future
+ } catch {
+ case e: ConnectException => {
+ logger.info("failed to connect to "+u.getHost,e)
+ e.fail
+ }
+ }
+
+ }
+
+
+ override def finalize() { http.shutdown() }
+}
+
+ object NoCachEntry extends Exception
\ No newline at end of file
--- a/src/main/scala/HttpsTrustAll.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/main/scala/HttpsTrustAll.scala Wed May 23 23:47:37 2012 +0200
@@ -1,18 +1,24 @@
/*
* Copyright (c) 2011 Henry Story (bblfish.net)
- * All rights reserved.
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
*
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Henry Story. The name of bblfish.net may not be used to endorse
- * or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.w3.readwriteweb
@@ -23,7 +29,9 @@
import org.jsslutils.sslcontext.trustmanagers.TrustAllClientsWrappingTrustManager
import org.jsslutils.sslcontext.{X509TrustManagerWrapper, X509SSLContextFactory}
import sys.SystemProperties
+import scala.util.Properties.{propOrNone => getProperty, javaHome}
import unfiltered.jetty.{Ssl, Https}
+import unfiltered.jetty.Server
/**
@@ -31,7 +39,10 @@
* @created: 12/10/2011
*/
-case class HttpsTrustAll(override val port: Int, override val host: String) extends Https(port, host) with TrustAll
+class HttpsTrustAll(
+ override val port: Int,
+ override val host: String)
+extends Https(port, host) with TrustAll
/**
@@ -49,36 +60,45 @@
* the user experience would be very bad, since TLS does not give many options for explaining what the problem
* is.
*/
-trait TrustAll { self: Ssl =>
- import scala.sys.SystemProperties._
+trait TrustAll extends Ssl with Server with DelayedInit {
- lazy val sslContextFactory = new X509SSLContextFactory(
- serverCertKeyStore,
- tryProperty("jetty.ssl.keyStorePassword"),
- serverCertKeyStore); //this one is not needed since our wrapper ignores all trust managers
+ import scala.sys.SystemProperties._
- lazy val trustWrapper = new X509TrustManagerWrapper {
- def wrapTrustManager(trustManager: X509TrustManager) = new TrustAllClientsWrappingTrustManager(trustManager)
- }
-
- lazy val serverCertKeyStore = {
+ val patchedSslContextFactory = {
+ val trustWrapper =
+ new X509TrustManagerWrapper {
+ def wrapTrustManager(trustManager: X509TrustManager) =
+ new TrustAllClientsWrappingTrustManager(trustManager)
+ }
+
+ val serverCertKeyStore = {
val keyStoreLoader = new KeyStoreLoader
- keyStoreLoader.setKeyStoreType(System.getProperty("jetty.ssl.keyStoreType","JKS"))
- keyStoreLoader.setKeyStorePath(trustStorePath)
- keyStoreLoader.setKeyStorePassword(System.getProperty("jetty.ssl.keyStorePassword","password"))
- keyStoreLoader.loadKeyStore();
- }
-
- sslContextFactory.setTrustManagerWrapper(trustWrapper);
+ keyStoreLoader.setKeyStoreType(getProperty("jetty.ssl.keyStoreType") getOrElse "JKS")
+ keyStoreLoader.setKeyStorePath(trustStorePath)
+ keyStoreLoader.setKeyStorePassword(getProperty("jetty.ssl.keyStorePassword") getOrElse "password")
+ keyStoreLoader.loadKeyStore()
+ }
+
+ val factory = new X509SSLContextFactory(
+ serverCertKeyStore,
+ getProperty("jetty.ssl.keyStorePassword") getOrElse sys.error("jetty.ssl.keyStorePassword not set"),
+ serverCertKeyStore) //this one is not needed since our wrapper ignores all trust managers
+
+ factory.setTrustManagerWrapper(trustWrapper)
+
+ factory
+ }
-
- lazy val trustStorePath = new SystemProperties().get("jetty.ssl.keyStore") match {
- case Some(path) => path
- case None => new File(new File(tryProperty("user.home")), ".keystore").getAbsolutePath
- }
-
- sslConn.setSslContext(sslContextFactory.buildSSLContext())
- sslConn.setWantClientAuth(true)
+ val trustStorePath =
+ getProperty("jetty.ssl.keyStore") getOrElse {
+ new File(new File(javaHome), ".keystore").getAbsolutePath
+ }
+
+ // not tested if ok, there was a problem anyway
+ def delayedInit(x: ⇒ Unit): Unit = {
+ sslConn.setSslContext(patchedSslContextFactory.buildSSLContext())
+ sslConn.setWantClientAuth(true)
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/Image.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb
+
+/**
+ * Image mime types adapted in a hurry from the Lang class.
+ *
+ * It really feels like oneshould have one whole set of mime type classes that cover all the cases.
+ *
+ * @author bblfish
+ * @created 12/04/2012
+ */
+
+sealed trait Image {
+
+ def suffix = this match {
+ case JPEG => ".jpeg"
+ case GIF => ".gif"
+ case PNG => ".png"
+ }
+
+ def contentType : String
+
+}
+
+
+object Image {
+
+ val supportedImages = Set(JPEG, GIF, PNG)
+
+ def apply(contentType: String): Option[Image] = {
+ contentType.trim.toLowerCase match {
+ case "image/jpeg" => Some(JPEG)
+ case "image/gif" => Some(GIF)
+ case "image/png" => Some(PNG)
+ case _ => None
+ }
+ }
+
+ def apply(cts: Iterable[String]): Option[Image] =
+ cts map Image.apply collectFirst {
+ case Some(lang) => lang
+ }
+}
+
+case object JPEG extends Image {
+ val contentType = "image/jpeg"
+}
+case object GIF extends Image {
+ val contentType = "image/gif"
+}
+case object PNG extends Image {
+ val contentType = "image/png"
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/Lang.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011 World Wide Web Consortium
+ * under the W3C licence defined at http://opensource.org/licenses/W3C
+ */
+
+package org.w3.readwriteweb
+
+sealed trait Lang {
+
+ def suffix = this match {
+ case RDFXML => ".rdf"
+ case TURTLE => ".ttl"
+ case N3 => ".n3"
+ case XHTML => ".xhtml"
+ case HTML => ".html"
+ }
+
+ def contentType = this match {
+ case RDFXML => "application/rdf+xml"
+ case TURTLE => "text/turtle"
+ case N3 => "text/n3"
+ case XHTML => "application/xhtml+xml"
+ case HTML => "text/html"
+ }
+
+ def jenaLang = this match {
+ case RDFXML => "RDF/XML-ABBREV"
+ case TURTLE => "TURTLE"
+ case N3 => "N3"
+ case HTML => "HTML"
+ case XHTML => "XHTML"
+ }
+}
+
+object Lang {
+
+ val supportedLanguages = Set(RDFXML, TURTLE, N3)
+ val supportContentTypes = supportedLanguages map (_.contentType)
+ val supportedAsString = supportContentTypes mkString ", "
+
+ val default = RDFXML
+
+ def apply(contentType: String): Option[Lang] =
+ contentType.trim.toLowerCase match {
+ case "text/n3" => Some(N3)
+ case "text/turtle" => Some(TURTLE)
+ case "application/rdf+xml" => Some(RDFXML)
+ case "text/html" => Some(HTML)
+ case "application/xhtml+xml" => Some(XHTML)
+ case _ => None
+ }
+
+ def apply(cts: Iterable[String]): Option[Lang] =
+ cts map Lang.apply collectFirst { case Some(lang) => lang }
+
+}
+
+case object RDFXML extends Lang
+
+case object TURTLE extends Lang
+
+case object N3 extends Lang
+
+case object XHTML extends Lang
+
+case object HTML extends Lang
\ No newline at end of file
--- a/src/main/scala/Main.scala Thu Oct 13 13:34:16 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,247 +0,0 @@
-package org.w3.readwriteweb
-
-import javax.servlet._
-import javax.servlet.http._
-import unfiltered.request._
-import unfiltered.response._
-import unfiltered.jetty._
-
-import java.io._
-import scala.io.Source
-import java.net.URL
-
-import org.slf4j.{Logger, LoggerFactory}
-
-import com.hp.hpl.jena.rdf.model._
-import com.hp.hpl.jena.query._
-import com.hp.hpl.jena.update._
-import org.w3.readwriteweb.Resource
-import Query.{QueryTypeSelect => SELECT, QueryTypeAsk => ASK,
- QueryTypeConstruct => CONSTRUCT, QueryTypeDescribe => DESCRIBE}
-
-import scalaz._
-import Scalaz._
-
-import org.w3.readwriteweb.util._
-import collection.mutable
-import webid.AuthFilter
-class ReadWriteWeb(rm: ResourceManager) {
-
- val logger:Logger = LoggerFactory.getLogger(this.getClass)
-
- def isHTML(accepts:List[String]):Boolean = {
- val accept = accepts.headOption
- accept == Some("text/html") || accept == Some("application/xhtml+xml")
- }
-
- /** I believe some documentation is needed here, as many different tricks
- * are used to make this code easy to read and still type-safe
- *
- * Planify.apply takes an Intent, which is defined in Cycle by
- * type Intent [-A, -B] = PartialFunction[HttpRequest[A], ResponseFunction[B]]
- * the corresponding syntax is: case ... => ...
- *
- * this code makes use of the Validation monad. For example of how to use it, see
- * http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html
- *
- * the Resource abstraction returns Validation[Throwable, ?something]
- * we use the for monadic constructs.
- * Everything construct are mapped to Validation[ResponseFunction, ResponseFuntion],
- * the left value always denoting the failure. Hence, the rest of the for-construct
- * is not evaluated, but let the reader of the code understand clearly what's happening.
- *
- * This mapping is made possible with the failMap method. I couldn't find an equivalent
- * in the ScalaZ API so I made my own through an implicit.
- *
- * At last, Validation[ResponseFunction, ResponseFuntion] is exposed as a ResponseFunction
- * through another implicit conversion. It saves us the call to the Validation.lift() method
- */
- val read = unfiltered.filter.Planify {
- case req @ Path(path) if path startsWith rm.basePath => {
- val baseURI = req.underlying.getRequestURL.toString
- val r:Resource = rm.resource(new URL(baseURI))
- req match {
- case GET(_) & Accept(accepts) if isHTML(accepts) => {
- val source = Source.fromFile("src/main/resources/skin.html")("UTF-8")
- val body = source.getLines.mkString("\n")
- Ok ~> ViaSPARQL ~> ContentType("text/html") ~> ResponseString(body)
- }
- case GET(_) | HEAD(_) =>
- for {
- model <- r.get() failMap { x => NotFound }
- encoding = RDFEncoding(req)
- } yield {
- req match {
- case GET(_) => Ok ~> ViaSPARQL ~> ContentType(encoding.toContentType) ~> ResponseModel(model, baseURI, encoding)
- case HEAD(_) => Ok ~> ViaSPARQL ~> ContentType(encoding.toContentType)
- }
- }
- case PUT(_) =>
- for {
- bodyModel <- modelFromInputStream(Body.stream(req), baseURI) failMap { t => BadRequest ~> ResponseString(t.getStackTraceString) }
- _ <- r.save(bodyModel) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString) }
- } yield Created
- case POST(_) => {
- Post.parse(Body.stream(req), baseURI) match {
- case PostUnknown => {
- logger.info("Couldn't parse the request")
- BadRequest ~> ResponseString("You MUST provide valid content for either: SPARQL UPDATE, SPARQL Query, RDF/XML, TURTLE")
- }
- case PostUpdate(update) => {
- logger.info("SPARQL UPDATE:\n" + update.toString())
- for {
- model <- r.get() failMap { t => NotFound }
- // TODO: we should handle an error here
- _ = UpdateAction.execute(update, model)
- _ <- r.save(model) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString)}
- } yield Ok
- }
- case PostRDF(diffModel) => {
- logger.info("RDF content:\n" + diffModel.toString())
- for {
- model <- r.get() failMap { t => NotFound }
- // TODO: we should handle an error here
- _ = model.add(diffModel)
- _ <- r.save(model) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString)}
- } yield Ok
- }
- case PostQuery(query) => {
- logger.info("SPARQL Query:\n" + query.toString())
- lazy val encoding = RDFEncoding(req)
- for {
- model <- r.get() failMap { t => NotFound }
- } yield {
- val qe:QueryExecution = QueryExecutionFactory.create(query, model)
- query.getQueryType match {
- case SELECT =>
- Ok ~> ContentType("application/sparql-results+xml") ~> ResponseResultSet(qe.execSelect())
- case ASK =>
- Ok ~> ContentType("application/sparql-results+xml") ~> ResponseResultSet(qe.execAsk())
- case CONSTRUCT => {
- val result:Model = qe.execConstruct()
- Ok ~> ContentType(encoding.toContentType) ~> ResponseModel(model, baseURI, encoding)
- }
- case DESCRIBE => {
- val result:Model = qe.execDescribe()
- Ok ~> ContentType(encoding.toContentType) ~> ResponseModel(model, baseURI, encoding)
- }
- }
- }
- }
- }
- }
- case _ => MethodNotAllowed ~> Allow("GET", "PUT", "POST")
- }
- }
-
- }
-
-}
-
-
-object ReadWriteWebMain {
- import org.clapper.argot._
- import ArgotConverters._
-
- val logger:Logger = LoggerFactory.getLogger(this.getClass)
-
- val postUsageMsg= Some("""
- |PROPERTIES
- |
- | * Keystore properties that need to be set if https is started
- | -Djetty.ssl.keyStoreType=type : the type of the keystore, JKS by default usually
- | -Djetty.ssl.keyStore=path : specify path to key store (for https server certificate)
- | -Djetty.ssl.keyStorePassword=password : specify password for keystore store (optional)
- |
- |NOTES
- |
- | - Trust stores are not needed because we use the WebID protocol, and client certs are nearly never signed by CAs
- | - one of --http or --https must be selected
- """.stripMargin);
-
- val parser = new ArgotParser("read-write-web",postUsage=postUsageMsg)
-
- val mode = parser.option[RWWMode](List("mode"), "m", "wiki mode: wiki or strict") {
- (sValue, opt) =>
- sValue match {
- case "wiki" => AllResourcesAlreadyExist
- case "strict" => ResourcesDontExistByDefault
- case _ => throw new ArgotConversionException("Option %s: must be either wiki or strict" format (opt.name, sValue))
- }
- }
-
- val rdfLanguage = parser.option[String](List("language"), "l", "RDF language: n3, turtle, or rdfxml") {
- (sValue, opt) =>
- sValue match {
- case "n3" => "N3"
- case "turtle" => "N3"
- case "rdfxml" => "RDF/XML-ABBREV"
- case _ => throw new ArgotConversionException("Option %s: must be either n3, turtle or rdfxml" format (opt.name, sValue))
- }
- }
-
- val httpPort = parser.option[Int]("http", "Port","start the http server on port")
- val httpsPort = parser.option[Int]("https","port","start the https server on port")
-
- val rootDirectory = parser.parameter[File]("rootDirectory", "root directory", false) {
- (sValue, opt) => {
- val file = new File(sValue)
- if (! file.exists)
- throw new ArgotConversionException("Option %s: %s must be a valid path" format (opt.name, sValue))
- else
- file
- }
- }
-
- implicit val webCache = new WebCache()
-
-
- val baseURL = parser.parameter[String]("baseURL", "base URL", false)
-
-
- // regular Java main
- def main(args: Array[String]) {
-
- try {
- parser.parse(args)
- } catch {
- case e: ArgotUsageException => println(e.message); System.exit(1)
- }
-
- val filesystem =
- new Filesystem(
- rootDirectory.value.get,
- baseURL.value.get,
- lang=rdfLanguage.value getOrElse "N3")(mode.value getOrElse ResourcesDontExistByDefault)
- val app = new ReadWriteWeb(filesystem)
-
- //this is incomplete: we should be able to start both ports.... not sure how to do this yet.
- val service = httpsPort.value match {
- case Some(port) => HttpsTrustAll(port,"0.0.0.0")
- case None => Http(httpPort.value.get)
- }
-
- // configures and launches a Jetty server
- service.filter {
- // a jee Servlet filter that logs HTTP requests
- new Filter {
- def destroy():Unit = ()
- def doFilter(request:ServletRequest, response:ServletResponse, chain:FilterChain):Unit = {
- val r:HttpServletRequest = request.asInstanceOf[HttpServletRequest]
- val method = r.getMethod
- val uri = r.getRequestURI
- logger.info("%s %s" format (method, uri))
- chain.doFilter(request, response)
- }
- def init(filterConfig:FilterConfig):Unit = ()
- }
- // Unfiltered filters
- }.filter(new AuthFilter)
- .context("/public"){ ctx:ContextBuilder =>
- ctx.resources(MyResourceManager.fromClasspath("public/").toURI.toURL)
- }.filter(app.read).run()
-
- }
-
-}
-
--- a/src/main/scala/Post.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/main/scala/Post.scala Wed May 23 23:47:37 2012 +0200
@@ -3,6 +3,7 @@
import org.w3.readwriteweb.util.modelFromString
import java.io.{InputStream, StringReader}
+import java.net.URL
import scala.io.Source
import org.slf4j.{Logger, LoggerFactory}
import com.hp.hpl.jena.rdf.model._
@@ -11,52 +12,61 @@
import com.hp.hpl.jena.shared.JenaException
sealed trait Post
-
case class PostUpdate(update: UpdateRequest) extends Post
-
case class PostRDF(model: Model) extends Post
-
case class PostQuery(query: Query) extends Post
-
+case class PostBinary(in: InputStream) extends Post
case object PostUnknown extends Post
-
import scalaz._
import Scalaz._
object Post {
+ val SPARQL = "application/sparql-query"
+ val supportContentTypes = Lang.supportContentTypes ++ Image.supportedImages.map(_.contentType) + SPARQL
+ val supportedAsString = supportContentTypes mkString ", "
+
+
val logger: Logger = LoggerFactory.getLogger(this.getClass)
- def parse(is: InputStream, baseURI:String): Post = {
- val source = Source.fromInputStream(is, "UTF-8")
- val s = source.getLines.mkString("\n")
- parse(s, baseURI)
- }
-
- def parse(s: String, baseURI: String): Post = {
- val reader = new StringReader(s)
-
+ def parse(
+ is: InputStream,
+ base: URL,
+ contentType: String): Post = {
+ assert(supportContentTypes contains contentType)
+
+ val inAsString = {
+ val source = Source.fromInputStream(is, "UTF-8")
+ source.getLines.mkString("\n")
+ }
+
def postUpdate =
try {
- val update: UpdateRequest = UpdateFactory.create(s, baseURI)
+ val update: UpdateRequest = UpdateFactory.create(inAsString, base.toString)
PostUpdate(update).success
} catch {
case qpe: QueryParseException => qpe.fail
}
- def postRDF =
- modelFromString(s, baseURI) flatMap { model => PostRDF(model).success }
+ def postRDF(lang: Lang) =
+ modelFromString(inAsString, base, lang) flatMap { model => PostRDF(model).success }
def postQuery =
try {
- val query = QueryFactory.create(s)
+ val query = QueryFactory.create(inAsString)
PostQuery(query).success
} catch {
case qe: QueryException => qe.fail
}
+
- postUpdate | (postRDF | (postQuery | PostUnknown))
+ contentType match {
+ case SPARQL => postUpdate | (postQuery | PostUnknown)
+ case RequestLang(lang) => postRDF(lang) | PostUnknown
+ case GIF.contentType | JPEG.contentType | PNG.contentType => PostBinary(is)
+ }
+
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/ReadWriteWeb.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,212 @@
+package org.w3.readwriteweb
+
+import auth.{AuthZ, NullAuthZ}
+import netty.ResponseBin
+import org.w3.readwriteweb.util._
+
+import scala.io.Source
+import java.net.URL
+
+import org.slf4j.{Logger, LoggerFactory}
+
+import com.hp.hpl.jena.query.{Query, QueryExecution, QueryExecutionFactory}
+import com.hp.hpl.jena.update.UpdateAction
+import Query.{QueryTypeSelect => SELECT,
+ QueryTypeAsk => ASK,
+ QueryTypeConstruct => CONSTRUCT,
+ QueryTypeDescribe => DESCRIBE}
+
+import scalaz.{Scalaz, Resource => _}
+import Scalaz._
+import unfiltered.request._
+import unfiltered.Cycle
+import unfiltered.response._
+
+import com.hp.hpl.jena.rdf.model.Model
+import javax.naming.BinaryRefAddr
+
+//object ReadWriteWeb {
+//
+// val defaultHandler: PartialFunction[Throwable, HttpResponse[_]] = {
+// case t => InternalServerError ~> ResponseString(t.getStackTraceString)
+// }
+//
+//}
+
+/**
+ * The ReadWriteWeb intent.
+ * It is independent of jetty or netty
+ */
+trait ReadWriteWeb[Req, Res] {
+ val rm: ResourceManager
+ implicit def manif: Manifest[Req]
+ implicit val authz: AuthZ[Req, Res] = new NullAuthZ[Req, Res]
+ // a few type short cuts to make it easier to reason with the code here
+ // one may want to generalize this code so that it does not depend so strongly on servlets.
+// type Request = HttpRequest[Req]
+// type Response = ResponseFunction[Res]
+
+ val logger: Logger = LoggerFactory.getLogger(this.getClass)
+
+ /**
+ * The partial function that if triggered sends to the readwrite web code.
+ * It wraps the ReadWriteWeb function with the AuthZ passed in the argument
+ * ( Note that we don't want to protect this intent, since that would be to apply the security to all other applications,
+ * many of which may want different authorization implementations )
+ */
+ def intent : Cycle.Intent[Req, Res] = {
+ case req @ Path(path) if path startsWith rm.basePath => authz.protect(rwwIntent)(manif)(req)
+ }
+
+ /**
+ * The core ReadWrite web function
+ * ( This is not a partial function and so is not a Plan.Intent )
+ *
+ * This code makes use of ScalaZ Validation. For example of how to use it, see
+ * http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html
+ *
+ * the Resource abstraction returns Validation[Throwable, ?something]
+ * we use the for monadic constructs (although it's *not* a monad).
+ * Everything construct are mapped to Validation[ResponseFunction, ResponseFuntion],
+ * the left value always denoting the failure. Hence, the rest of the for-construct
+ * is not evaluated, but let the reader of the code understand clearly what's happening.
+ *
+ * This mapping is made possible with the failMap method. I couldn't find an equivalent
+ * in the ScalaZ API so I made my own through an implicit.
+ *
+ * At last, Validation[ResponseFunction, ResponseFuntion] is exposed as a ResponseFunction
+ * through another implicit conversion. It saves us the call to the Validation.fold() method
+ */
+ def rwwIntent = (req: HttpRequest[Req]) => {
+
+ val Authoritative(uri: URL, representation: Representation) = req
+ val r: Resource = rm.resource(uri)
+ val res: ResponseFunction[Res] = req match {
+ case GET(_) if representation == HTMLRepr => {
+ val source = Source.fromFile("src/main/resources/skin.html")("UTF-8")
+ val body = source.getLines.mkString("\n")
+ Ok ~> ViaSPARQL ~> ContentType("text/html") ~> ResponseString(body)
+ }
+ case GET(_) if representation.isInstanceOf[ImageRepr] => {
+ for (in <- r.getStream failMap {x => NotFound })
+ yield {
+ val ImageRepr(typ) = representation
+ Ok ~> ContentType(typ.contentType) ~> ResponseBin(in)
+ }
+ }
+ case GET(_) | HEAD(_) =>
+ for {
+ model <- r.get() failMap { x => NotFound }
+ lang = AcceptLang.unapply(req).getOrElse{
+ representation match {
+ case RDFRepr(l) => l
+ case _ => Lang.default
+ }
+ }
+ } yield {
+ val res = req match {
+ case GET(_) => Ok ~> ViaSPARQL ~> ContentType(lang.contentType) ~> ResponseModel(model, uri, lang)
+ case HEAD(_) => Ok ~> ViaSPARQL ~> ContentType(lang.contentType)
+ }
+ res ~> ContentLocation( uri.toString ) // without this netty (perhaps jetty too?) sends very weird headers, breaking tests
+ }
+ case PUT(_) if representation.isInstanceOf[ImageRepr] => {
+ for (_ <- r.putStream(Body.stream(req)) failMap { t=> InternalServerError ~> ResponseString(t.getStackTraceString)})
+ yield Created
+ }
+ case PUT(_) & RequestLang(lang) if representation == DirectoryRepr => {
+ for {
+ bodyModel <- modelFromInputStream(Body.stream(req), uri, lang) failMap { t => BadRequest ~> ResponseString(t.getStackTraceString) }
+ _ <- r.createDirectory failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString) }
+ } yield Created
+ }
+ case PUT(_) & RequestLang(lang) =>
+ for {
+ bodyModel <- modelFromInputStream(Body.stream(req), uri, lang) failMap { t => BadRequest ~> ResponseString(t.getStackTraceString) }
+ _ <- r.save(bodyModel) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString) }
+ } yield Created
+ case PUT(_) =>
+ BadRequest ~> ResponseString("Content-Type MUST be one of: " + Lang.supportedAsString)
+ case POST(_) & RequestContentType(ct) if representation == DirectoryRepr =>
+ val createType = Representation.fromAcceptedContentTypes(List(ct))
+ r.create(createType) failMap { t => NotFound ~> ResponseString(t.getStackTraceString)} flatMap { rNew =>
+ Post.parse(Body.stream(req), rNew.name, ct) match {
+ case PostRDF(model) => {
+ logger.info("RDF content:\n" + model.toString())
+ for {
+ _ <- rNew.save(model) failMap {
+ t => InternalServerError ~> ResponseString(t.getStackTraceString)
+ }
+ } yield Created ~> ResponseHeader("Location",Seq(rNew.name.toString))
+ }
+ case PostBinary(is) => {
+ for (_ <- rNew.putStream(is) failMap { t=> InternalServerError ~> ResponseString(t.getStackTraceString)})
+ yield Created ~> ResponseHeader("Location",Seq(rNew.name.toString))
+ }
+ case _ => {
+ logger.info("Couldn't parse the request")
+ (BadRequest ~> ResponseString("You MUST provide valid content for given Content-Type: " + ct)).success
+ }
+ }
+ }
+ case POST(_) & RequestContentType(ct) if Post.supportContentTypes contains ct => {
+ Post.parse(Body.stream(req), uri, ct) match {
+ case PostUnknown => {
+ logger.info("Couldn't parse the request")
+ BadRequest ~> ResponseString("You MUST provide valid content for given Content-Type: " + ct)
+ }
+ case PostUpdate(update) => {
+ logger.info("SPARQL UPDATE:\n" + update.toString())
+ for {
+ model <- r.get() failMap { t => NotFound }
+ // TODO: we should handle an error here
+ _ = UpdateAction.execute(update, model)
+ _ <- r.save(model) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString)}
+ } yield Ok
+ }
+ case PostRDF(diffModel) => {
+ logger.info("RDF content:\n" + diffModel.toString())
+ for {
+ model <- r.get() failMap { t => NotFound }
+ // TODO: we should handle an error here
+ _ = model.add(diffModel)
+ _ <- r.save(model) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString)}
+ } yield Ok
+ }
+ case PostQuery(query) => {
+ logger.info("SPARQL Query:\n" + query.toString())
+ lazy val lang = RequestLang.unapply(req) getOrElse Lang.default
+ for {
+ model <- r.get() failMap { t => NotFound }
+ } yield {
+ val qe: QueryExecution = QueryExecutionFactory.create(query, model)
+ query.getQueryType match {
+ case SELECT =>
+ Ok ~> ContentType("application/sparql-results+xml") ~> ResponseResultSet(qe.execSelect())
+ case ASK =>
+ Ok ~> ContentType("application/sparql-results+xml") ~> ResponseResultSet(qe.execAsk())
+ case CONSTRUCT => {
+ val result: Model = qe.execConstruct()
+ Ok ~> ContentType(lang.contentType) ~> ResponseModel(model, uri, lang)
+ }
+ case DESCRIBE => {
+ val result: Model = qe.execDescribe()
+ Ok ~> ContentType(lang.contentType) ~> ResponseModel(model, uri, lang)
+ }
+ }
+ }
+ }
+ }
+ }
+ case POST(_) =>
+ BadRequest ~> ResponseString("Content-Type MUST be one of: " + Post.supportedAsString)
+ case DELETE(_) => {
+ for { _ <- r.delete failMap { t => NotFound ~> ResponseString("Error found"+t.toString)}
+ } yield NoContent
+ }
+ case _ => MethodNotAllowed ~> Allow("GET", "PUT", "POST")
+ }
+ res
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/ReadWriteWebArgs.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2011 World Wide Web Consortium
+ * under the W3C licence defined at http://opensource.org/licenses/W3C
+ */
+
+package org.w3.readwriteweb
+
+import java.io.File
+import java.net.{MalformedURLException, URL}
+import org.clapper.argot.{ArgotConversionException, ArgotParser, ArgotConverters}
+import org.slf4j.{LoggerFactory, Logger}
+import org.w3.readwriteweb.auth.X509CertSigner
+
+
+/**
+ * @author bblfish
+ * @created 22/05/2012
+ */
+
+trait ReadWriteWebArgs {
+ val logger: Logger = LoggerFactory.getLogger(this.getClass)
+
+ // in Order to be receptive to DNS changes the DNS cache properties below must be set
+ // please tune them to see what works best
+ java.security.Security.setProperty("networkaddress.cache.ttl" , ""+60*10);
+ java.security.Security.setProperty("networkaddress.cache.negative.ttl",""+60*3) //3 minutes
+ import ArgotConverters._
+
+ val postUsageMsg= Some(
+ """
+ |NOTES
+ |
+ | - One of --http or --https must be selected
+ | - Trust stores are not needed because we use the WebID protocol, and client certs are nearly never signed by CAs
+ |
+ |SYSTEM PROPERTIES
+ |
+ | You can also set the following system properties with -Dproperty=value
+ |
+ | SECURITY:
+ | * ssl.keyStore: location of keystore (also --ks )
+ | * ssl.keyStorePassword: keystore password (so you don't need to type it on command line)
+ | * ssl.keyStoreType: keystore type (eg. JKS) where the server sertificate is located
+ |
+ |EXAMPLES
+ |
+ | from sbt shell in the source directory
+ | > run --lang turtle --keyStore src/test/resources/KEYSTORE.jks --ksPass secret --https 8443 test_www /2012/
+ |
+ """.stripMargin);
+
+ val parser = new ArgotParser("read-write-web",
+ outputWidth = 120,
+ preUsage = Some("Version 0.2"), postUsage = postUsageMsg,
+ sortUsage = false
+ )
+
+ val mode = parser.flag[RWWMode](List("wiki"), List("strict"),
+ "all resources already exist in --wiki mode (you can GET them) but not in --strict mode") {
+ (sValue, opt) =>
+ sValue match {
+ case true => AllResourcesAlreadyExist
+ case false => ResourcesDontExistByDefault
+ case _ => throw new ArgotConversionException("Option %s: must be either wiki or strict" format (opt.name, sValue))
+ }
+ }
+
+ val host = parser.option[String](List("host"),"domain","the domain of your machine (localhost otherwise) - not sure where this ends up revealing itself")
+
+ val rdfLanguage = parser.option[Lang](List("language","lang"), "l", "RDF language files are stored as: turtle or rdfxml") {
+ (sValue, opt) =>
+ sValue match {
+ case "n3" => N3
+ case "turtle" => TURTLE
+ case "rdfxml" => RDFXML
+ case _ => throw new ArgotConversionException("Option %s: must be either n3, turtle or rdfxml" format (opt.name, sValue))
+ }
+ }
+
+
+ /**
+ * set environmental variables, but adapt them for the underlying server
+ * (a silly hack because jetty and netty in unfiltered use different TLS security
+ * properties, and I don't want to dig through each library to set that right just now)
+ * @param name
+ * @param value
+ */
+ def setPropHack(name: String, value: String)
+
+ private val keyStoreOpt = parser.option[String](List("keyStore","ks"),"url",
+ "path to keystore (same as system property ssl.keyStore )")
+
+ //this should only be called after parsing
+ //todo: The ArgotParsers options cannot deal with default values, which is why we have to do this ugly hack
+ //it would require some mothod like orElse
+ lazy val keyStore = keyStoreOpt.value.orElse{
+ Option(System.getProperty("ssl.keyStore"))
+ }.map(p => new URL(new File(".").toURI.toURL,p))
+
+
+ private val keyStoreTypeOpt = parser.option[String](List("ksType"),"t","Type of KeyStore (JKS by default)") {
+ (sValue, opt) =>
+ sValue match {
+ case tp: String => tp
+ case _ => "JKS"
+ }
+ }
+
+ //this should only be called after parsing
+ lazy val keyStoreType = keyStoreTypeOpt.value.orElse{
+ Option(System.getProperty("ssl.keyStoreType"))
+ }
+
+ val keyStoreAlias = parser.option[String](List("ksAlias"),"name","alias for the key in the keystore")
+
+ private val keyStorePasswordOpt = parser.option[String](List("ksPass"),"pass",
+ "password for keystore (better set ssl.keyStorePassword System property)")
+
+ lazy val keyStorePassword = keyStorePasswordOpt.value.orElse{
+ Option(System.getProperty("ssl.keyStorePassword"))
+ }
+
+ val clientTLSsecurity = parser.option[Boolean](List("clientTLS"),"mode",
+ """client TLS connection security mode:
+ | * secure: if server certificate is not signed by well known CA don't accept
+ | * noCA: if the server certificate is not signed by well known CA ignore and continue
+ | * noDomain: for test situations where the server cert does not name its server correctly
+ | * [todo: add more flexible server certificate verification mechanisms]
+ """.stripMargin) {
+ (sValue, opt) =>
+ sValue match {
+ case "noCA" => {
+ //todo: work with system property as a hack for the moment, as passing around conexts is going to require
+ // a lot of rewriting
+ System.setProperty("rww.clientTLSsecurity","noCA")
+ false
+ }
+ case "noDomain" => {
+ System.setProperty("rww.clientTLSsecurity","noDomain")
+ false
+ }
+ case _ => {
+ System.setProperty("rww.clientTLSsecurity","secure")
+ true
+ }
+ }
+ }
+
+ parser.option[Unit](List("sslReneg"),"type",
+ """enable workaround for SSL regegotiation issue RFC5746 (see http://tinyurl.com/d9ydrnw )
+ | * sslUnsafe: allow unsafe renegotiation (will work with older browsers)
+ | * sslLegacy: allow legacy handshake without RFC 5746 messages
+ | (otherwise will use the default of the JVM used)
+ """.stripMargin) {
+ (sValue, opt) =>
+ sValue match {
+ case "sslUnsafe" => System.setProperty("sun.security.ssl.allowUnsafeRenegotiation","true")
+ case "sslLegacy" => System.setProperty("sun.security.ssl.allowLegacyHelloMessages","true")
+ case _ => ()
+ }
+ }
+
+ parser.flag[Unit](List("sslDebug"),"trace all SSL messages to output") {
+ (select, opt) => if (select) System.setProperty("javax.net.debug","all")
+ }
+
+ val proxy = parser.option[URL](List("proxy"),"p",
+ "Proxy to use when making client http(s) connections (sets http.proxy system property)") {
+ (sValue, opt) =>
+ try {
+ val proxy = new URL(sValue);
+ System.getProperties().put("http.proxy", proxy);
+ proxy
+ } catch {
+ case e: MalformedURLException => throw new ArgotConversionException("Option %s: url does not parse correctly "
+ format (opt.name, sValue))
+ }
+ }
+
+ val httpPort = parser.option[Int]("http", "port","start the http server on port")
+ val httpsPort = parser.option[Int]("https","port","start the https server on port")
+
+ val rootDirectory = parser.parameter[File]("rootDirectory", "path to root directory where files are served", false) {
+ (sValue, opt) => {
+ val file = new File(sValue)
+ if (! file.exists)
+ throw new ArgotConversionException("Option %s: %s must be a valid path" format (opt.name, sValue))
+ else
+ file
+ }
+ }
+
+ lazy val signer =
+ X509CertSigner( keyStore, keyStoreType,
+ keyStorePassword, keyStoreAlias.value.orElse(Some("selfsigned")) )
+
+ val baseURL = parser.parameter[String]("baseURL", "the base path in the URL from which resources will be served", false)
+
+ /** execute after parseing command line */
+ protected def postParse {
+ keyStore.map(u=>setPropHack("ssl.keyStore",u.getPath))
+ keyStorePassword.map(setPropHack("ssl.keyStorePassword",_))
+ keyStoreType.map(setPropHack("ssl.keyStoreType",_))
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/ReadWriteWebJetty.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011 World Wide Web Consortium
+ * under the W3C licence defined at http://opensource.org/licenses/W3C
+ */
+
+
+package org.w3.readwriteweb
+
+import auth.{X509CertSigner, RDFAuthZ, X509view}
+import org.w3.readwriteweb.util._
+
+import unfiltered.jetty._
+import Console.err
+import org.slf4j.{Logger, LoggerFactory}
+
+import org.clapper.argot._
+import ArgotConverters._
+import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
+import java.lang.String
+import java.io.File
+import java.net.{MalformedURLException, URL}
+
+
+object ReadWriteWebJetty extends ReadWriteWebArgs {
+
+ import unfiltered.filter.Planify
+
+ // regular Java main
+ def main(args: Array[String]) {
+
+ try {
+ parser.parse(args)
+ postParse
+ } catch {
+ case e: ArgotUsageException => err.println(e.message); sys.exit(1)
+ }
+
+
+ val filesystem =
+ new Filesystem(
+ rootDirectory.value.get,
+ baseURL.value.get,
+ lang=rdfLanguage.value getOrElse RDFXML)(mode.value getOrElse ResourcesDontExistByDefault)
+
+ val rww = new ReadWriteWeb[HttpServletRequest,HttpServletResponse] {
+ val rm = filesystem
+ def manif = manifest[HttpServletRequest]
+ override implicit val authz = new RDFAuthZ[HttpServletRequest,HttpServletResponse](filesystem)
+ }
+
+
+ //this is incomplete: we should be able to start both ports.... not sure how to do this yet.
+ val service = httpsPort.value match {
+ case Some(port) => new HttpsTrustAll(port,host.value.getOrElse("0.0.0.0"))
+ case None => Http(httpPort.value.get,host.value.getOrElse("0.0.0.0"))
+ }
+
+ // configures and launches a Jetty server
+ service.filter(new FilterLogger(logger)).
+ context("/public"){ ctx:ContextBuilder =>
+ ctx.resources(ClasspathUtils.fromClasspath("public/").toURI.toURL)
+ }.filter(Planify(JettyEchoPlan.intent)).
+ filter(Planify(rww.intent)).
+ filter(Planify(x509v.intent)).
+ run()
+
+ }
+
+
+
+ object x509v extends X509view[HttpServletRequest,HttpServletResponse] {
+ def manif = manifest[HttpServletRequest]
+ }
+
+ /**
+ * set environmental variables, but adapt them for the underlying server
+ * (a silly hack because jetty and netty in unfiltered use different TLS security
+ * properties, and I don't want to dig through each library to set that right just now)
+ * @param name
+ * @param value
+ */
+ def setPropHack(name: String, value: String) {
+ System.setProperty("jetty."+name,value)
+ }
+}
+
+
--- a/src/main/scala/ReadWriteWebMain.scala Thu Oct 13 13:34:16 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-package org.w3.readwriteweb
-
-import org.w3.readwriteweb.util._
-
-import javax.servlet._
-import javax.servlet.http._
-import unfiltered.jetty._
-import java.io.File
-import Console.err
-import org.slf4j.{Logger, LoggerFactory}
-
-import org.clapper.argot._
-import ArgotConverters._
-
-object ReadWriteWebMain {
-
- val logger:Logger = LoggerFactory.getLogger(this.getClass)
-
- val postUsageMsg= Some("""
- |PROPERTIES
- |
- | * Keystore properties that need to be set if https is started
- | -Djetty.ssl.keyStoreType=type : the type of the keystore, JKS by default usually
- | -Djetty.ssl.keyStore=path : specify path to key store (for https server certificate)
- | -Djetty.ssl.keyStorePassword=password : specify password for keystore store (optional)
- |
- |NOTES
- |
- | - Trust stores are not needed because we use the WebID protocol, and client certs are nearly never signed by CAs
- | - one of --http or --https must be selected
- """.stripMargin);
-
- val parser = new ArgotParser("read-write-web",postUsage=postUsageMsg)
-
- val mode = parser.option[RWWMode](List("mode"), "m", "wiki mode: wiki or strict") {
- (sValue, opt) =>
- sValue match {
- case "wiki" => AllResourcesAlreadyExist
- case "strict" => ResourcesDontExistByDefault
- case _ => throw new ArgotConversionException("Option %s: must be either wiki or strict" format (opt.name, sValue))
- }
- }
-
- val rdfLanguage = parser.option[String](List("language"), "l", "RDF language: n3, turtle, or rdfxml") {
- (sValue, opt) =>
- sValue match {
- case "n3" => "N3"
- case "turtle" => "N3"
- case "rdfxml" => "RDF/XML-ABBREV"
- case _ => throw new ArgotConversionException("Option %s: must be either n3, turtle or rdfxml" format (opt.name, sValue))
- }
- }
-
- val httpPort = parser.option[Int]("http", "Port","start the http server on port")
- val httpsPort = parser.option[Int]("https","port","start the https server on port")
-
- val rootDirectory = parser.parameter[File]("rootDirectory", "root directory", false) {
- (sValue, opt) => {
- val file = new File(sValue)
- if (! file.exists)
- throw new ArgotConversionException("Option %s: %s must be a valid path" format (opt.name, sValue))
- else
- file
- }
- }
-
- implicit val webCache = new WebCache()
-
-
- val baseURL = parser.parameter[String]("baseURL", "base URL", false)
-
- // regular Java main
- def main(args: Array[String]) {
-
- try {
- parser.parse(args)
- } catch {
- case e: ArgotUsageException => err.println(e.message); sys.exit(1)
- }
-
- val filesystem =
- new Filesystem(
- rootDirectory.value.get,
- baseURL.value.get,
- lang=rdfLanguage.value getOrElse "N3")(mode.value getOrElse ResourcesDontExistByDefault)
-
- val app = new ReadWriteWeb(filesystem)
-
- //this is incomplete: we should be able to start both ports.... not sure how to do this yet.
- val service = httpsPort.value match {
- case Some(port) => HttpsTrustAll(port,"0.0.0.0")
- case None => Http(httpPort.value.get)
- }
-
- // configures and launches a Jetty server
- service.filter(new FilterLogger(logger)).
- filter(new auth.AuthFilter).
- context("/public"){ ctx:ContextBuilder =>
- ctx.resources(ClasspathUtils.fromClasspath("public/").toURI.toURL)
- }.filter(app.plan).run()
-
- }
-
-}
-
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/Representation.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,70 @@
+
+package org.w3.readwriteweb
+
+import unfiltered.request._
+import java.net.URL
+
+sealed trait Representation
+
+object Representation {
+
+ def fromSuffix(suffix: String): Representation = {
+ suffix match {
+ case "n3" => RDFRepr(N3)
+ case "turtle" | "ttl" => RDFRepr(TURTLE)
+ case "rdf" => RDFRepr(RDFXML)
+ case "htm" | "html" | "xhtml" => HTMLRepr
+ case "jpeg" | "jpg" => ImageRepr(JPEG)
+ case "png" => ImageRepr(PNG)
+ case "gif" => ImageRepr(GIF)
+ case "/" => DirectoryRepr
+ case _ => UnknownRepr
+ }
+ }
+
+
+ val htmlContentTypes = Set("text/html", "application/xhtml+xml")
+ val imgageTypes = Set("image/jpeg","image/png","image/gif")
+
+ def acceptsHTML(ct: Iterable[String]) =
+ ! (htmlContentTypes & ct.toSet).isEmpty
+
+ def acceptsPicture(ct: Iterable[String]) =
+ ! (imgageTypes & ct.toSet).isEmpty
+
+ def fromAcceptedContentTypes(ct: Iterable[String]): Representation = {
+ Lang(ct) map RDFRepr.apply getOrElse {
+ Image(ct).map(ImageRepr.apply(_)).getOrElse {
+ if (acceptsHTML(ct))
+ HTMLRepr
+ else
+ UnknownRepr
+ }
+ }
+ }
+
+ /** implements http://www.w3.org/2001/tag/doc/metaDataInURI-31 and http://www.w3.org/2001/tag/doc/mime-respect
+ *
+ * if there is no known suffix (eg. the URI was already the authoritative one),
+ * inspects the given accepted content types
+ *
+ * This knows only about the RDF and HTML charsets
+ */
+ def apply(
+ suffixOpt: Option[String],
+ ct: Iterable[String]): Representation = {
+ suffixOpt map fromSuffix match {
+ case None | Some(UnknownRepr) => fromAcceptedContentTypes(ct)
+ case Some(repr) => repr
+ }
+ }
+
+
+
+}
+
+case class RDFRepr(lang: Lang) extends Representation
+case class ImageRepr(mime: Image) extends Representation
+case object HTMLRepr extends Representation
+case object DirectoryRepr extends Representation
+case object UnknownRepr extends Representation
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/RequestLang.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb
+
+import unfiltered.request._
+
+object RequestLang {
+
+ //is this type of use of apply, where it returns a type different from the class it seems
+ //to be constructing not confusing?
+ def apply(req: HttpRequest[_]): Option[Lang] =
+ Lang(RequestContentType(req))
+
+ def unapply(req: HttpRequest[_]): Option[Lang] =
+ Lang(RequestContentType(req))
+
+ def unapply(ct: String): Option[Lang] =
+ Lang(ct)
+
+}
+
+object AcceptLang {
+
+
+ def unapply(req: HttpRequest[_]): Option[Lang] =
+ Lang(Accept(req))
+
+ def unapply(ct: String): Option[Lang] =
+ Lang(ct)
+
+}
\ No newline at end of file
--- a/src/main/scala/Resource.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/main/scala/Resource.scala Wed May 23 23:47:37 2012 +0200
@@ -4,17 +4,63 @@
import java.net.URL
import com.hp.hpl.jena.rdf.model._
-import scalaz._
+import scalaz.{Resource => _, _}
import Scalaz._
+import java.io.InputStream
trait ResourceManager {
- def basePath: String
- def sanityCheck(): Boolean
- def resource(url: URL): Resource
+ def basePath:String
+ def sanityCheck():Boolean
+ def resource(url:URL):Resource
+}
+
+object CacheControl extends Enumeration {
+ val CacheOnly, CacheFirst, NoCache = Value
}
trait Resource {
- def get(): Validation[Throwable, Model]
- def save(model: Model): Validation[Throwable, Unit]
+ def name: URL
+
+ /**
+ * get the resource as a model.
+ * Note: the cache policy only really makes sense for remote resources, not for the file system.
+ * Note: returning a model only makes sense when the resource is something that can be transformed to
+ * one which is not always the case, especially not for images. (see below)
+ * @param policy
+ * @return
+ */
+ def get(policy: CacheControl.Value = CacheControl.CacheFirst): Validation[Throwable, Model]
+
+ /**
+ * Many resources are not images. We need to get inputStreams for this.
+ * (this model here is getting more and more complicated. The get that returns a model above cannot
+ * simply be reduced to this one, as in the FileResource doing a GET on the directory should return
+ * a Graph describing the directory for example. Dealing with this is going to be a bit more tricky than
+ * I (bblfish) have time for at this point - as it would probably require quite a deep rewrite.)
+ * )
+ * @return
+ */
+ def getStream: Validation[Throwable,InputStream]
+ def delete: Validation[Throwable, Unit]
+ def save(model:Model):Validation[Throwable, Unit]
+
+ /**
+ * PUT the inputstream in the location
+ *
+ * same comments as with getStream
+ *
+ * @param in inputstream containing serialisation
+ */
+ def putStream(in: InputStream): Validation[Throwable, Unit]
+
+ //These two methods only work when called on directories
+ def createDirectory: Validation[Throwable, Unit]
+
+ /**
+ *
+ * @param contentType this should be Lang or ContentType, which should be a superinterface on all CTs
+ * @return
+ */
+ def create(contentType: Representation): Validation[Throwable, Resource]
}
--- a/src/main/scala/WebCache.scala Thu Oct 13 13:34:16 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
- /*
- * Copyright (c) 2011 Henry Story (bblfish.net)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Henry Story. The name of bblfish.net may not be used to endorse
- * or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-package org.w3.readwriteweb
-
-import com.hp.hpl.jena.rdf.model.Model
-import java.net.URL
-import org.apache.http.MethodNotSupportedException
-import org.w3.readwriteweb.RDFEncoding._
-import org.w3.readwriteweb.util._
-import org.w3.readwriteweb.{RDFEncoding, RDFXML}
-import scalaz._
-import Scalaz._
-
-/**
- * @author Henry Story
- * @created: 12/10/2011
- *
- * The WebCache currently does not cache
- */
-class WebCache extends ResourceManager {
- import dispatch._
-
- val http = new Http
-
- def basePath = null //should be cache dir?
-
- def sanityCheck() = true //cache dire exists? But is this needed for functioning?
-
- def resource(u : URL) = new org.w3.readwriteweb.Resource {
-
- def get() = {
- // note we prefer rdf/xml and turtle over html, as html does not always contain rdfa, and we prefer those over n3,
- // as we don't have a full n3 parser. Better would be to have a list of available parsers for whatever rdf framework is
- // installed (some claim to do n3 when they only really do turtle)
- // we can't currently accept */* as we don't have GRDDL implemented
- val request = url(u.toString) <:< Map("Accept"->
- "application/rdf+xml,text/turtle,application/xhtml+xml;q=0.8,text/html;q=0.7,text/n3;q=0.6")
-
- //we need to tell the model about the content type
- val handler: Handler[Validation[Throwable, Model]] = request.>+>[Validation[Throwable, Model]](res => {
- res >:> { headers =>
- val encoding = headers("Content-Type").headOption match {
- case Some(mime) => RDFEncoding(mime)
- case None => RDFXML // it would be better to try to do a bit of guessing in this case by looking at content
- }
- val loc = headers("Content-Location").headOption match {
- case Some(loc) => new URL(u,loc)
- case None => new URL(u.getProtocol,u.getAuthority,u.getPort,u.getPath)
- }
- res>>{ in=>modelFromInputStream(in,loc.toString,encoding) }
-
- }
- })
- http(handler)
-
- }
-
- def save(model: Model) = { throw new MethodNotSupportedException("not implemented"); null }
- }
-}
--- a/src/main/scala/auth/AuthFilter.scala Thu Oct 13 13:34:16 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,384 +0,0 @@
-/*
- * Copyright (c) 2011 Henry Story (bblfish.net)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Henry Story. The name of bblfish.net may not be used to endorse
- * or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-package org.w3.readwriteweb.auth
-
-import java.security.cert.X509Certificate
-import javax.servlet._
-import org.slf4j.LoggerFactory
-import org.w3.readwriteweb._
-
-import java.util.{LinkedList, Date}
-import java.security.interfaces.RSAPublicKey
-import java.security.{Principal, PublicKey}
-import java.net.URL
-import java.math.BigInteger
-import com.hp.hpl.jena.rdf.model.RDFNode
-import collection.JavaConversions._
-import javax.security.auth.{Subject, Refreshable}
-import com.hp.hpl.jena.query._
-import org.apache.shiro.authc.AuthenticationToken
-
-/**
- * @author Henry Story from http://bblfish.net/
- * @created: 09/10/2011
- */
-
-case class WebIdPrincipal(webid: String) extends Principal {
- def getName = webid
- override def equals(that: Any) = that match {
- case other: WebIdPrincipal => other.webid == webid
- case _ => false
- }
-}
-
-case class Anonymous() extends Principal {
- def getName = "anonymous"
- override def equals(that: Any) = that match {
- case other: WebIdPrincipal => other eq this
- case _ => false
- } //anonymous principals are equal only when they are identical. is this wise?
- //well we don't know when two anonymous people are the same or different.
-}
-
-class AuthFilter(implicit webCache: WebCache) extends Filter {
- def init(filterConfig: FilterConfig) {}
-
- def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
- val certChain = request.getAttribute("javax.servlet.request.X509Certificate") match {
- case certs: Array[X509Certificate] => certs.toList
- case _ => Nil
- }
- val subject = new Subject()
- if (certChain.size == 0) {
- System.err.println("No certificate found!")
- subject.getPrincipals.add(Anonymous())
- } else {
- val x509c = new X509Claim(certChain(0))
- subject.getPublicCredentials.add(x509c)
-
-
- val verified = for (
- claim <- x509c.webidclaims;
- if (claim.verified)
- ) yield claim.principal
-
- subject.getPrincipals.addAll(verified)
- System.err.println("Found "+verified.size+" principals: "+verified)
- }
-
- chain.doFilter(request, response)
- }
-
- def destroy() {}
-}
-
-object X509Claim {
- final val logger = LoggerFactory.getLogger(classOf[X509Claim])
-
- /**
- * Extracts the URIs in the subject alternative name extension of an X.509
- * certificate
- *
- * @param cert X.509 certificate from which to extract the URIs.
- * @return Iterator of URIs as strings found in the subjectAltName extension.
- */
- def getClaimedWebIds(cert: X509Certificate): Iterator[String] =
- if (cert == null) Iterator.empty;
- else cert.getSubjectAlternativeNames() match {
- case coll if (coll != null) => {
- for (sanPair <- coll
- if (sanPair.get(0) == 6)
- ) yield sanPair(1).asInstanceOf[String]
- }.iterator
- case _ => Iterator.empty
- }
-
-
-
-}
-
-
-/**
- * An X509 Claim maintains information about the proofs associated with claims
- * found in an X509 Certificate. It is the type of object that can be passed
- * into the public credentials part of a Subject node
- *
- * todo: think of what this would look like for a chain of certificates
- *
- * @author bblfish
- * @created: 30/03/2011
- */
-class X509Claim(val cert: X509Certificate)(implicit webCache: WebCache) extends Refreshable with AuthenticationToken {
-
- import X509Claim._
- val claimReceivedDate = new Date();
- lazy val tooLate = claimReceivedDate.after(cert.getNotAfter())
- lazy val tooEarly = claimReceivedDate.before(cert.getNotBefore())
-
- /* a list of unverified principals */
- lazy val webidclaims = getClaimedWebIds(cert).map {
- webid =>new WebIDClaim(webid, cert.getPublicKey)
- }.toSet
-
-
- //note could also implement Destroyable
- //
- //http://download.oracle.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html#Credentials
- //
- //if updating validity periods can also take into account the WebID reference, then it is possible
- //that a refresh could have as consequence to do a fetch on the WebID profile
- //note: one could also take the validity period to be dependent on the validity of the profile representation
- //in which case updating the validity period would make more sense.
-
- override
- def refresh() {
- }
-
- /* The certificate is currently within the valid time zone */
- override
- def isCurrent(): Boolean = !(tooLate||tooEarly)
-
- lazy val error = {}
-
- def canEqual(other: Any) = other.isInstanceOf[X509Claim]
-
- override
- def equals(other: Any): Boolean =
- other match {
- case that: X509Claim => (that eq this) || (that.canEqual(this) && cert == that.cert)
- case _ => false
- }
-
- override
- lazy val hashCode: Int = 41 * (41 +
- (if (cert != null) cert.hashCode else 0))
-
- //for Shiro, we'll think of the cert as a principal as well as a credential
- def getPrincipal = cert
-
- def getCredentials = cert
-}
-
-object WebIDClaim {
- final val cert: String = "http://www.w3.org/ns/auth/cert#"
- final val xsd: String = "http://www.w3.org/2001/XMLSchema#"
-
- val selectQuery = QueryFactory.create("""
- PREFIX cert: <http://www.w3.org/ns/auth/cert#>
- PREFIX rsa: <http://www.w3.org/ns/auth/rsa#>
- SELECT ?key ?m ?e ?mod ?exp
- WHERE {
- ?key cert:identity ?webid ;
- rsa:modulus ?m ;
- rsa:public_exponent ?e .
-
- OPTIONAL { ?m cert:hex ?mod . }
- OPTIONAL { ?e cert:decimal ?exp . }
- }""")
-
- /**
- * Transform an RDF representation of a number into a BigInteger
- * <p/>
- * Passes a statement as two bindings and the relation between them. The
- * subject is the number. If num is already a literal number, that is
- * returned, otherwise if enough information from the relation to optstr
- * exists, that is used.
- *
- * @param num the number node
- * @param optRel name of the relation to the literal
- * @param optstr the literal representation if it exists
- * @return the big integer that num represents, or null if undetermined
- */
- def toInteger(num: RDFNode, optRel: String, optstr: RDFNode): Option[BigInteger] =
- if (null == num) None
- else if (num.isLiteral) {
- val lit = num.asLiteral()
- toInteger_helper(lit.getLexicalForm,lit.getDatatypeURI)
- } else if (null != optstr && optstr.isLiteral) {
- toInteger_helper(optstr.asLiteral().getLexicalForm,optRel)
- } else None
-
-
- private def intValueOfHexString(s: String): BigInteger = {
- val strval = cleanHex(s);
- new BigInteger(strval, 16);
- }
-
-
- /**
- * This takes any string and returns in order only those characters that are
- * part of a hex string
- *
- * @param strval
- * any string
- * @return a pure hex string
- */
-
- private def cleanHex(strval: String) = {
- def legal(c: Char) = {
- //in order of appearance probability
- ((c >= '0') && (c <= '9')) ||
- ((c >= 'A') && (c <= 'F')) ||
- ((c >= 'a') && (c <= 'f'))
- }
- (for (c <- strval; if legal(c)) yield c)
- }
-
-
- /**
- * This transforms a literal into a number if possible ie, it returns the
- * BigInteger of "ddd"^^type
- *
- * @param num the string representation of the number
- * @param tpe the type of the string representation
- * @return the number
- */
- protected def toInteger_helper(num: String, tpe: String): Option[BigInteger] =
- try {
- if (tpe.equals(cert + "decimal") || tpe.equals(cert + "int")
- || tpe.equals(xsd + "integer") || tpe.equals(xsd + "int")
- || tpe.equals(xsd + "nonNegativeInteger")) {
- // cert:decimal is deprecated
- Some(new BigInteger(num.trim(), 10));
- } else if (tpe.equals(cert + "hex")) {
- Some(intValueOfHexString(num));
- } else {
- // it could be some other encoding - one should really write a
- // special literal transformation class
- None;
- }
- } catch {
- case e: NumberFormatException => None
- }
-
-
-}
-
-/**
- * An X509 Claim maintains information about the proofs associated with claims
- * found in an X509 Certificate. It is the type of object that can be passed
- * into the public credentials part of a Subject node
- *
- * todo: think of what this would look like for a chain of certificates
- *
- * @author bblfish
- * @created 30/03/2011
- */
-class WebIDClaim(val webId: String, val key: PublicKey)(implicit cache: WebCache) extends AuthenticationToken {
-
- val errors = new LinkedList[java.lang.Throwable]()
-
- lazy val principal = new WebIdPrincipal(webId)
- lazy val tests: List[Verification] = verify() //I need to try to keep more verification state
-
-
- /**
- * verify this claim
- * @param authSrvc: the authentication service contains information about where to get graphs
- */
- //todo: make this asynchronous
- lazy val verified: Boolean = tests.exists(v => v.isInstanceOf[Verified])
-
- private def verify(): List[Verification] = {
- import util.wrapValidation
- import collection.JavaConversions._
- import WebIDClaim._
- if (!webId.startsWith("http:") && !webId.startsWith("https:")) {
- //todo: ftp, and ftps should also be doable, though content negotiations is then lacking
- unsupportedProtocol::Nil
- } else if (!key.isInstanceOf[RSAPublicKey]) {
- certificateKeyTypeNotSupported::Nil
- } else {
- val res = for {
- model <- cache.resource(new URL(webId)).get() failMap {
- t => new ProfileError("error fetching profile", t)
- }
- } yield {
- val initialBinding = new QuerySolutionMap();
- initialBinding.add("webid",model.createResource(webId))
- val qe: QueryExecution = QueryExecutionFactory.create(WebIDClaim.selectQuery, model,initialBinding)
- try {
- qe.execSelect().map( qs => {
- val modulus = toInteger(qs.get("m"), cert + "hex", qs.get("mod"))
- val exponent = toInteger(qs.get("e"), cert + "decimal", qs.get("exp"))
-
- (modulus, exponent) match {
- case (Some(mod), Some(exp)) => {
- val rsakey = key.asInstanceOf[RSAPublicKey]
- if (rsakey.getPublicExponent == exp && rsakey.getModulus == mod) verifiedWebID
- else keyDoesNotMatch
- }
- case _ => new KeyProblem("profile contains key that cannot be analysed:" +
- qs.varNames().map(nm => nm + "=" + qs.get(nm).toString) + "; ")
- }
- }).toList
- //it would be nice if we could keep a lot more state of what was verified and how
- //will do that when implementing tests, so that these tests can then be used directly as much as possible
- } finally {
- qe.close()
- }
- }
- res.either match {
- case Right(tests) => tests
- case Left(profileErr) => profileErr::Nil
- }
- }
-
-
- }
-
-
-
- def canEqual(other: Any) = other.isInstanceOf[WebIDClaim]
-
- override
- def equals(other: Any): Boolean =
- other match {
- case that: WebIDClaim => (that eq this) || (that.canEqual(this) && webId == that.webId && key == that.key)
- case _ => false
- }
-
- override
- lazy val hashCode: Int = 41 * (
- 41 * (
- 41 + (if (webId != null) webId.hashCode else 0)
- ) + (if (key != null) key.hashCode else 0)
- )
-
- def getPrincipal = webId
-
- def getCredentials = key
-}
-
-
-class Verification(msg: String)
-class Verified(msg: String) extends Verification(msg)
-class Unverified(msg: String) extends Verification(msg)
-
-class TestFailure(msg: String) extends Verification(msg)
-class ProfileError(msg: String, t: Throwable ) extends TestFailure(msg)
-class KeyProblem(msg: String) extends TestFailure(msg)
-
-object unsupportedProtocol extends TestFailure("WebID protocol not supported")
-object noMatchingKey extends TestFailure("No keys in profile matches key in cert")
-object keyDoesNotMatch extends TestFailure("Key does not match")
-
-object verifiedWebID extends Verified("WebId verified")
-object notstarted extends Unverified("No verification attempt started")
-object failed extends Unverified("Tests failed")
-object certificateKeyTypeNotSupported extends TestFailure("The certificate key type is not supported. We only support RSA")
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/auth/Authz.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import unfiltered.request._
+import collection.JavaConverters._
+import javax.security.auth.Subject
+import java.net.URL
+import com.hp.hpl.jena.query.{QueryExecutionFactory, QuerySolutionMap, QueryFactory}
+import unfiltered.response.{ResponseFunction, Unauthorized}
+import com.hp.hpl.jena.rdf.model.ResourceFactory
+import org.w3.readwriteweb.{Authoritative, Resource, ResourceManager, GraphCache}
+import org.w3.readwriteweb.util.HttpMethod
+
+/**
+ * @author hjs
+ * @created: 14/10/2011
+ */
+
+object AuthZ {
+
+ implicit def x509toSubject(x509c: X509Claim): Subject = {
+ val subject = new Subject()
+ subject.getPublicCredentials.add(x509c)
+ if (x509c.isCurrent()) {
+ val verified = x509c.verified
+ subject.getPrincipals.addAll(verified.asJava)
+ }
+ subject
+ }
+}
+
+class NullAuthZ[Request, Response] extends AuthZ[Request, Response] {
+ def subject(req: Req): Option[Subject] = None
+
+ def guard(m: Method, path: URL): Guard = null
+
+ override def protect(in: Req => Res)(implicit m: Manifest[Request]) = in
+}
+
+
+trait AuthZ[Request, Response] {
+ type Req = HttpRequest[Request]
+ type Res = ResponseFunction[Response]
+
+ def protect(in: Req => Res)(implicit m: Manifest[Request]): Req => Res = {
+ case req @ HttpMethod(method) & Authoritative(url,_) if guard(method, url).allow(subject(req)) => in(req)
+ case _ => Unauthorized
+ }
+
+ protected def subject(req: Req): Option[Subject]
+
+ /** create the guard defined in subclass */
+ protected def guard(m: Method, path: URL): Guard
+
+ abstract class Guard(m: Method, url: URL) {
+
+ /**
+ * verify if the given request is authorized
+ * @param subj function returning the subject to be authorized if the resource needs authorization
+ */
+ def allow(subj: => Option[Subject]): Boolean
+ }
+
+}
+
+
+class RDFAuthZ[Request, Response](val rm: ResourceManager)(implicit val m: Manifest[Request])
+ extends AuthZ[Request,Response] {
+
+ import AuthZ.x509toSubject
+
+
+ def subject(req: Req) = req match {
+ case X509Claim(claim) => Option(claim)
+ case _ => None
+ }
+
+ object RDFGuard {
+ val acl = "http://www.w3.org/ns/auth/acl#"
+ val foafAgent = ResourceFactory.createResource("http://xmlns.com/foaf/0.1/Agent")
+ val Read = acl+"Read"
+ val Write = acl+"Write"
+ val Control = acl+"Control"
+
+ val selectQuery = QueryFactory.create("""
+ PREFIX acl: <http://www.w3.org/ns/auth/acl#>
+ SELECT ?mode ?group ?agent
+ WHERE {
+ ?auth acl:accessTo ?res ;
+ acl:mode ?mode .
+ OPTIONAL { ?auth acl:agentClass ?group . }
+ OPTIONAL { ?auth acl:agent ?agent . }
+ }""")
+ }
+
+ def guard(method: Method, url: URL) = new Guard(method, url) {
+ import RDFGuard._
+ import org.w3.readwriteweb.util.{ValidationW, wrapValidation}
+
+ def allow(subj: => Option[Subject]) = {
+ val r: Resource = rm.resource(new URL(url,".meta.n3"))
+ val res: ValidationW[Boolean,Boolean] = for {
+ model <- r.get() failMap { x => true }
+ } yield {
+ val initialBinding = new QuerySolutionMap();
+ initialBinding.add("res", model.createResource(url.toString)) //todo: this will work only if the files are described with relative URLs
+ val qe = QueryExecutionFactory.create(selectQuery, model, initialBinding)
+ val agentsAllowed = try {
+ val exec = qe.execSelect()
+ val res = for (qs <- exec.asScala) yield {
+ val methods = qs.get("mode").toString match {
+ case Read => List(GET)
+ case Write => List(PUT, POST)
+ case Control => List(POST)
+ case _ => List(GET, PUT, POST, DELETE) //nothing everything is allowed
+ }
+ if (methods.contains(method)) Some((qs.get("agent"), qs.get("group")))
+ else None
+ }
+ res.flatten.toList
+ } finally {
+ qe.close()
+ }
+ if (agentsAllowed.size > 0) {
+ if (agentsAllowed.exists( pair => pair._2 == foafAgent )) true
+ else subj match {
+ case Some(s) => {
+ agentsAllowed.exists{
+ p => s.getPrincipals(classOf[WebID]).asScala.
+ exists(id=> {
+ val ps = if (p._1 != null) p._1.toString else null;
+ ps == id.getName
+ })
+ }
+ }
+ case None => false
+ }
+ //currently we just check for agent match. Group match would require us to have a store
+ //of trusted information of which groups someone was member of -- one would probably need a reasoning engine there.
+ } else false //
+ }
+ res.validation.fold()
+ } // end allow()
+
+
+ }
+
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/auth/Principals.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import java.security.Principal
+import com.hp.hpl.jena.rdf.model.Model
+import com.hp.hpl.jena.shared.WrappedIOException
+import scalaz.{Scalaz, Validation}
+import Scalaz._
+import java.net.{ConnectException, URL}
+import org.w3.readwriteweb.{CacheControl, GraphCache}
+
+/**
+ * @author Henry Story from http://bblfish.net/
+ * @created: 09/10/2011
+ */
+
+/**
+ * The WebID - ie, verified identity - something like a Principal.
+ * it is arguable that it should know what it was verified against.
+ */
+protected object WebID {
+
+ def apply(subjectAlternativeName: String): Validation[SANFailure,WebID] =
+ toUrl(subjectAlternativeName) flatMap { url =>
+ val protocol = url.getProtocol
+ if ("http".equals(protocol) || "https".equals(protocol)) {
+ new WebID(url).success
+ } else UnsupportedProtocol("only http and https url supported at present",subjectAlternativeName).fail
+ }
+
+
+
+ def toUrl(urlStr: String): Validation[SANFailure,URL] = {
+ try { new URL(urlStr).success } catch {
+ // oops: should be careful, not all SANs are perhaps traditionally written out as a full URL.
+ case e => URISyntaxError("unparseable Subject Alternative Name",urlStr).fail
+ }
+ }
+
+}
+
+/**
+ * A WebID Principal
+ * Can only be constructed by the object, which does some minimal verifications
+ **/
+case class WebID private (val url: URL) extends Principal {
+ import org.w3.readwriteweb.util.wrapValidation
+
+ def getName = url.toExternalForm
+
+ override def equals(that: Any) = that match {
+ case other: WebID => other.url == url
+ case _ => false
+ }
+
+ //TODO: now that we are no longer passing the GraphCache around it's questionable whether we still need this method
+ //in this class
+ def getDefiningModel(cacheControl: CacheControl.Value = CacheControl.CacheFirst): Validation[ProfileError, Model] =
+ GraphCache.resource(url).get(cacheControl) failMap {
+ case ioe: WrappedIOException => new ProfileGetError("error fetching profile", Some(ioe),url)
+ case connE : ConnectException => new ProfileGetError("error fetching profile", Some(connE),url)
+ case other => new ProfileParseError("error parsing profile", Some(other),url)
+ }
+}
+
+
+case class Anonymous() extends Principal {
+ def getName = "anonymous"
+ override def equals(that: Any) = that match {
+ case other: Principal => other eq this
+ case _ => false
+ } //anonymous principals are equal only when they are identical. is this wise?
+ //well we don't know when two anonymous people are the same or different.
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/auth/WebIDSrvc.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package auth
+
+import unfiltered.Cycle
+import java.net.{URLEncoder, URL}
+import java.util.Calendar
+import org.apache.commons.codec.binary.Base64
+import java.text.SimpleDateFormat
+import org.w3.readwriteweb.util.trySome
+import unfiltered.request.Params.ParamMapper
+import com.hp.hpl.jena.rdf.model.ModelFactory
+import sommer.{CertAgent, Extractors}
+import org.w3.readwriteweb.util._
+import unfiltered.request._
+import org.fusesource.scalate.scuery.{Transform, Transformer}
+import org.w3.readwriteweb.netty.ReadWriteWebNetty.StaticFiles
+import java.lang.String
+import xml._
+import unfiltered.response._
+import java.security.interfaces.RSAPublicKey
+import org.w3.readwriteweb.auth._
+
+object WebIDSrvc {
+ val dateFormat: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
+
+ val noImage = "idp/profile_anonymous.png" //"http://eagereyes.org/media/2010/empty-frame.jpg"
+
+}
+
+/**
+ * @author Henry Story
+ *
+ */
+trait WebIDSrvc[Req,Res] {
+ implicit def manif: Manifest[Req]
+ val signer: Option[X509CertSigner]
+
+ import WebIDSrvc._
+
+
+
+ def sign(urlStr: String): URL = {
+ val timeStampedUrlStr = urlStr + "ts=" + URLEncoder.encode(dateFormat.format(Calendar.getInstance.getTime), "UTF-8")
+ val signedUri = signer.map(sgnr =>
+ timeStampedUrlStr +
+ "&sig=" + URLEncoder.encode(new String(Base64.encodeBase64URLSafeString(sgnr.sign(timeStampedUrlStr))), "UTF-8")
+ ).getOrElse(timeStampedUrlStr)
+ return new URL(signedUri)
+ }
+
+
+ val fileDir ="/template/webidp/"
+
+ /**
+ * using three different templates uses up more memory for the moment, and could be more maintenance work
+ * if all three templates require similar changes, but it makes it easier to visualise the result without
+ * needing a web server.
+ */
+ lazy val errorPg: Elem = XML.load(this.getClass.getResourceAsStream(fileDir+ "WebIdService.badcert.html"))
+ lazy val authenticatedPg: Elem = XML.load(this.getClass.getResourceAsStream(fileDir+ "WebIdService.auth.html"))
+ lazy val aboutPg: Elem = XML.load(this.getClass.getResourceAsStream(fileDir+ "WebIdService.about.html"))
+ lazy val profilePg: Elem = XML.load(this.getClass.getResourceAsStream(fileDir+ "WebIdService.entry.html"))
+
+ def intent : Cycle.Intent[Req,Res] = {
+ case req @ Path(Seg("srv" :: "idp" :: next)) => { //easy partial function entry match
+ if (next!=Nil && next.size==1) srvStaticFiles(next.head)
+ else req match {
+ case Params(RelyingParty(rp)) => req match {
+ //&doit => we redirect to the relying party with the identity answer
+ //TODO: here I would have liked to go with what the user decided without forcing him to login,
+ //ie by using XClaim(claim) in the match,
+ //but http://stackoverflow.com/questions/8731157/netty-https-tls-session-duration-why-is-renegotiation-needed
+ case Params(DoIt(_)) => {
+ val answer = X509Claim.unapply(req) match {
+ case None => "error=nocert&"
+ case Some(claim) =>
+ if (claim.claims.size == 0) "error=noWebID&"
+ else if (claim.verified.size == 0) "error=noVerifiedWebID&" +
+ claim.claims.map(claim => claim.verify.failMap(e => "cause=" + e.getMessage)).mkString("&") + "&"
+ else claim.verified.slice(0, 3).foldRight("") {
+ (wid, str) => "webid=" + URLEncoder.encode(wid.url.toExternalForm, "UTF-8") + "&"
+ }
+ }
+ val signedAnswer = sign(rp.toExternalForm + "?" + answer).toExternalForm
+ Redirect(signedAnswer) ~> Expires("0") ~> CacheControl("no-cache")
+ }
+ //GET=>The user just arrived on the page. We recuperated the X509 claim in case he has authenticated already
+ case GET(_) & XClaim(claim: XClaim) => {
+ val pg = claim match {
+ case NoClaim => profilePg
+ case claim: X509Claim => if (claim.verified.size > 0) authenticatedPg else errorPg
+ }
+ Ok ~> Html5(new ServiceTrans(rp, claim).apply(pg)) ~> Expires("0") ~> CacheControl("no-cache")
+ }
+ //POST=> we authenticate the user because he has agreed to be authenticated on the page, which we know if the
+ // request is a POST
+ case POST(_) & X509Claim(claim: X509Claim) => {
+ //repetition because of intellij scala 0.5.273 bug
+ val pg = if (claim.verified.size > 0) authenticatedPg else errorPg
+ Ok ~> Html5(new ServiceTrans(rp, claim).apply(pg))
+ }
+ case _ => Ok ~> Html5(new ServiceTrans(rp, NoClaim).apply(errorPg))
+ }
+ case _ => Ok ~> Html5(aboutTransform.apply(aboutPg))
+ }
+ }
+
+ }
+
+
+ object TransUtils {
+ //taken from http://stackoverflow.com/questions/2569580/how-to-change-attribute-on-scala-xml-element
+ implicit def addGoodCopyToAttribute(attr: Attribute) = new {
+ def goodcopy(key: String = attr.key, value: Any = attr.value): Attribute =
+ Attribute(attr.pre, key, Text(value.toString), attr.next)
+ }
+
+ implicit def iterableToMetaData(items: Iterable[MetaData]): MetaData = {
+ items match {
+ case Nil => Null
+ case head :: tail => head.copy(next=iterableToMetaData(tail))
+ }
+ }
+ }
+
+ object srvStaticFiles extends StaticFiles {
+ override def toLocal(file: String) = "/template/webidp/idp/"+file
+ }
+
+ object aboutTransform extends Transformer {
+ val key = signer.map(_.signingCert.getPublicKey.asInstanceOf[RSAPublicKey])
+ $(".modulus").contents = key.map(_.getModulus.toString(16)).getOrElse("no key, no modulus - no signature - contact admin!")
+ $(".exponent").contents = key.map(_.getPublicExponent.toString).getOrElse("no key, no exponent")
+ }
+
+ class ServiceTrans(relyingParty: URL, claim: XClaim) extends Transformer {
+ $(".webidform") { node =>
+ val elem = node.asInstanceOf[scala.xml.Elem]
+ import TransUtils._
+ val newelem = elem.copy(attributes=for(attr <- elem.attributes) yield attr match {
+ case attr@Attribute("action", _, _) => attr.goodcopy(value="/srv/idp?rs="+relyingParty.toExternalForm)
+ case other => other
+ })
+ new Transform(newelem) {
+ $(".authenticated") { node =>
+ claim match {
+ case NoClaim => <span/>
+ case _ => new Transform(node) {
+ val union = claim.verified.flatMap(_.getDefiningModel().toOption).fold(ModelFactory.createDefaultModel()) {
+ (m1, m2) => m1.add(m2)
+ }
+ //this works because we have verified before
+ val person = if (union.size() > 0) Extractors.namedPerson(union, claim.verified.head.url)
+ else new CertAgent(claim.cert.getSubjectDN.getName)
+ $(".user_name").contents = person.name
+ $(".mugshot").attribute("src").value = person.depictions.collectFirst {
+ case o => o.toString
+ }.getOrElse(noImage)
+ }.toNodes()
+ }
+ }
+ $(".error").contents = {
+ if (claim==NoClaim) "We received no Certificate"
+ else if (claim.claims.size==0) "Certificate contained no WebID"
+ else if (claim.verified.size==0) "Could not verify any of the WebIDs"
+ else "Some error occured"
+ }
+ $(".response") { nodeRes =>
+ val elemRes = nodeRes.asInstanceOf[scala.xml.Elem]
+ val newElem = elemRes.copy(attributes=for(attr <- elemRes.attributes) yield attr match {
+ case attr@Attribute("href", _, _) =>
+ attr.goodcopy(value= "/srv/idp?rs="+URLEncoder.encode(relyingParty.toExternalForm,"UTF-8") + "&doit=true" )
+ case other => other
+ })
+ new Transform(newElem) {
+ $(".sitename").contents = relyingParty.getHost
+ }.toNodes()
+ }
+
+ }.toNodes()
+ }
+ }
+}
+
+case class Html5(nodes: scala.xml.NodeSeq) extends ComposeResponse(HtmlContent ~> {
+ val w = new java.io.StringWriter()
+ val html = nodes.head match {
+ case <html>{_*}</html> => nodes.head
+ case _ => <html>{nodes}</html>
+ }
+ xml.XML.write( w, html, "UTF-8", xmlDecl = false, doctype =
+ xml.dtd.DocType( "html", xml.dtd.SystemID( "about:legacy-compat" ), Nil ))
+ ResponseString(w.toString)
+})
+
+
+ /**
+ * similar to Extract superclass, but is useful when one has a number of attributes that
+ * have the same meaning. This can arise if one has legacy URLS or if one has code that
+ * has human readable and shorter ones
+ */
+import unfiltered.request.Params.Map
+class ExtractN[E,T](f: Map => Option[T]) extends Params.Extract[E,T](f) {
+ def this(names: Seq[String], f: Seq[String] => Option[T]) =
+ this({ params: Map => f(names.flatMap(s => params(s))) })
+}
+
+object urlMap extends ParamMapper(_.flatMap(u=>trySome{new URL(u)}).headOption)
+object RelyingParty extends ExtractN(List("rs","authreqissuer"), urlMap )
+object DoIt extends Params.Extract("doit", Params.first)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/auth/WebIdClaim.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import java.security.interfaces.RSAPublicKey
+import scalaz.Scalaz
+import Scalaz._
+import java.security.PublicKey
+import com.hp.hpl.jena.rdf.model.Model
+import com.hp.hpl.jena.query._
+import java.math.BigInteger
+import com.hp.hpl.jena.datatypes.xsd.XSDDatatype
+import scalaz.{Failure, Validation}
+import org.w3.readwriteweb.CacheControl
+import java.net.URL
+
+
+/**
+ * One can only construct a WebID via the WebIDClaim apply
+ */
+object WebIDClaim {
+ final val cert: String = "http://www.w3.org/ns/auth/cert#"
+ val numericDataTypes = List(XSDDatatype.XSDinteger, XSDDatatype.XSDint, XSDDatatype.XSDpositiveInteger, XSDDatatype.XSDdecimal)
+
+ //we cannot do the simpler ask query as Jena does not do Sparql d-entailment on xsd:hexBinary
+ //There is also the problem that most parsers will not be very lenient and fail on spaces in the hex
+ //( as required for little gain by xsd:hexBinary spec)
+ val query = QueryFactory.create("""
+ PREFIX : <http://www.w3.org/ns/auth/cert#>
+ SELECT ?m ?e
+ WHERE {
+ ?webid :key [ :modulus ?m ;
+ :exponent ?e ].
+ }""")
+
+ /*
+ * Useful when converting the bytes from a BigInteger to a hex for inclusion in rdf
+ **/
+ def hex(bytes: Array[Byte]): String = bytes.dropWhile(_ == 0).map("%02X" format _).mkString
+
+ def stripSpace(hex: String): String = hex.filter(c => !Character.isWhitespace(c))
+
+}
+
+/**
+ * One has to construct a WebID using the object, that can do basic verifications
+ */
+class WebIDClaim(val san: String, val key: PublicKey) {
+
+ import WebIDClaim._
+
+ private def rsaTest(webid: WebID, rsakey: RSAPublicKey): (Model) => Validation[WebIDVerificationFailure, WebID] = {
+ model =>
+ val initialBinding = new QuerySolutionMap();
+ initialBinding.add("webid", model.createResource(webid.url.toString))
+ // initialBinding.add("m", model.createTypedLiteral(hex(rsakey.getModulus.toByteArray), XSDhexBinary))
+ // initialBinding.add("e", model.createTypedLiteral(rsakey.getPublicExponent.toString, XSDinteger))
+ val qe: QueryExecution = QueryExecutionFactory.create(WebIDClaim.query, model, initialBinding)
+ try {
+ def matches: Boolean = {
+ import scala.collection.JavaConversions._
+ val resultset = qe.execSelect().toSet
+ resultset.exists {
+ sol: QuerySolution => try {
+ val mod = sol.getLiteral("m")
+ if (mod.getDatatype == XSDDatatype.XSDhexBinary &&
+ new BigInteger(stripSpace(mod.getLexicalForm), 16) == rsakey.getModulus) {
+ val exp = sol.getLiteral("e")
+ numericDataTypes.contains(exp.getDatatype) && new BigInteger(exp.getLexicalForm.trim) == rsakey.getPublicExponent
+ } else false
+ } catch {
+ case _ => false
+ }
+ }
+ }
+ if (matches) webid.success
+ else new WebIDVerificationFailure("could not verify public key", None, this).fail
+ } finally {
+ qe.close()
+ }
+ }
+
+ def verify: Validation[WebIDClaimFailure, WebID] = key match {
+ case rsakey: RSAPublicKey =>
+ WebID(san).flatMap(webid=> {
+ webid.getDefiningModel(CacheControl.CacheOnly).flatMap(rsaTest(webid, rsakey)) match {
+ case Failure(_) => webid.getDefiningModel(CacheControl.NoCache).flatMap(rsaTest(webid, rsakey))
+ case o => o
+ }
+ }
+ )
+ case _ => new UnsupportedKeyType("We only support RSA keys at present", key).fail
+ }
+}
+
+
+trait Err {
+ type T <: AnyRef
+ val msg: String
+ val cause: Option[Throwable]=None
+ val subject: T
+}
+
+abstract class Fail extends Throwable with Err
+
+abstract class WebIDClaimFailure extends Fail
+
+class UnsupportedKeyType(val msg: String, val subject: PublicKey) extends WebIDClaimFailure { type T = PublicKey }
+
+
+abstract class SANFailure extends WebIDClaimFailure { type T = String }
+case class UnsupportedProtocol(val msg: String, subject: String) extends SANFailure
+case class URISyntaxError(val msg: String, subject: String) extends SANFailure
+
+//The subject could be more refined than the URL, especially in the paring error
+abstract class ProfileError extends WebIDClaimFailure { type T = URL }
+case class ProfileGetError(val msg: String, override val cause: Option[Throwable], subject: URL) extends ProfileError
+case class ProfileParseError(val msg: String, override val cause: Option[Throwable], subject: URL) extends ProfileError
+
+//it would be useful to pass the graph in
+class WebIDVerificationFailure(val msg: String, val caused: Option[Throwable], val subject: WebIDClaim)
+ extends WebIDClaimFailure { type T = WebIDClaim }
--- a/src/main/scala/auth/WebIdRealm.scala Thu Oct 13 13:34:16 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2011 Henry Story (bblfish.net)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Henry Story. The name of bblfish.net may not be used to endorse
- * or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-package org.w3.readwriteweb.auth
-
-import org.w3.readwriteweb.WebCache
-import org.apache.shiro.authc.{AuthenticationInfo, AuthenticationToken}
-import org.apache.shiro.subject.{SimplePrincipalCollection, PrincipalCollection}
-import collection.JavaConversions
-import org.apache.shiro.realm.{AuthenticatingRealm, AuthorizingRealm}
-import org.apache.shiro.authz.AuthorizationInfo
-
-/**
- * @author hjs
- * @created: 12/10/2011
- */
-
-class WebIdRealm(cache: WebCache) extends AuthorizingRealm {
-
- def doGetAuthenticationInfo(token: AuthenticationToken): AuthenticationInfo = {
- val x509claim = token.asInstanceOf[X509Claim]
- val verified = for (
- claim <- x509claim.webidclaims;
- if (claim.verified)
- ) yield claim.principal
-
-
- return new AuthenticationInfo {
- def getPrincipals = new SimplePrincipalCollection(JavaConversions.asJavaCollection(verified),"webid")
-
- def getCredentials = x509claim
- }
- }
-
- // not really sure what to do here
- //
- def doGetAuthorizationInfo(principals: PrincipalCollection) = new AuthorizationInfo {
-
- def getRoles = null
-
- def getStringPermissions = null
-
- def getObjectPermissions = null
- }
-
-
-}
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/auth/X509Cert.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import javax.servlet.http.HttpServletRequest
+import unfiltered.netty.ReceivedMessage
+import java.util.Date
+import java.math.BigInteger
+import java.net.URL
+import unfiltered.request.{UserAgent, HttpRequest}
+import java.security.cert.{X509Certificate, Certificate}
+import java.security._
+import interfaces.RSAPublicKey
+import unfiltered.util.IO
+import sun.security.x509._
+import org.w3.readwriteweb.util.trySome
+import actors.threadpool.TimeUnit
+import com.google.common.cache.{CacheLoader, CacheBuilder, Cache}
+import scalaz.Validation
+import scalaz.Scalaz._
+
+import com.weiglewilczek.slf4s.Logging
+
+object X509CertSigner extends Logging {
+
+ def apply( keyStoreLoc: Option[URL],
+ keyStoreType: Option[String],
+ password: Option[String],
+ alias: Option[String]): Option[X509CertSigner] = {
+ try {
+ for {
+ loc <- keyStoreLoc
+ tp <- keyStoreType
+ } yield {
+ val pass = password.map(_.toCharArray).getOrElse(null)
+ val alias2 = alias.getOrElse("") //todo there are better ways of finding an alias than this
+ val ks = KeyStore.getInstance(tp)
+ IO.use(loc.openStream()) {
+ in => ks.load(in, pass)
+ }
+ val privateKey = ks.getKey(alias2, pass).asInstanceOf[PrivateKey]
+ val certificate = ks.getCertificate(alias2).asInstanceOf[X509Certificate]
+ //one could verify that indeed this is the private key corresponding to the public key in the cert.
+ new X509CertSigner(certificate, privateKey)
+ }
+ } catch {
+ case e: Exception => {
+ logger.warn("could not load TLS certificate for certificate signing service", e)
+ None
+ }
+ }
+ }
+
+ def apply( keyStoreLoc: URL,
+ keyStoreType: String,
+ password: String,
+ alias: String): X509CertSigner =
+ apply(Option(keyStoreLoc),Option(keyStoreType),Option(password),Option(alias)).get
+
+}
+
+class X509CertSigner(
+ val signingCert: X509Certificate,
+ signingKey: PrivateKey ) {
+ val WebID_DN="""O=FOAF+SSL, OU=The Community of Self Signers, CN=Not a Certification Authority"""
+
+ val sigAlg = signingKey.getAlgorithm match {
+ case "RSA" => "SHA1withRSA"
+ case "DSA" => "SHA1withDSA"
+ //else will throw a case exception
+ }
+
+
+ /**
+ * Adapted from http://bfo.com/blog/2011/03/08/odds_and_ends_creating_a_new_x_509_certificate.html
+ * The libraries used here are sun gpled code. This is much lighter to use than bouncycastle. All VMs that already
+ * have these classes don't need to download the code. It should be easy in scala to create a build that can decide
+ * if these need to be added to the classpath. I think the code just looks better than bouncycastle too.
+ *
+ * WARNING THIS IS in construction
+ *
+ * Look in detail at http://www.ietf.org/rfc/rfc2459.txt
+ *
+ * Create a self-signed X.509 Certificate
+ * @param subjectDN the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
+ * @param subjectKey the public key for the subject
+ * @param days how many days from now the Certificate is valid for
+ * @param webId a WebID to place in the Subject Alternative Name field of the Cert to be generated
+ */
+ def generate(
+ subjectDN: String,
+ subjectKey: RSAPublicKey,
+ days: Int,
+ webId: URL): X509Certificate = { //todo: the algorithm should be deduced from private key in part
+
+ var info = new X509CertInfo
+ val from = new Date(System.currentTimeMillis()-10*1000*60) //start 10 minutes ago, to avoid network trouble
+ val to = new Date(from.getTime + days*24*60*60*1000)
+ val interval = new CertificateValidity(from, to)
+ val serialNumber = new BigInteger(64, new SecureRandom)
+ val subjectXN = new X500Name(subjectDN)
+ val issuerXN = new X500Name(signingCert.getSubjectDN.toString)
+
+ info.set(X509CertInfo.VALIDITY, interval)
+ info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(serialNumber))
+ info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(subjectXN))
+ info.set(X509CertInfo.ISSUER, new CertificateIssuerName(issuerXN))
+ info.set(X509CertInfo.KEY, new CertificateX509Key(subjectKey))
+ info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3))
+
+ //
+ //extensions
+ //
+ val extensions = new CertificateExtensions
+
+ val san =
+ new SubjectAlternativeNameExtension(
+ true,
+ new GeneralNames().add(
+ new GeneralName(new URIName(webId.toExternalForm))))
+
+ extensions.set(san.getName, san)
+
+ val basicCstrExt = new BasicConstraintsExtension(false,1)
+ extensions.set(basicCstrExt.getName,basicCstrExt)
+
+ {
+ import KeyUsageExtension._
+ val keyUsage = new KeyUsageExtension
+ val usages =
+ List(DIGITAL_SIGNATURE, NON_REPUDIATION, KEY_ENCIPHERMENT, KEY_AGREEMENT)
+ usages foreach { usage => keyUsage.set(usage, true) }
+ extensions.set(keyUsage.getName,keyUsage)
+ }
+
+ {
+ import NetscapeCertTypeExtension._
+ val netscapeExt = new NetscapeCertTypeExtension
+ List(SSL_CLIENT, S_MIME) foreach { ext => netscapeExt.set(ext, true) }
+ extensions.set(
+ netscapeExt.getName,
+ new NetscapeCertTypeExtension(false, netscapeExt.getExtensionValue().clone))
+ }
+
+ val subjectKeyExt =
+ new SubjectKeyIdentifierExtension(new KeyIdentifier(subjectKey).getIdentifier)
+
+ extensions.set(subjectKeyExt.getName, subjectKeyExt)
+
+ info.set(X509CertInfo.EXTENSIONS, extensions)
+
+ val algo = signingCert.getPublicKey.getAlgorithm match {
+ case "DSA" => new AlgorithmId(AlgorithmId.sha1WithDSA_oid )
+ case "RSA" => new AlgorithmId(AlgorithmId.sha1WithRSAEncryption_oid)
+ case _ => sys.error("Don't know how to sign with this type of key")
+ }
+
+ info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo))
+
+ // Sign the cert to identify the algorithm that's used.
+ val tmpCert = new X509CertImpl(info)
+ tmpCert.sign(signingKey, algo.getName)
+
+ //update the algorithm and re-sign
+ val sigAlgo = tmpCert.get(X509CertImpl.SIG_ALG).asInstanceOf[AlgorithmId]
+ info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, sigAlgo)
+ val cert = new X509CertImpl(info)
+ cert.sign(signingKey,algo.getName)
+
+ cert.verify(signingCert.getPublicKey)
+ return cert
+ }
+
+ val clonesig : Signature = sig
+
+ def sig: Signature = {
+ if (clonesig != null && clonesig.isInstanceOf[Cloneable]) clonesig.clone().asInstanceOf[Signature]
+ else {
+ val signature = Signature.getInstance(sigAlg)
+ signature.initSign(signingKey)
+ signature
+ }
+ }
+
+ def sign(string: String): Array[Byte] = {
+ val signature = sig
+ signature.update(string.getBytes("UTF-8"))
+ signature.sign
+ }
+
+}
+
+
+object Certs {
+
+ def unapplySeq[T](r: HttpRequest[T])(implicit m: Manifest[T], fetch: Boolean=true): Option[IndexedSeq[Certificate]] = {
+ if (m <:< manifest[HttpServletRequest])
+ unapplyServletRequest(r.asInstanceOf[HttpRequest[HttpServletRequest]])
+ else if (m <:< manifest[ReceivedMessage])
+ unapplyReceivedMessage(r.asInstanceOf[HttpRequest[ReceivedMessage]],fetch)
+ else
+ None //todo: should throw an exception here?
+ }
+
+
+ //todo: should perhaps pass back error messages, which they could in the case of netty
+
+ private def unapplyServletRequest[T <: HttpServletRequest](r: HttpRequest[T]): Option[IndexedSeq[Certificate]] =
+ r.underlying.getAttribute("javax.servlet.request.X509Certificate") match {
+ case certs: Array[Certificate] => Some(certs)
+ case _ => None
+ }
+
+ private def unapplyReceivedMessage[T <: ReceivedMessage](r: HttpRequest[T], fetch: Boolean): Option[IndexedSeq[Certificate]] = {
+
+ import org.jboss.netty.handler.ssl.SslHandler
+
+ val sslh = r.underlying.context.getPipeline.get(classOf[SslHandler])
+
+ trySome(sslh.getEngine.getSession.getPeerCertificates.toIndexedSeq) orElse {
+ //it seems that the jvm does not keep a very good cache of remote certificates in a session. But
+ //see http://stackoverflow.com/questions/8731157/netty-https-tls-session-duration-why-is-renegotiation-needed
+ if (!fetch) None
+ else {
+ sslh.setEnableRenegotiation(true) // todo: does this have to be done on every request?
+ r match {
+ case UserAgent(agent) if needAuth(agent) => sslh.getEngine.setNeedClientAuth(true)
+ case _ => sslh.getEngine.setWantClientAuth(true)
+ }
+ val future = sslh.handshake()
+ future.await(30000) //that's certainly way too long.
+ if (future.isDone && future.isSuccess)
+ trySome(sslh.getEngine.getSession.getPeerCertificates.toIndexedSeq)
+ else
+ None
+ }
+ }
+
+ }
+
+ /**
+ * Some agents do not send client certificates unless required. This is a problem for them, as it ends up breaking the
+ * connection for those agents if the client does not have a certificate...
+ *
+ * It would be useful if this could be updated by server from time to time from a file on the internet,
+ * so that changes to browsers could update server behavior
+ *
+ */
+ def needAuth(agent: String): Boolean =
+ (agent contains "Java") | (agent contains "AppleWebKit") | (agent contains "Opera") | (agent contains "libcurl")
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/auth/X509Claim.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+
+
+import org.slf4j.LoggerFactory
+import java.security.cert.X509Certificate
+import javax.security.auth.Refreshable
+import collection.JavaConversions._
+import unfiltered.request.HttpRequest
+import java.security.interfaces.RSAPublicKey
+import collection.immutable.List
+import java.util.concurrent.TimeUnit
+import org.w3.readwriteweb.util.trySome
+import java.util.Date
+import com.weiglewilczek.slf4s.Logging
+import com.google.common.cache.{LoadingCache, CacheLoader, CacheBuilder, Cache}
+
+/**
+ * @author hjs
+ * @created: 13/10/2011
+ */
+
+object X509Claim {
+ final val logger = LoggerFactory.getLogger(classOf[X509Claim])
+ implicit val fetch = true //fetch the certificate if we don't have it
+
+// this is cool because it is not in danger of running out of memory but it makes it impossible to create the claim
+// with an implicit GraphCache...
+ val idCache: LoadingCache[X509Certificate, X509Claim] =
+ CacheBuilder.newBuilder()
+ .expireAfterWrite(30, TimeUnit.MINUTES)
+ .build(new CacheLoader[X509Certificate, X509Claim] {
+ def load(x509: X509Certificate) = new X509Claim(x509)
+ })
+
+ def unapply[T](r: HttpRequest[T])(implicit m: Manifest[T]): Option[X509Claim] = r match {
+ case Certs(c1: X509Certificate, _*) => trySome(idCache.get(c1))
+ case _ => None
+ }
+
+
+ /**
+ * Extracts the URIs in the subject alternative name extension of an X.509
+ * certificate
+ *
+ * @param cert X.509 certificate from which to extract the URIs.
+ * @return Iterator of URIs as strings found in the subjectAltName extension.
+ */
+ def getClaimedWebIds(cert: X509Certificate): List[String] =
+ if (cert == null) Nil
+ else cert.getSubjectAlternativeNames().toList match {
+ case coll if (coll != null) => {
+ for {
+ sanPair <- coll if (sanPair.get(0) == 6)
+ } yield sanPair(1).asInstanceOf[String].trim
+ }
+ case _ => Nil
+ }
+
+}
+
+object ExistingClaim {
+ implicit val fetch = false //don't fetch the certificate if we don't have it -- ie, don't force the fetching of it
+
+ def unapply[T](r: HttpRequest[T])(implicit m: Manifest[T]): Option[X509Claim] = r match {
+ case Certs(c1: X509Certificate, _*) => trySome(X509Claim.idCache.get(c1))
+ case _ => None
+ }
+
+}
+
+object XClaim {
+ //warning: it turns out that one nearly never recuperates the client certificate
+ //see http://stackoverflow.com/questions/8731157/netty-https-tls-session-duration-why-is-renegotiation-needed
+ implicit val fetch = false
+ def unapply[T](r: HttpRequest[T])(implicit m: Manifest[T]): Option[XClaim] = r match {
+ case Certs(c1: X509Certificate, _*) => trySome(X509Claim.idCache.get(c1))
+ case _ => Some(NoClaim)
+ }
+}
+
+
+
+/**
+ * This looks like something that could be abstracted into type perhaps XClaim[X509Certificate,WebIDClaim]
+ */
+sealed trait XClaim {
+ def cert: X509Certificate
+ def valid: Boolean
+ def claims: List[WebIDClaim]
+ def verified: List[WebID]
+}
+
+/**
+ * An X509 Claim maintains information about the proofs associated with claims
+ * found in an X509 Certificate. It is the type of object that can be passed
+ * into the public credentials part of a Subject node
+ *
+ * todo: think of what this would look like for a chain of certificates
+ *
+ * @author bblfish
+ * @created: 30/03/2011
+ */
+// can't be a case class as it then creates object which clashes with defined one
+class X509Claim(val cert: X509Certificate) extends Refreshable with XClaim with Logging {
+
+ import X509Claim._
+ val claimReceivedDate = new Date()
+ lazy val tooLate = claimReceivedDate.after(cert.getNotAfter())
+ lazy val tooEarly = claimReceivedDate.before(cert.getNotBefore())
+ logger.debug("X509 Claim for certificate with DN="+cert.getSubjectDN)
+
+ lazy val claims: List[WebIDClaim] = getClaimedWebIds(cert) map { webid =>
+ new WebIDClaim(webid, cert.getPublicKey.asInstanceOf[RSAPublicKey])
+ }
+
+ def verified: List[WebID] = claims.flatMap(_.verify.toOption)
+
+ //note could also implement Destroyable
+ //
+ //http://download.oracle.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html#Credentials
+ //
+ //if updating validity periods can also take into account the WebID reference, then it is possible
+ //that a refresh could have as consequence to do a fetch on the WebID profile
+ //note: one could also take the validity period to be dependent on the validity of the profile representation
+ //in which case updating the validity period would make more sense.
+
+ override def refresh() = ()
+
+ /* The certificate is currently within the valid time zone */
+ override def isCurrent(): Boolean = ! (tooLate || tooEarly)
+
+ protected def canEqual(other: Any) = other.isInstanceOf[X509Claim]
+
+ override def equals(other: Any): Boolean = other match {
+ case that: X509Claim => (that eq this) || (that.canEqual(this) && cert == that.cert)
+ case _ => false
+ }
+
+ override lazy val hashCode: Int =
+ 41 * (41 + (if (cert != null) cert.hashCode else 0))
+
+ def valid = isCurrent()
+}
+
+/**
+ * A bit like a None for X509Claims
+ */
+case object NoClaim extends XClaim {
+ override def cert = throw new NoSuchElementException("None.get")
+
+ def valid = false
+
+ def claims = List.empty
+
+ def verified = List.empty
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/auth/X509view.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import unfiltered.Cycle
+import xml.{Elem, XML}
+import unfiltered.request.Path
+import org.fusesource.scalate.scuery.{Transform, Transformer}
+import unfiltered.scalate.Scalate
+import java.text.DateFormat
+import java.util.Date
+import unfiltered.response.{CacheControl, Expires, Ok, Html}
+
+/**
+ * This plan just described the X509 WebID authentication information.
+ * It works independently of the underlying Cycle.Intent implementations of Request and Response,
+ * so it can work with servlet filters just as well as with netty.
+ *
+ * This is a simple version. A future version will show EARL output, and so be useful for debugging the endpoint.
+ *
+ * @author hjs
+ * @created: 13/10/2011
+ */
+
+trait X509view[Req,Res] {
+ implicit def manif: Manifest[Req]
+
+ val fileDir = "/template/"
+
+ lazy val webidTst: Elem = XML.load(this.getClass.getResourceAsStream(fileDir+"WebId.xhtml"))
+ lazy val noX509: Elem = XML.load(this.getClass.getResourceAsStream(fileDir+"NoWebId.xhtml"))
+
+ def intent : Cycle.Intent[Req,Res] = {
+ case req @ Path("/test/WebId") => req match {
+ case X509Claim(claim) => Ok ~> Html( new X509Filler(claim).apply(webidTst) ) ~> Expires("0") ~> CacheControl("no-cache")
+ case _ => Ok ~> Html (new NoX509().apply(noX509)) ~> Expires("0") ~> CacheControl("no-cache")
+ }
+ case req @ Path("/test/WebIdAuth2") => Ok ~> Scalate(req, "hello.ssp")
+ }
+
+}
+
+class NoX509() extends Transformer {
+ $(".date").contents = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG).format(new Date)
+}
+
+class X509Filler(x509: X509Claim) extends Transformer {
+ def pretty(res: Outcome) = {
+ res match {
+ case org.w3.readwriteweb.auth.passed => <span class="outcome_passed">passed</span>
+ case org.w3.readwriteweb.auth.failed => <span class="outcome_failed">failed</span>
+ case org.w3.readwriteweb.auth.untested => <span class="outcome_untested">untested</span>
+ }
+ }
+ $(".date").contents = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG).format( x509.claimReceivedDate)
+ $(".cert_test") { node =>
+ val x509Assertion = new Assertion(certOk,x509);
+ val x509Assertions = x509Assertion::x509Assertion.depends
+ val ff = for (ast <- x509Assertions) yield {
+ new Transform(node) {
+ $(".tst_question").contents = ast.test.title
+ $(".tst_txt").contents = ast.test.description
+ $(".tst_res").contents = pretty(ast.result.outcome)
+ $(".tst_res_txt").contents = ast.result.description
+ }.toNodes()
+ }
+ ff.flatten
+ }
+ $(".san_number").contents = if (x509.claims.size == 0) "No" else x509.claims.size.toString
+ $(".san_verified") { node => if (x509.claims.size==0) <span/> else
+ new Transform(node) {
+ $(".san_verified_no").contents = x509.verified.size.toString
+ }.toNodes()
+ }
+
+ $(".webid_test") { node =>
+ val ff = for (idclaim <- x509.claims) yield {
+ val idAsrt = new Assertion(webidClaimTst, idclaim)
+ new Transform(node) {
+ $(".webid").contents = idclaim.san
+ $(".tst_res_txt").contents = idAsrt.result.description
+ $(".tst_res").contents = pretty(idAsrt.result.outcome)
+ $(".webid_cause") { n2 =>
+ val nn = for (a <- idAsrt.depends) yield {
+ new Transform(n2) {
+ $(".cause_question").contents = a.test.title
+ $(".cause_txt").contents = a.test.description
+ $(".cause_res").contents = a.result.outcome.name
+ }.toNodes()
+ }
+ nn.flatten
+ }
+ }.toNodes()
+ }
+ ff.flatten
+ }
+ $(".certificate").contents = x509.cert.toString
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/auth/earl.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import com.hp.hpl.jena.vocabulary.DCTerms
+import java.security.interfaces.RSAPublicKey
+import org.w3.readwriteweb.util.trySome
+import java.lang.ref.WeakReference
+import com.hp.hpl.jena.rdf.model.{Model, Property, ModelFactory}
+import scalaz.{Failure, Success}
+
+/**
+ * Classes for the tests in WebID Authentication.
+ *
+ * The idea is to try to use the earl test cases we are defining at the WebID XG as
+ * a way of collecting tests done to prove the X509Claim and the WebIDClaim.
+ *
+ * These tests are now very close to the way the code is working. So much so that one can get
+ * feeling that perhaps by adding the URIs of these tests directly to the error codes one
+ * could merge a few classes. So perhaps with a bit of tuning a few classes here could just
+ * disappear.
+ *
+ */
+
+
+object Tests {
+ // This is where the earl tests are documented and named
+ val ns = "http://www.w3.org/2005/Incubator/webid/earl/RelyingParty"
+ val skos = "http://www.w3.org/2004/02/skos/core#"
+
+ private var m : WeakReference[Model] = null
+
+ //todo: this model should be a weak pointer
+ def model= {
+ if (m==null || m.get() == null) m = new WeakReference( ModelFactory.createDefaultModel().read(
+ this.getClass.getResourceAsStream("/ontologies/RelyingParty.n3"),
+ ns, "TURTLE" ) )
+ m.get;
+ }
+
+
+}
+
+
+trait Test {
+ val title: String
+ val description: String
+ val note: String
+}
+
+/**
+ * Test with extra information taken from the ontologies
+ */
+abstract class OntTest(val name: String) extends Test {
+ import Tests._
+ implicit def boolToResult(bool: Boolean): Outcome = if (bool) passed else failed
+
+ private def value(p: Property) = trySome(resource.getProperty(p).getLiteral.getLexicalForm) getOrElse "-missing-"
+
+ val title: String = value(DCTerms.title)
+ val description: String = value(DCTerms.description)
+ val note: String = value(model.createProperty(skos,"note"))
+
+ private def resource = model.getResource(ns+"#"+name)
+}
+
+abstract class TestObj[T](name: String) extends OntTest(name) {
+ def apply(subj: T): Result
+ def depends(subj: T): List[Assert] =Nil
+}
+
+/**
+ * tests that we apply only to Exceptions
+ */
+class TestErr(name: String) extends OntTest(name)
+
+//todo: (bblfish:) I get the feeling that one could put the logic into the tests directly.
+// would that make things easier or better?
+
+//
+//The types of tests that we do here
+//
+
+//for X509Claim
+//object certProvided[X509Certificate] extends OntTest("certificateProvided") {
+// def apply(cert: Option[X509Certificate]): Assertion = cert match {
+// case Some(x509) => new Assertion(this,passed,"got certificate") //the subject is the session
+// case None => new Assertion(this,failed,"missing certificate")
+// }
+//}
+
+object certOk extends TestObj[X509Claim]("certificateOk") {
+ val parts = List[TestObj[X509Claim]](certDateOk, certProvidedSan,certPubKeyRecognized)
+
+ def apply(x509: X509Claim): Result = {
+ val deps = depends(x509)
+ val res = deps.forall(_.result.outcome == passed)
+ new Result(if (res) "X509 Certificate Good" else "X509 Certificate had problems",
+ res, deps)
+ }
+ override def depends(x509: X509Claim): List[Assert] = parts.map(test=>new Assertion[X509Claim](test,x509))
+}
+
+object certProvidedSan extends TestObj[X509Claim]("certificateProvidedSAN") {
+ def apply(x509: X509Claim) = new Result(" There are "+x509.claims.size+" SANs in the certificate",
+ x509.claims.size >0)
+
+}
+
+object certDateOk extends TestObj[X509Claim]("certificateDateOk") {
+ def apply(x509: X509Claim) =
+ new Result("the x509certificate " + (
+ if (x509.tooEarly) "is not yet valid "
+ else if (x509.tooLate) " passed its validity date "
+ else " is valid"),
+ x509.isCurrent)
+
+}
+
+object certPubKeyRecognized extends TestObj[X509Claim]("certificatePubkeyRecognised") {
+ def apply(claim: X509Claim) = {
+ val pk = claim.cert.getPublicKey;
+ new Result("We only support RSA Keys at present. ",pk.isInstanceOf[RSAPublicKey] )
+ }
+}
+
+//for WebIDClaims
+object webidClaimTst extends TestObj[WebIDClaim]("webidClaim") {
+ def apply(webIdclaim: WebIDClaim) : Result =
+ webIdclaim.verify match {
+ case Success(webId) => new Result("WebId successfully verified",passed)
+ case Failure(webIdClaimErr: WebIDVerificationFailure) =>
+ new Result("keys in profile don't match key in certificate for "+webIdClaimErr.subject.san,failed)
+ case Failure(e) => new Result("WebID verification failed",failed,cause=List(new AssertionErr(e)))
+ }
+
+ override def depends(webIdclaim: WebIDClaim): List[Assert] =
+ webIdclaim.verify match {
+ case Failure(e) if !e.isInstanceOf[WebIDVerificationFailure] => new AssertionErr(e)::Nil
+ case _ => Nil
+ }
+}
+
+
+
+object profileGetTst extends TestErr("profileGet")
+object profileParseTst extends TestErr("profileWellFormed")
+object sanOk extends TestErr("sanOK")
+
+//object profileOkTst extends OntTest("profileOk") {
+// def test(err: ProfileError): Assertion = new Assertion(this,err)::err match {
+// case getError : ProfileGetError => profileGetTst.test(getError)
+// case ProfileParseError(parseError: Fail) => new Assertion(profileParseTst,parseError)
+// }
+//}
+//object profileWellFormedKeyTst extends OntTest("profileWellFormedPubkey")
+
+object Assertion {
+ def name(fail: WebIDClaimFailure): Test = {
+ fail match {
+ case e: UnsupportedProtocol => sanOk
+ case e: URISyntaxError => sanOk
+ case e: ProfileGetError => profileGetTst
+ case e: ProfileParseError => profileParseTst
+ case e: UnsupportedKeyType => certPubKeyRecognized
+ }
+ }
+}
+
+trait Assert {
+ val subject: AnyRef
+ val test: Test
+ val result: Result
+}
+
+class Assertion[T<:AnyRef]( val test: TestObj[T], val subject: T ) extends Assert {
+ override val result: Result = test(subject)
+ val depends: List[Assert] = test.depends(subject)
+}
+
+class AssertionErr(val fail: WebIDClaimFailure) extends Assert {
+ import Assertion.name
+ val subject = fail.subject
+ val test = name(fail)
+ val result: Result = new Result(fail.msg,failed)
+}
+
+class Result (val description: String,
+ val outcome: Outcome,
+ val cause: List[Assert] = Nil)
+
+
+
+sealed class Outcome(val name: String) {
+ val earl = "http://www.w3.org/ns/earl#"
+ val id = earl+name
+}
+
+object untested extends Outcome("untested")
+object passed extends Outcome("passed")
+object failed extends Outcome("failed")
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/cache/WebFetcher.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2012 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3c.readwriteweb.cache
+
+
+import com.ning.http.client.AsyncHandler.STATE
+
+import java.net.URL
+import org.w3.readwriteweb.Lang
+import com.weiglewilczek.slf4s.Logging
+import com.hp.hpl.jena.rdf.model.{ModelFactory, Model}
+import scalaz.Zero
+import java.util.Collections
+import com.fasterxml.aalto.stax.InputFactoryImpl
+import com.fasterxml.aalto.{AsyncXMLStreamReader, AsyncInputFeeder}
+import com.hp.hpl.jena.rdf.arp.SAX2Model
+import patch.AsyncJenaParser
+import com.ning.http.client._
+
+
+/**
+ * Asynchronous URL fetcher.
+ *
+ * see http://www.cowtowncoder.com/blog/archives/2011/03/entry_451.html
+ * for background on fasterxml's async parser
+ *
+ * @author bblfish
+ * @created 27/01/2012
+ */
+
+class URLFetcher(url: URL) extends AsyncHandler[Model]() with Logging {
+ import scala.collection.JavaConverters._
+
+// var reader: RDFReader = _
+// var base: String = _
+
+ var status: HttpResponseStatus = _
+ var base: String = _
+ var asyncParser: AsyncJenaParser = _
+
+ lazy val asyncReader: AsyncXMLStreamReader = new InputFactoryImpl().createAsyncXMLStreamReader();
+ lazy val feeder: AsyncInputFeeder = asyncReader.getInputFeeder();
+ lazy val model: Model = ModelFactory.createDefaultModel()
+
+ def onThrowable(t: Throwable) {
+ logger.error(t.getMessage)
+ }
+
+ def onBodyPartReceived(bodyPart: HttpResponseBodyPart) = {
+ val bytes = bodyPart.getBodyPartBytes
+ if (feeder.needMoreInput()) {
+ feeder.feedInput(bytes,0,bytes.length)
+ } else logger.warn("feeder does not want more input - parsing did not consume all")
+
+ //should one check if asyncParser needs more input?
+ asyncParser.parse()
+
+ STATE.CONTINUE
+ }
+
+ def onStatusReceived(responseStatus: HttpResponseStatus) = {
+ status = responseStatus
+ STATE.CONTINUE
+ }
+
+ def onHeadersReceived(headers: HttpResponseHeaders) = {
+ if (status.getStatusCode < 200 && status.getStatusCode > 204) {
+ STATE.CONTINUE
+ } else {
+ val typeHdr = nullSquisher( headers.getHeaders.get("Content-Type") ).asScala
+ logger.info("Content-Types ➤ " + typeHdr.mkString(" ➤ "))
+ val mime = typeHdr.flatMap(mime => Lang(mime.split(";")(0))).headOption
+
+ val locHdr = nullSquisher ( headers.getHeaders.get("Content-Location")).asScala
+ logger.info("Content-Location ➤ " + locHdr.mkString(" ➤ "))
+ val location = locHdr.headOption match {
+ case Some(loc) => new URL(url, loc)
+ case None => new URL(url.getProtocol, url.getAuthority, url.getPort, url.getPath)
+ }
+ base = location.toString
+
+ // currently we assume rdf/xml
+ // val lang = mime getOrElse Lang.default
+ // reader = model.getReader(lang.jenaLang)
+
+ asyncParser = new AsyncJenaParser(SAX2Model.create(base, model),asyncReader)
+
+ STATE.CONTINUE
+ }
+ }
+
+ def onCompleted() = {
+ feeder.endOfInput()
+ asyncReader.close()
+ model
+ }
+
+
+ def nullSquisher[T](body: => T)(implicit z: Zero[T]): T =
+ try {
+ val res = body;
+ if (res == null) z.zero else res
+ } catch {
+ case e => {
+ logger.warn("squished an exception to null",e)
+ z.zero
+ }
+ }
+ implicit def JavaListZero[A]: Zero[java.util.List[A]] = new Zero[java.util.List[A]] { val zero = Collections.emptyList[A]() }
+}
+
+/**
+ * test object to run from the scala command line
+ */
+object ModelCache {
+ lazy val url = "http://bblfish.net/people/henry/card.rdf"
+ //for debugging
+ lazy val config = new AsyncHttpClientConfig.Builder().
+ setConnectionTimeoutInMs(60000*15).
+ setIdleConnectionTimeoutInMs(60000*15).
+ setRequestTimeoutInMs(60000*15).
+ setWebSocketIdleTimeoutInMs(60000*15).build()
+ lazy val client = new AsyncHttpClient(config)
+
+ def response(url: String) = client.prepareGet(url).
+ setFollowRedirects(true).
+ execute(new URLFetcher(new URL(url)))
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/netty/ReadWriteWebNetty.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.netty
+
+
+import _root_.auth.WebIDSrvc
+import org.clapper.argot.ArgotUsageException
+import scala.Console._
+import org.w3.readwriteweb.auth.{X509view, RDFAuthZ}
+import org.w3.readwriteweb._
+import org.jboss.netty.handler.codec.http.HttpResponse
+import unfiltered.request.Path
+import java.io.{InputStream, OutputStream}
+import unfiltered.response._
+import unfiltered.netty._
+import collection.immutable.List
+import scala.None
+
+/**
+ * ReadWrite Web for Netty server, allowing TLS renegotiation
+ *
+ * @author hjs
+ * @created: 21/10/2011
+ */
+
+object ReadWriteWebNetty extends ReadWriteWebArgs {
+
+ // regular Java main
+ def main(args: Array[String]) {
+
+ try {
+ parser.parse(args)
+ postParse
+ } catch {
+ case e: ArgotUsageException => err.println(e.message); sys.exit(1)
+ }
+
+ val filesystem =
+ new Filesystem(
+ rootDirectory.value.get,
+ baseURL.value.get,
+ lang=rdfLanguage.value getOrElse RDFXML)(mode.value getOrElse ResourcesDontExistByDefault)
+
+ val rww = new cycle.Plan with cycle.ThreadPool with ServerErrorResponse with ReadWriteWeb[ReceivedMessage,HttpResponse]{
+ val rm = filesystem
+ def manif = manifest[ReceivedMessage]
+ override val authz = new RDFAuthZ[ReceivedMessage,HttpResponse](filesystem)
+ }
+
+ val echo = new cycle.Plan with cycle.ThreadPool with ServerErrorResponse with NettyEchoPlan
+
+ val domain = host.value.getOrElse("0.0.0.0")
+ //only one of the following two servers can be started at one time
+ //having two would require a lot more care with issues of overwriting
+ httpsPort.value.map {
+ port => new KeyAuth_Https(port).
+ plan(publicStatic).
+ plan( echo ).
+ plan( x509v ).
+ plan( webidp ).
+ plan( rww ).run()
+ }
+
+ httpPort.value.map {
+ port => Http(httpPort.value.get,domain).
+ plan(publicStatic).
+ plan( echo ).
+ plan( rww ).run()
+ }
+
+ }
+
+
+
+ trait StaticFiles extends PartialFunction[String, ResponseFunction[Any]] {
+ /* override this if the local path is somehow different from the url path */
+ def toLocal(webpath: String): String = webpath
+ val extension = "([^\\.]*?)$".r
+ val extList: List[String] = List("css", "png")
+
+ private def toString(in: InputStream): String = {
+ val source = scala.io.Source.fromInputStream(in)
+ val lines = source.mkString
+ source.close()
+ lines
+ }
+
+ def isDefinedAt(path: String): Boolean = try {
+ val in = classOf[StaticFiles].getResourceAsStream(toLocal(path))
+ (in != null) & (extension.findFirstIn(path).exists(extList contains _))
+ } catch {
+ case _ => false
+ }
+
+ def apply(path: String): ResponseFunction[Any] = {
+ try {
+ val in = classOf[StaticFiles].getResourceAsStream(toLocal(path))
+ extension.findFirstIn(path).getOrElse("css") match {
+ case "css" => Ok ~> ResponseString(toString(in)) ~> CssContent
+ case "js" => Ok ~> ResponseString(toString(in)) ~> JsContent
+ case "png" => Ok ~> ResponseBin(in) ~> ContentType("image/png")
+ }
+ } catch {
+ case _ => NotFound
+ }
+ }
+ }
+
+ object publicStatic extends cycle.Plan with cycle.ThreadPool with ServerErrorResponse with StaticFiles {
+ val initialPath= "/public"
+
+ def intent = {
+ case Path(path) if path.startsWith(initialPath) => apply(path)
+ }
+ }
+
+ object x509v extends cycle.Plan with cycle.ThreadPool with ServerErrorResponse with X509view[ReceivedMessage,HttpResponse] {
+ def manif = manifest[ReceivedMessage]
+ }
+
+ object webidp extends cycle.Plan with cycle.ThreadPool with ServerErrorResponse with WebIDSrvc[ReceivedMessage, HttpResponse] {
+ def manif = manifest[ReceivedMessage]
+ val signer = ReadWriteWebNetty.signer
+ }
+
+ /**
+ * set environmental variables, but adapt them for the underlying server
+ * (a silly hack because jetty and netty in unfiltered use different TLS security
+ * properties, and I don't want to dig through each library to set that right just now)
+ * @param name
+ * @param value
+ */
+ def setPropHack(name: String, value: String) {
+ System.setProperty("netty."+name,value)
+ }
+}
+
+
+case class ResponseBin(bis: InputStream) extends ResponseStreamer {
+ override def stream(out: OutputStream) {
+ val buf = new Array[Byte](4096)
+ Iterator continually bis.read(buf) takeWhile (-1 !=) foreach { bytesRead =>
+ out.write(buf,0,bytesRead)
+ }
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/netty/server.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.netty
+
+
+import unfiltered.netty._
+import java.lang.String
+import org.jboss.netty.channel.{ChannelPipelineFactory, ChannelHandler}
+import java.security.cert.X509Certificate
+import javax.net.ssl.X509TrustManager
+
+trait NormalPlan extends cycle.Plan with cycle.ThreadPool with ServerErrorResponse
+
+
+class KeyAuth_Https(override val port: Int) extends Https(port) with KeyAuth_Ssl
+
+
+/**
+ * a class that trusts all ssl certificates - as long as the tls handshake crypto works of course.
+ * Ie: we don't care about who signed the certificate. All we know when the certificate is received
+ * is that the client knew the private key of the given public key. It is the job of other layers,
+ * to follow through on claims made in the certificate.
+ */
+trait KeyAuth_Ssl extends Ssl {
+
+ import java.security.SecureRandom
+ import javax.net.ssl.{SSLContext, TrustManager}
+
+ val nullArray = Array[X509Certificate]()
+
+ val trustManagers = Array[TrustManager](new X509TrustManager {
+ def getAcceptedIssuers = nullArray
+
+ def checkClientTrusted(p1: Array[X509Certificate], p2: String) {}
+
+ def checkServerTrusted(p1: Array[X509Certificate], p2: String) {}
+ })
+
+
+ override def initSslContext(ctx: SSLContext) = ctx.init(keyManagers, trustManagers, new SecureRandom)
+
+
+}
+
+//
+// Below is code mostly taken from unfiltered.netty, and so available under their licence. I am waiting
+// for them to make it easier to extend the netty.Https classes so that this code would not longer be
+// needed
+//
+
+object Https {
+
+ /** bind to a the loopback interface only */
+ def local(port: Int): Https =
+ new Https(port, "127.0.0.1")
+
+ /** bind to any available port on the loopback interface */
+ def anylocal = local(unfiltered.util.Port.any)
+}
+
+
+/** Http + Ssl implementation of the Server trait. */
+class Https(val port: Int,
+ val host: String,
+ val handlers: List[() => ChannelHandler],
+ val beforeStopBlock: () => Unit) extends HttpServer with KeyAuth_Ssl { self =>
+
+ def this(port: Int, host: String) = this(port, host, Nil, () => ())
+
+ def this(port: Int) = this(port, "0.0.0.0")
+
+ def pipelineFactory: ChannelPipelineFactory =
+ new SecureServerPipelineFactory(channels, handlers, this)
+
+ type ServerBuilder = Https
+ def handler(h: => ChannelHandler) = makePlan(h)
+
+ def makePlan(h: => ChannelHandler) =
+ new Https(port, host, { () => h } :: handlers, beforeStopBlock)
+
+
+ def beforeStop(block: => Unit) = new Https(port, host, handlers, { () => beforeStopBlock(); block })
+
+}
--- a/src/main/scala/plan.scala Thu Oct 13 13:34:16 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2011 Henry Story (bblfish.net)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Henry Story. The name of bblfish.net may not be used to endorse
- * or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-package org.w3.readwriteweb
-
-import org.w3.readwriteweb.util._
-
-import unfiltered.request._
-import unfiltered.response._
-
-import scala.io.Source
-import java.net.URL
-
-import org.slf4j.{Logger, LoggerFactory}
-
-import com.hp.hpl.jena.rdf.model.Model
-import com.hp.hpl.jena.query.{Query, QueryExecution, QueryExecutionFactory}
-import com.hp.hpl.jena.update.UpdateAction
-import Query.{QueryTypeSelect => SELECT,
- QueryTypeAsk => ASK,
- QueryTypeConstruct => CONSTRUCT,
- QueryTypeDescribe => DESCRIBE}
-
-import scalaz._
-import Scalaz._
-
-class ReadWriteWeb(rm: ResourceManager) {
-
- val logger: Logger = LoggerFactory.getLogger(this.getClass)
-
- def isHTML(accepts: List[String]): Boolean = {
- val accept = accepts.headOption
- accept == Some("text/html") || accept == Some("application/xhtml+xml")
- }
-
- /** I believe some documentation is needed here, as many different tricks
- * are used to make this code easy to read and still type-safe
- *
- * Planify.apply takes an Intent, which is defined in Cycle by
- * type Intent [-A, -B] = PartialFunction[HttpRequest[A], ResponseFunction[B]]
- * the corresponding syntax is: case ... => ...
- *
- * this code makes use of ScalaZ Validation. For example of how to use it, see
- * http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html
- *
- * the Resource abstraction returns Validation[Throwable, ?something]
- * we use the for monadic constructs (although it's *not* a monad).
- * Everything construct are mapped to Validation[ResponseFunction, ResponseFuntion],
- * the left value always denoting the failure. Hence, the rest of the for-construct
- * is not evaluated, but let the reader of the code understand clearly what's happening.
- *
- * This mapping is made possible with the failMap method. I couldn't find an equivalent
- * in the ScalaZ API so I made my own through an implicit.
- *
- * At last, Validation[ResponseFunction, ResponseFuntion] is exposed as a ResponseFunction
- * through another implicit conversion. It saves us the call to the Validation.lift() method
- */
- val plan = unfiltered.filter.Planify {
- case req @ Path(path) if path startsWith rm.basePath => {
- val baseURI = req.underlying.getRequestURL.toString
- val r: Resource = rm.resource(new URL(baseURI))
- req match {
- case GET(_) & Accept(accepts) if isHTML(accepts) => {
- val source = Source.fromFile("src/main/resources/skin.html")("UTF-8")
- val body = source.getLines.mkString("\n")
- Ok ~> ViaSPARQL ~> ContentType("text/html") ~> ResponseString(body)
- }
- case GET(_) | HEAD(_) =>
- for {
- model <- r.get() failMap { x => NotFound }
- encoding = RDFEncoding(req)
- } yield {
- req match {
- case GET(_) => Ok ~> ViaSPARQL ~> ContentType(encoding.toContentType) ~> ResponseModel(model, baseURI, encoding)
- case HEAD(_) => Ok ~> ViaSPARQL ~> ContentType(encoding.toContentType)
- }
- }
- case PUT(_) =>
- for {
- bodyModel <- modelFromInputStream(Body.stream(req), baseURI) failMap { t => BadRequest ~> ResponseString(t.getStackTraceString) }
- _ <- r.save(bodyModel) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString) }
- } yield Created
- case POST(_) => {
- Post.parse(Body.stream(req), baseURI) match {
- case PostUnknown => {
- logger.info("Couldn't parse the request")
- BadRequest ~> ResponseString("You MUST provide valid content for either: SPARQL UPDATE, SPARQL Query, RDF/XML, TURTLE")
- }
- case PostUpdate(update) => {
- logger.info("SPARQL UPDATE:\n" + update.toString())
- for {
- model <- r.get() failMap { t => NotFound }
- // TODO: we should handle an error here
- _ = UpdateAction.execute(update, model)
- _ <- r.save(model) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString)}
- } yield Ok
- }
- case PostRDF(diffModel) => {
- logger.info("RDF content:\n" + diffModel.toString())
- for {
- model <- r.get() failMap { t => NotFound }
- // TODO: we should handle an error here
- _ = model.add(diffModel)
- _ <- r.save(model) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString)}
- } yield Ok
- }
- case PostQuery(query) => {
- logger.info("SPARQL Query:\n" + query.toString())
- lazy val encoding = RDFEncoding(req)
- for {
- model <- r.get() failMap { t => NotFound }
- } yield {
- val qe: QueryExecution = QueryExecutionFactory.create(query, model)
- query.getQueryType match {
- case SELECT =>
- Ok ~> ContentType("application/sparql-results+xml") ~> ResponseResultSet(qe.execSelect())
- case ASK =>
- Ok ~> ContentType("application/sparql-results+xml") ~> ResponseResultSet(qe.execAsk())
- case CONSTRUCT => {
- val result: Model = qe.execConstruct()
- Ok ~> ContentType(encoding.toContentType) ~> ResponseModel(model, baseURI, encoding)
- }
- case DESCRIBE => {
- val result: Model = qe.execDescribe()
- Ok ~> ContentType(encoding.toContentType) ~> ResponseModel(model, baseURI, encoding)
- }
- }
- }
- }
- }
- }
- case _ => MethodNotAllowed ~> Allow("GET", "PUT", "POST")
- }
- }
-
- }
-
-}
\ No newline at end of file
--- a/src/main/scala/rdfLanguage.scala Thu Oct 13 13:34:16 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-package org.w3.readwriteweb
-
-import unfiltered.request._
-
-sealed trait RDFEncoding {
- def toContentType:String
-}
-
-case object RDFXML extends RDFEncoding {
- def toContentType = "application/rdf+xml"
-}
-
-case object TURTLE extends RDFEncoding {
- def toContentType = "text/turtle"
-}
-
-object RDFEncoding {
-
- def apply(contentType:String):RDFEncoding =
- contentType match {
- case "text/turtle" => TURTLE
- case "application/rdf+xml" => RDFXML
- case _ => RDFXML
- }
-
- def jena(encoding: RDFEncoding) = encoding match {
- case RDFXML => "RDF/XML-ABBREV"
- case TURTLE => "TURTLE"
- case _ => "RDF/XML-ABBREV" //don't like this default
- }
-
- def apply(req:HttpRequest[_]):RDFEncoding = {
- val contentType = Accept(req).headOption
- contentType map { RDFEncoding(_) } getOrElse RDFXML
- }
-
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/sommer/ResourceReader.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package sommer
+
+import com.hp.hpl.jena.vocabulary.RDF
+import com.hp.hpl.jena.sparql.vocabulary.FOAF
+import java.lang.String
+import org.w3.readwriteweb.{Resource, GraphCache}
+import scalaz.Validation
+import java.net.URL
+import collection._
+import collection.JavaConverters._
+import com.hp.hpl.jena.rdf.model.{Model, ResourceFactory, Resource => JResource}
+import java.security.cert.X509Certificate
+
+
+/**
+ * Some initial ideas on mappers between rdf and scala classes
+ * exploring ideas from
+ * http://dl.dropbox.com/u/7810909/docs/reader-monad/chunk-html/index.html
+ *
+ * @author Henry Story
+ */
+
+
+/**
+ * Resource readers are Monads
+ * These function directly on types given by resources specified by URIs
+ * But the map from resource to validation, makes things a bit heavy.
+ */
+case class ResourceReader[A](extract: Resource => Validation[scala.Throwable,A]) {
+ def map[B](g: A => B) = ResourceReader(r => extract(r).map(g(_)))
+ def flatMap[B](g: A => ResourceReader[B]): ResourceReader[B] = ResourceReader(r => extract(r).map(g(_)).flatMap(_.extract(r)))
+}
+
+trait Agent {
+ def name: String
+ def foaf(attr: String): Iterator[AnyRef] = Iterator.empty
+ def depictions: Iterator[JResource] = Iterator.empty
+}
+
+object CertAgent {
+ val CNregex = "cn=(.*?),".r
+}
+
+/**
+ *Information about an agent gleaned from the certificate
+ *(One could generalise this by having a function from certificates to graphs)
+ **/
+class CertAgent(dn : String) extends Agent {
+ val name = CertAgent.CNregex.findFirstMatchIn(dn).map(_.group(1)).getOrElse("(unnamed)")
+
+ override def foaf(attr: String) = if (attr == "name") Iterator(name) else Iterator.empty
+
+}
+
+case class Person(name: String)
+
+
+
+case class IdPerson(id: JResource) extends Agent {
+
+
+ import Extractors.toProperty
+ // a couple of useful methods for foaf relations. One could add a few others for other vocabs
+ override def foaf(attr: String) = id.listProperties(toProperty(FOAF.NS+attr)).asScala.map(_.getObject)
+
+ //very very simple implementation, not taking account of first/last name, languages etc...
+ override def name = {
+ foaf("name").mkString(" ")
+ }
+
+ override def depictions = foaf("depiction").collect{case n if n.isURIResource => n.asResource()}
+
+}
+
+object ANONYMOUS extends Agent {
+ val pix = ResourceFactory.createResource("http://massivnews.com/wp-content/uploads/2011/07/Anonymous-000006.jpg")
+ override val name = "_ANONYMOUS_"
+ override def foaf(attr: String) = if (attr == "name") Iterator(name) else Iterator.empty
+ override val depictions = List(pix).iterator
+}
+
+
+object Extractors {
+ type Val[A] = Validation[scala.Throwable,A]
+
+ def findPeople(m: Resource): Validation[scala.Throwable,Set[Person]] = {
+ for (gr<-m.get()) yield {
+ for (st <- gr.listStatements(null,RDF.`type`,FOAF.Person).asScala;
+ val subj = st.getSubject;
+ st2 <- gr.listStatements(subj, FOAF.name,null).asScala
+ ) yield {
+ new Person(st2.getObject.asLiteral().toString)
+ }
+ }.toSet
+ }
+
+ def definedPeople(gr: Model, doc: URL): Iterator[IdPerson] = {
+ for (st <- gr.listStatements(null, RDF.`type`, FOAF.Person).asScala;
+ val subj = st.getSubject;
+ //todo: come up with a better definition of "is defined in"
+ if (subj.isURIResource && subj.toString.split("#")(0) == doc.toString.split("#")(0));
+ st2 <- gr.listStatements(subj, FOAF.name, null).asScala
+ ) yield {
+ new IdPerson(subj)
+ }
+ }
+
+ /**
+ * Argh. Jena does not make a good difference between read only models, and RW ones
+ * So one should verify the person exists before doing this if one does not want to create a RW model
+ */
+ def namedPerson(gr: Model, webid: URL): IdPerson = {
+ IdPerson(gr.createResource(webid.toString))
+ }
+
+ def findDefinedPeople(m: Resource): Validation[scala.Throwable,Set[IdPerson]] = {
+ for (gr<-m.get()) yield {
+ definedPeople(gr, m.name)
+ }.toSet
+ }
+
+ def findIdPeople(m: Resource): Val[Set[IdPerson]] = {
+ for (gr<-m.get()) yield {
+ for (st <- gr.listStatements(null,RDF.`type`,FOAF.Person).asScala;
+ val subj = st.getSubject;
+ if (subj.isURIResource)
+ ) yield {
+ val p = new IdPerson(subj)
+
+ p
+ }
+ }.toSet
+
+ }
+
+ implicit def toResource(str: String) = ResourceFactory.createResource(str)
+ implicit def toProperty(str: String) = ResourceFactory.createProperty(str)
+
+}
+
+object Test {
+ implicit def urlToResource(u: URL) = GraphCache.resource(u)
+ import System._
+
+ val peopleRd = new ResourceReader[Set[Person]](Extractors.findPeople)
+ val definedPeopleRd = new ResourceReader[Set[IdPerson]](Extractors.findDefinedPeople)
+ val idPeopleRd = new ResourceReader[Set[IdPerson]](Extractors.findIdPeople)
+ val definedPeopleFriends = definedPeopleRd.flatMap(people =>ResourceReader[Set[IdPerson]]{
+ resource: Resource =>
+ resource.get().map(gr=>
+ for ( p <- people;
+ st <- gr.listStatements(p.id, FOAF.knows, null).asScala ;
+ val friend = st.getObject;
+ if (friend.isURIResource)
+ ) yield IdPerson(friend.asInstanceOf[JResource])
+ )
+ } )
+
+/*
+ def main(args: Array[String]) {
+
+ val url: String = "http://bblfish.net/people/henry/card"
+
+ // extract the people who are defined in the graph (rarely more than one)
+ for (people <- definedPeopleRd.extract(new URL(url));
+ p <- people) {
+ System.out.println("found "+p.name)
+ }
+ out.println
+
+ out.println("friends of people defined using flatmaped reader")
+ //use the flatMap to go from defined people to their friends
+ //get these friends names
+ for (people <- definedPeopleFriends.extract(new URL(url));
+ p <- people) {
+ System.out.println("found "+p.name)
+ }
+ out.println
+
+
+
+ // extract all the people with ids.
+ // and show all their properties
+ // this produces a lot of data so its commented out
+// out.println("=== ID PEOPLE ===")
+// out.println
+// for (people <- idPeopleRd.extract(new URL(url));
+// p <- people) {
+// out.println
+// out.println("----------")
+// out.println("id "+p.webid)
+// out.println("with properties:")
+// val str = for ((prop,setovals) <- p.relations.iterator) yield {
+// setovals.map(n=>prop.getLocalName+" is "+n.toString).mkString("\n")
+// }
+// out.print(str.mkString("\r\n"))
+// }
+
+ }
+*/
+}
\ No newline at end of file
--- a/src/main/scala/util.scala Thu Oct 13 13:34:16 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,200 +0,0 @@
-package org.w3.readwriteweb
-
-import javax.servlet._
-import javax.servlet.http._
-import unfiltered.request._
-import unfiltered.response._
-import unfiltered.jetty._
-
-import java.io._
-import scala.io.Source
-
-import scalaz._
-import Scalaz._
-
-import _root_.scala.sys.error
-
-import org.slf4j.{Logger, LoggerFactory}
-
-import com.hp.hpl.jena.rdf.model._
-import com.hp.hpl.jena.query._
-import com.hp.hpl.jena.update._
-
-import unfiltered.request._
-import unfiltered.response._
-import unfiltered.jetty._
-sealed trait RWWMode
-case object AllResourcesAlreadyExist extends RWWMode
-case object ResourcesDontExistByDefault extends RWWMode
-
-sealed trait RDFEncoding {
- def toContentType:String
-}
-case object RDFXML extends RDFEncoding {
- def toContentType = "application/rdf+xml"
-}
-case object TURTLE extends RDFEncoding {
- def toContentType = "text/turtle"
-}
-
-object RDFEncoding {
-
- def apply(contentType:String):RDFEncoding = {
- val i = contentType.indexOf(';')
- (if (i<0) contentType
- else contentType.substring(0,i).trim()).toLowerCase match {
- case "text/turtle" => TURTLE
- case "application/rdf+xml" => RDFXML
- case _ => RDFXML
- }
- }
-
- def jena(encoding: RDFEncoding) = encoding match {
- case RDFXML => "RDF/XML-ABBREV"
- case TURTLE => "TURTLE"
- case _ => "RDF/XML-ABBREV" //don't like this default
- }
-
- def apply(req:HttpRequest[_]):RDFEncoding = {
- val contentType = Accept(req).headOption
- contentType map { RDFEncoding(_) } getOrElse RDFXML
- }
-
-}
-
-trait ValidationW[E, S] {
- val validation:Validation[E, S]
- def failMap[EE](f:E => EE):Validation[EE, S] = validation.fail map f validation
-}
-
-package object util {
-
- val defaultLang = "RDF/XML-ABBREV"
-
- class MSAuthorVia(value:String) extends ResponseHeader("MS-Author-Via", List(value))
- object ViaSPARQL extends MSAuthorVia("SPARQL")
-
- object ResponseModel {
- def apply(model:Model, base:String, encoding:RDFEncoding):ResponseStreamer =
- new ResponseStreamer {
- def stream(os:OutputStream):Unit =
- encoding match {
- case RDFXML => model.getWriter("RDF/XML-ABBREV").write(model, os, base)
- case TURTLE => model.getWriter("TURTLE").write(model, os, base)
- }
- }
- }
-
- object ResponseResultSet {
- def apply(rs:ResultSet):ResponseStreamer =
- new ResponseStreamer {
- def stream(os:OutputStream):Unit = ResultSetFormatter.outputAsXML(os, rs)
- }
- def apply(result:Boolean):ResponseStreamer =
- new ResponseStreamer {
- def stream(os:OutputStream):Unit = ResultSetFormatter.outputAsXML(os, result)
- }
- }
-
- def modelFromInputStream(is:InputStream, base: String, lang: RDFEncoding): Validation[Throwable, Model]=
- modelFromInputStream(is, base, RDFEncoding.jena(lang))
-
- def modelFromInputStream(
- is:InputStream,
- base:String,
- lang:String = "RDF/XML-ABBREV"):Validation[Throwable, Model] =
- try {
- val m = ModelFactory.createDefaultModel()
- m.read(is, base, lang)
- m.success
- } catch {
- case t => t.fail
- }
-
- def modelFromString(s:String,
- base:String,
- lang:String = "RDF/XML-ABBREV"):Validation[Throwable, Model] =
- try {
- val reader = new StringReader(s)
- val m = ModelFactory.createDefaultModel()
- m.read(reader, base, lang)
- m.success
- } catch {
- case t => t.fail
- }
-
- implicit def wrapValidation[E, S](v:Validation[E,S]):ValidationW[E, S] =
- new ValidationW[E, S] { val validation = v }
-
- implicit def unwrap[E, F <: E, S <: E](v:Validation[F,S]):E = v.fold(e => e, s => s)
-
-}
-
-
-import java.io.{File, FileWriter}
-import java.util.jar._
-import scala.collection.JavaConversions._
-import scala.io.Source
-import java.net.{URL, URLDecoder}
-import org.slf4j.{Logger, LoggerFactory}
-
-/** useful stuff to read resources from the classpath */
-object MyResourceManager {
-
- val logger:Logger = LoggerFactory.getLogger(this.getClass)
-
- val clazz:Class[_] = this.getClass
- val classloader = this.getClass.getClassLoader
-
- /** http://www.uofr.net/~greg/java/get-resource-listing.html
- */
- def getResourceListing(path:String):List[String] = {
- var dirURL:URL = classloader.getResource(path)
- if (dirURL != null && dirURL.getProtocol == "file") {
- /* A file path: easy enough */
- new File(dirURL.toURI).list.toList
- } else {
- if (dirURL == null) {
- val me = clazz.getName().replace(".", "/")+".class"
- dirURL = classloader.getResource(me)
- }
- if (dirURL.getProtocol == "jar") {
- val jarPath = dirURL.getPath.substring(5, dirURL.getPath().indexOf("!"))
- val jar:JarFile = new JarFile(URLDecoder.decode(jarPath, "UTF-8"))
- val entries = jar.entries filter { _.getName startsWith path } map { e => {
- var entry = e.getName substring path.length
- val checkSubdir = entry indexOf "/"
- if (checkSubdir >= 0) entry = entry.substring(0, checkSubdir)
- entry
- } }
- entries filterNot { _.isEmpty } toList
- } else
- error("Cannot list files for URL "+dirURL);
- }
- }
-
- /** extract a path found in the classpath
- *
- * @return the file on disk
- */
- def fromClasspath(path:String, base:File = new File("src/main/resources")):File = {
- val workingPath = new File(base, path)
- if (workingPath isDirectory) {
- workingPath
- } else {
- val dir = new File(System.getProperty("java.io.tmpdir"),
- "virtual-trainer-" + scala.util.Random.nextInt(10000).toString)
- if (! dir.mkdir()) logger.error("Couldn't extract %s from jar to %s" format (path, dir.getAbsolutePath))
- val entries = getResourceListing(path) foreach { entry => {
- val url = classloader.getResource(path + entry)
- val content = Source.fromURL(url, "UTF-8").getLines.mkString("\n")
- val writer = new FileWriter(new File(dir, entry))
- writer.write(content)
- writer.close()
- }
- }
- dir
- }
- }
-
-}
--- a/src/main/scala/util/FilterLogger.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/main/scala/util/FilterLogger.scala Wed May 23 23:47:37 2012 +0200
@@ -13,9 +13,9 @@
def destroy(): Unit = ()
def doFilter(
- request: ServletRequest,
- response: ServletResponse,
- chain: FilterChain): Unit = {
+ request: ServletRequest,
+ response: ServletResponse,
+ chain: FilterChain): Unit = {
val r: HttpServletRequest = request.asInstanceOf[HttpServletRequest]
val method = r.getMethod
val uri = r.getRequestURI
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/HttpMethod.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,20 @@
+package org.w3.readwriteweb.util
+
+import unfiltered.request._
+
+// TODO pull request to the unfiltered project!
+object HttpMethod {
+ def unapply(req: HttpRequest[_]): Option[Method] =
+ Some(
+ req.method match {
+ case "GET" => GET
+ case "PUT" => PUT
+ case "HEAD" => HEAD
+ case "POST" => POST
+ case "CONNECT" => CONNECT
+ case "OPTIONS" => OPTIONS
+ case "TRACE" => TRACE
+ case m => new Method(m)
+ })
+
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/LogSecurityManager.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.util
+
+import com.weiglewilczek.slf4s.Logging
+import java.lang.{Class, String}
+import java.net.InetAddress
+import java.io.FileDescriptor
+import java.security.Permission
+
+/**
+ * This class can be set as the SecurityManager on the command line with
+ * -Djava.security.manager=org.w3.readwriteweb.util.NetworkLoggingSM
+ * IT will show all attempts to make outbound network connections, which can be useful to track connections made in
+ * various libraries
+ */
+class NetworkLoggingSM extends AllowAllSecurityManager with Logging {
+
+ override def checkConnect(host: String, port: Int) {
+ logger.info("connecting to "+host+":"+port)
+ super.checkConnect(host,port)
+ }
+
+ override def checkConnect(host: String, port: Int, context: AnyRef) {
+ logger.info("connecting to "+host+":"+port)
+ super.checkConnect(host,port,context)
+ }
+
+}
+
+class AllowAllSecurityManager extends SecurityManager {
+ override def checkAccept(host: String, port: Int) {}
+
+
+ override def checkAwtEventQueueAccess() {}
+
+ override def checkConnect(host: String, port: Int) {}
+
+ override def checkConnect(host: String, port: Int, context: AnyRef) {}
+
+ override def checkCreateClassLoader() {}
+
+ override def checkDelete(file: String) {}
+
+ override def checkExec(cmd: String) {}
+
+ override def checkExit(status: Int) {}
+
+ override def checkLink(lib: String) {}
+
+ override def checkListen(port: Int) {}
+
+ override def checkMemberAccess(clazz: Class[_], which: Int) {}
+
+ override def checkMulticast(maddr: InetAddress) {}
+
+ override def checkMulticast(maddr: InetAddress, ttl: Byte) {}
+
+ override def checkPackageAccess(pkg: String) {}
+
+ override def checkPackageDefinition(pkg: String) {}
+
+ override def checkPermission(perm: Permission) {}
+
+ override def checkPermission(perm: Permission, context: AnyRef) {}
+
+ override def checkPrintJobAccess() {}
+
+ override def checkPropertiesAccess() {}
+
+ override def checkPropertyAccess(key: String) {}
+
+ override def checkRead(fd: FileDescriptor) {}
+
+ override def checkRead(file: String) {}
+
+ override def checkRead(file: String, context: AnyRef) {}
+
+ override def checkSecurityAccess(target: String) {}
+
+ override def checkSetFactory() {}
+
+ override def checkSystemClipboardAccess() {}
+
+ override def checkTopLevelWindow(window: AnyRef) = false
+
+ override def checkWrite(fd: FileDescriptor) {}
+
+ override def checkWrite(file: String) {}
+}
+
+trait WrappedSecurityManager extends SecurityManager {
+ val wrap: SecurityManager
+ override def getSecurityContext = wrap.getSecurityContext
+
+ override def checkPermission(perm: Permission) { wrap.checkPermission(perm)}
+
+ override def checkPermission(perm: Permission, context: AnyRef) {wrap.checkPermission(perm,context)}
+
+ override def checkCreateClassLoader() { wrap.checkCreateClassLoader() }
+
+ override def checkAccess(t: Thread) { wrap.checkAccess(t)}
+
+ override def checkAccess(g: ThreadGroup) { wrap.checkAccess(g)}
+
+ override def checkExit(status: Int) { wrap.checkExit(status) }
+
+ override def checkExec(cmd: String) { wrap.checkExec(cmd) }
+
+ override def checkLink(lib: String) { wrap.checkLink(lib)}
+
+ override def checkRead(fd: FileDescriptor) {wrap.checkRead(fd)}
+
+ override def checkRead(file: String) { wrap.checkRead(file)}
+
+ override def checkRead(file: String, context: AnyRef) { wrap.checkRead(file)}
+
+ override def checkWrite(fd: FileDescriptor) {wrap.checkWrite(fd)}
+
+ override def checkWrite(file: String) {wrap.checkWrite(file)}
+
+ override def checkDelete(file: String) {wrap.checkDelete(file)}
+
+ override def checkListen(port: Int) {wrap.checkListen(port)}
+
+ override def checkAccept(host: String, port: Int) {wrap.checkAccept(host,port)}
+
+ override def checkMulticast(maddr: InetAddress) { wrap.checkMulticast(maddr)}
+
+ override def checkPropertiesAccess() { wrap.checkPropertiesAccess()}
+
+ override def checkPropertyAccess(key: String) {wrap.checkPropertyAccess(key)}
+
+ override def checkTopLevelWindow(window: AnyRef) = wrap.checkTopLevelWindow(window)
+
+ override def checkPrintJobAccess() { wrap.checkPrintJobAccess()}
+
+ override def checkSystemClipboardAccess() { wrap.checkSystemClipboardAccess()}
+
+ override def checkAwtEventQueueAccess() { wrap.checkAwtEventQueueAccess()}
+
+ override def checkPackageAccess(pkg: String) { wrap.checkPackageAccess(pkg)}
+
+ override def checkPackageDefinition(pkg: String) {wrap.checkPackageDefinition(pkg)}
+
+ override def checkSetFactory() {wrap.checkSetFactory()}
+
+ override def checkMemberAccess(clazz: Class[_], which: Int) {wrap.checkMemberAccess(clazz,which)}
+
+ override def checkSecurityAccess(target: String) {wrap.checkSecurityAccess(target)}
+
+ override def getThreadGroup = wrap.getThreadGroup
+}
+
+
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/ResponseModel.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,15 @@
+package org.w3.readwriteweb
+
+import java.io._
+import java.net.URL
+
+import com.hp.hpl.jena.rdf.model._
+import unfiltered.response._
+
+object ResponseModel {
+ def apply(model: Model, base: URL, lang: Lang): ResponseStreamer =
+ new ResponseStreamer {
+ def stream(os: OutputStream): Unit =
+ model.getWriter(lang.jenaLang).write(model, os, base.toString)
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/ResponseResultSet.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,23 @@
+package org.w3.readwriteweb
+
+import java.io._
+import com.hp.hpl.jena.rdf.model._
+import com.hp.hpl.jena.query._
+import unfiltered.response._
+import scalaz._
+import Scalaz._
+
+object ResponseResultSet {
+
+ def apply(rs: ResultSet): ResponseStreamer =
+ new ResponseStreamer {
+ def stream(os: OutputStream): Unit = ResultSetFormatter.outputAsXML(os, rs)
+ }
+
+ def apply(result: Boolean): ResponseStreamer =
+ new ResponseStreamer {
+ def stream(os: OutputStream): Unit =
+ ResultSetFormatter.outputAsXML(os, result)
+ }
+
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/SpyInputStream.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.util
+
+import java.io.{IOException, OutputStream, InputStream}
+
+
+/**
+ * Wrap an inputstream and write everything that comes in here
+ * @author hjs
+ * @created: 30/10/2011
+ */
+
+class SpyInputStream(val in: InputStream, val out: OutputStream) extends InputStream {
+ var stopOut = false
+
+ def read() ={
+
+ val i = try {
+ in.read()
+ } catch {
+ case ioe: IOException => {
+ out.flush()
+ out.close()
+ stopOut=true
+ throw ioe;
+ }
+ }
+ if (!stopOut) try {
+ out.write(i)
+ } catch {
+ case ioe: IOException => {
+ stopOut = true
+ }
+ }
+ i
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/ViaSPARQL.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,7 @@
+package org.w3.readwriteweb
+
+import unfiltered.response._
+
+class MSAuthorVia(value: String) extends ResponseHeader("MS-Author-Via", List(value))
+
+object ViaSPARQL extends MSAuthorVia("SPARQL")
--- a/src/main/scala/util/package.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/main/scala/util/package.scala Wed May 23 23:47:37 2012 +0200
@@ -2,66 +2,36 @@
import java.io._
import com.hp.hpl.jena.rdf.model._
-import com.hp.hpl.jena.query._
-import unfiltered.response._
import scalaz._
import Scalaz._
+import java.net.URL
+import com.weiglewilczek.slf4s.Logging
-package object util {
-
- val defaultLang = "RDF/XML-ABBREV"
-
- class MSAuthorVia(value: String) extends ResponseHeader("MS-Author-Via", List(value))
-
- object ViaSPARQL extends MSAuthorVia("SPARQL")
+package object util extends Logging {
- object ResponseModel {
- def apply(model: Model, base: String, encoding: RDFEncoding): ResponseStreamer =
- new ResponseStreamer {
- def stream(os: OutputStream): Unit =
- encoding match {
- case RDFXML => model.getWriter("RDF/XML-ABBREV").write(model, os, base)
- case TURTLE => model.getWriter("TURTLE").write(model, os, base)
- }
- }
- }
-
- object ResponseResultSet {
- def apply(rs: ResultSet): ResponseStreamer =
- new ResponseStreamer {
- def stream(os: OutputStream): Unit = ResultSetFormatter.outputAsXML(os, rs)
- }
- def apply(result: Boolean): ResponseStreamer =
- new ResponseStreamer {
- def stream(os: OutputStream):Unit = ResultSetFormatter.outputAsXML(os, result)
- }
- }
-
- //Passing strings into mathod arguments, especially as these differ completely between rdf stacks is not so good
- //passing objects is better
- def modelFromInputStream(is:InputStream, base: String, lang: RDFEncoding): Validation[Throwable, Model]=
- modelFromInputStream(is, base, RDFEncoding.jena(lang))
-
def modelFromInputStream(
is: InputStream,
- base: String,
- lang: String = "RDF/XML-ABBREV"): Validation[Throwable, Model] =
+ base: URL,
+ lang: Lang): Validation[Throwable, Model] =
try {
val m = ModelFactory.createDefaultModel()
- m.read(is, base, lang)
+ m.getReader(lang.jenaLang).read(m, is, base.toString)
m.success
} catch {
- case t => t.fail
+ case t => {
+ logger.info("cought exception turning stream into model ",t)
+ t.fail
+ }
}
def modelFromString(
s: String,
- base: String,
- lang: String = "RDF/XML-ABBREV"): Validation[Throwable, Model] =
+ base: URL,
+ lang: Lang): Validation[Throwable, Model] =
try {
val reader = new StringReader(s)
val m = ModelFactory.createDefaultModel()
- m.read(reader, base, lang)
+ m.getReader(lang.jenaLang).read(m, reader, base.toString)
m.success
} catch {
case t => t.fail
@@ -72,4 +42,20 @@
implicit def unwrap[E, F <: E, S <: E](v: Validation[F,S]): E = v.fold(e => e, s => s)
+ // I wonder if this is already defined somewhere...
+ def trySome[T](body: => T): Option[T] =
+ try {
+ val res = body;
+ if (res == null) None else Option(res)
+ } catch {
+ case _ => None
+ }
+
+ def tryOrFail[T](body: => T): Validation[Throwable,T] =
+ try {
+ val res = body;
+ res.success
+ } catch {
+ case e => e.fail
+ }
}
Binary file src/test/resources/JohnDoe.p12 has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/resources/JohnDoe.pem Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,59 @@
+Bag Attributes
+ friendlyName: John Doe
+ localKeyID: AC 40 B2 E2 CB FA BA 99 31 19 84 48 C6 2A 9C 6A F9 2F BD 3E
+subject=/C=FR/CN=John Doe/emailAddress=joe@localhost
+issuer=/C=FR/ST=Essonne/O=MyProfile/OU=MyProfile/CN=MyProfile
+-----BEGIN CERTIFICATE-----
+MIIDWzCCAsSgAwIBAgIJAP/V3sbj4N55MA0GCSqGSIb3DQEBBQUAMFsxCzAJBgNV
+BAYTAkZSMRAwDgYDVQQIEwdFc3Nvbm5lMRIwEAYDVQQKEwlNeVByb2ZpbGUxEjAQ
+BgNVBAsTCU15UHJvZmlsZTESMBAGA1UEAxMJTXlQcm9maWxlMB4XDTEyMDUyMzEy
+NTc1MloXDTIyMDUyMTEyNTc1MlowPjELMAkGA1UEBhMCRlIxETAPBgNVBAMTCEpv
+aG4gRG9lMRwwGgYJKoZIhvcNAQkBFg1qb2VAbG9jYWxob3N0MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYdRrO4yBLcoXS5Rnl75d09+NOTlBQChocJ1
+KUjHpLKFBy2T0BLWRTtb8XCnDBDvPWRIIoYJmhJ3ESg+VO7hzxyOGq+iIzrSnK0d
+FnezTB9F6i8pblIkI3d/1LRj2SLeXwFnEa3CQXfkdV4nuk+xeKHEtGiYRXY+bWwt
+MqX/7d+fX625yOLnsqfobWxmQtWujZ/HqCxXrAzXW3l8g4bcsiPmupODWKsxrN3z
+W+6l/F6WWs9wXdhIdAw9F3cgAUGd/KWnZy4p2voTDS03957SYqWMmLXzFycE1z0M
+kej2uwRsfWI/5r4bVhmflr+frFWWB6AUReEZhhhDNlkgnPTJGQIDAQABo4G/MIG8
+MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENl
+cnRpZmljYXRlMB0GA1UdDgQWBBSsQLLiy/q6mTEZhEjGKpxq+S+9PjAfBgNVHSME
+GDAWgBSmauM8jjh5l4t3jIf1SW5ry65FATBBBgNVHREEOjA4gQ1qb2VAbG9jYWxo
+b3N0hidodHRwczovL2xvY2FsaG9zdDo4NDQzLzIwMTIvZm9hZi5uMyNqb2UwDQYJ
+KoZIhvcNAQEFBQADgYEAU2i3OjgGR4N3HAObVXjDc6h+2iCk44ylzx5Fg+tLJyqt
+iUQL4XBKiaj87kxTNBNASXlm68WKXJmU8de48Zla5sdhGxNuGIxSphVTjCYbx/aY
+0l3p/Z1OcbI4EPqvFnYtpE3xdWF2q+UMQr6jea/sLRXORN2HKz8q3GITW04DPvU=
+-----END CERTIFICATE-----
+Bag Attributes
+ friendlyName: my-profile.eu
+ localKeyID: AC 40 B2 E2 CB FA BA 99 31 19 84 48 C6 2A 9C 6A F9 2F BD 3E
+Key Attributes: <No Attributes>
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI3ku0QwonlvMCAggA
+MBQGCCqGSIb3DQMHBAgisb41zYBv7QSCBMhCSN32ZMnGMcUl2QUQ/vjUANl39p9Y
+36Er/+h4rjCTO4oQP+jcO1NonY8BDh+sinFfSrtkj59IYewhCGOUjAdpDhQyyTDe
+BMbYcT+yzcPZB0EaIPbHgBFdlvhesuXXiL8J3IOYl6TvnO2+uaO6O5JYhFq3Pfjg
+OLtM3NXTbvxgyNr37MtjmTSSEMkHpRR9iuYW23YzkS1lp2Kbm6R8dFtL/25/TJ3z
+eiHt5OXHkTyeQU38b4/zRQuEwkAwJf1GlirdFCT0dxP6aXLJmfc47uMKCQCA8OmM
+rnFWrw4j0h3t4G1byiTxkd9QHJ0stgTjXWjVuj4tIBsl8UJSfHniES5cav7Mhajk
+0/5JBJ0GQd8Q40W0QLKiMH5KwDRhzdsvxn5Bk/Tp5sL8/WQaxAqQ4ISxWVxLBVFz
+3xg2nkAThi1Cp6PPEOBu3cJDRSxmcgrDNYkOfqPYe3CIIg4caiLBJs/bsUCHI5dL
+/9cBuknftKtrWxkEGHi+QQWUw9EmyvUPylVXyPFPY1whrsKu3z3MvMNaUXw4OjkN
+Vpcgw/BORnLig8GYF3LV5ZbijgvzkJ60lNIzLZiHkVeeQFYZ/muptdLm47DXIm9T
+usrVa5UzpmrW5QZ/rWts+UBTRAZCz0AUK/24vwaP4AC5LnWmjy52zt+qJw3ZYTQQ
+FKy1pesMPM5FPC6l7f+midxv/echnnsubP1+ChntSbGAxD/GSo305TpUgxqJrtaK
+dPx89xzVp9+z3rC28qSOjryDO3HwIL8JA/kBMLzd9FClZzAhQKsez8ha2ETpyJXj
+6YQPbTQTkOpprdh6T7IqYF9Q69xGBvFR+EG1AbiYWyPY2L/SyqIoK9shUXnf3Pkd
+NbZRxHaNKJIDy5loFi0kJ4Hi3ZnZDJM89Gpo3gEWBdudHBWYYiP97+jDFG7Yxi7U
++wvX1K9dhwq8El80K49Z1HNOOhgFH4gZQfsu+osCs1ESOAvAGDXMcyPRoZqDrMln
+4zKHSWJXNPhH2KTxIcuoRiFgITlHy4vicfcRffNV7J4+BFA8cu94IvYkRXvEcOkU
+qHZMcR03p1AJM1haIP7xL5aBq+41ToiX5ynI1TQnYgwR2o8RUUNDmmSBGePg81q1
+1Nd4JUTLFyIPIOgYVQ6mqQ1sQzbPtxSStTCCu6y4Tk1wkOysONTEE3GToVxflrMb
++FLbw7ObNMNhgdeCY7hWlMA9sPUT9O/Ta5RbldXgxnWdamrOE8vB/w83ZrDANcNO
+zY7mx4EWSgDl8ixOYNC+PifJRyk0aq6AP3FXVRgm9igAo9aMc8e3p+cn7fdGj18v
+lrl66DTLlClxJKNPrVJQyONj57EMSachia5inZiQ24mFJ0+c0cY975DiCLmfOTjB
++6JP7Dk0rQ8Lnu+sJ3nu7rww6YJJtWhBi54ogj4+dVspB/O7qyAijQqmuIqhvJp4
+m59T2UzsGvx316j4gFquUCpbauu/L2TKI91CNHQ7sobJJnHKrFZokBvlggka/26F
+1Tma7RJPowGoP/bgWPw05zjnZMsDrRIx2NFZqhAQbRY+YVesal8eKONoHcrhD9Z1
+g0eZOUCNKTrrQDagU9hco0zpnPcEkJdIgdB19TuVkVd0VEYmUI/aIQhfX/xHjF2C
+bDc=
+-----END ENCRYPTED PRIVATE KEY-----
Binary file src/test/resources/KEYSTORE.jks has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/resources/KEYSTORE.pem Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIEdOn4GjANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJDWTETMBEGA1UE
+CBMKQ3liZXJzcGFjZTEUMBIGA1UEBxMLTW9vbiBCYXNlIDExEjAQBgNVBAoTCU1hdmVyaWNrczEV
+MBMGA1UECxMMVW5pdCBUZXN0aW5nMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTIwNTIzMTIyNzAw
+WhcNMTcxMTEzMTIyNzAwWjB3MQswCQYDVQQGEwJDWTETMBEGA1UECBMKQ3liZXJzcGFjZTEUMBIG
+A1UEBxMLTW9vbiBCYXNlIDExEjAQBgNVBAoTCU1hdmVyaWNrczEVMBMGA1UECxMMVW5pdCBUZXN0
+aW5nMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5
+SDUFfqi7EY3G3rV/NKiDRqcxmrJa22lSLWEaeL2GaMwm4BriWx1CkpCdm34rghZ0yaA7Es45XweZ
+/ccT803RA2s6lrJnz0m3zgOaPC0oo/gzjx4wQH0IRxPbk1q4i/KFI62Im+vSKgZmU2PhWiIaXLgY
+YNIYI1By8JTzzV/MlhADFh3rvziAI4U3HReunx8Oy98wlqNP2rCe6zRofmr0xX3hLX4qwXxDVBmw
+HAg5BAWCt2Pc84TTY5rKQMrxXWY/uU8d5f5wlshts5Ix4yH4SWWir1yY5xaZxqhcIIMWv2vm5+Jp
+06a7JgCu7vdnYvbN0V+PQEliuH7Q51jG8BE7AgMBAAGjITAfMB0GA1UdDgQWBBSjQNIk5JyPGUSd
+I5ZaxoB5i5shQTANBgkqhkiG9w0BAQsFAAOCAQEAYqPEv4vnHWIo7WBAGCIlh0rdkUJufhB4eOVJ
+PV4VGPPI15C/QoBLjC+3rdiM+EVF5p/mYWAc5/mjKAIhJnlo91eEKlSvD3qlnhJDyDDnpuiY3tdP
+SMvLEYtm/8qhZl/E2crs7T2ozfynmtQFfNnKpTluBMJtBNQwaCPCgxQ/e+9YCSasdHJp1xLp20Ma
+Sm8c8gSo/wYdsnuoVpNHZh3k+UZgMLKQp5jLBJRH6nBhjCibTiAaf/5Hcqufuedwcw6qYR1fIXR5
+COZvu0OuVTJyGipDp43mHlg0GRDT6qsYKuQHfs3PaKtKnC31F1YnNz6a4sUTxNkkJqGIvIpsTNOH
+dg==
+-----END CERTIFICATE-----
--- a/src/test/scala/AccessContentSpecs.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/test/scala/AccessContentSpecs.scala Wed May 23 23:47:37 2012 +0200
@@ -24,7 +24,7 @@
"return a 200 and an empty model" in {
val (statusCode, model) = Http(uri >+ {
req => (req.get_statusCode,
- req as_model(uriBase))
+ req as_model(uriBase, RDFXML))
} )
statusCode must_== 200
model must beIsomorphicWith (emptyModel)
@@ -37,8 +37,8 @@
"a GET on Joe's URI" should {
"deliver TURTLE and RDF/XML graphs that are isomorphic to each other" in {
- val rdfxml = Http(uri as_model(uriBase))
- val turtle = Http(uri <:< Map("Accept" -> "text/turtle") as_model(uriBase, lang="TURTLE"))
+ val rdfxml = Http(uri as_model(uriBase, RDFXML))
+ val turtle = Http(uri <:< Map("Accept" -> "text/turtle") as_model(uriBase, TURTLE))
rdfxml must beIsomorphicWith(turtle)
}
}
--- a/src/test/scala/CreateContentSpecs.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/test/scala/CreateContentSpecs.scala Wed May 23 23:47:37 2012 +0200
@@ -4,12 +4,17 @@
import org.w3.readwriteweb.utiltest._
import dispatch._
+import java.net.URL
+import java.io.File
+import com.hp.hpl.jena.vocabulary.RDF
+import com.hp.hpl.jena.sparql.vocabulary.FOAF
+import com.hp.hpl.jena.rdf.model.Model
-object PutRDFXMLSpec extends FilesystemBased with SomeRDF with SomeURI {
+object PutRDFXMLSpec extends SomePeopleDirectory {
"PUTing an RDF document on Joe's URI (which does not exist yet)" should {
"return a 201" in {
- val httpCode = Http(uri.put(rdfxml) get_statusCode)
+ val httpCode = Http(uri.put(RDFXML, rdfxml) get_statusCode)
httpCode must_== 201
}
"create a document on disk" in {
@@ -21,14 +26,14 @@
"now exist and be isomorphic with the original document" in {
val (statusCode, via, model) = Http(uri >++ { req => (req.get_statusCode,
req.get_header("MS-Author-Via"),
- req as_model(uriBase))
+ req as_model(uriBase, RDFXML))
} )
statusCode must_== 200
via must_== "SPARQL"
model must beIsomorphicWith (referenceModel)
}
}
-
+
}
@@ -56,18 +61,58 @@
</rdf:RDF>
"""
- val expectedFinalModel = modelFromString(finalRDF, uriBase).toOption.get
+ val expectedFinalModel = modelFromString(finalRDF, uriBase, RDFXML).toOption.get
"POSTing an RDF document to Joe's URI" should {
"succeed" in {
- val httpCode:Int = Http(uri.post(diffRDF) get_statusCode)
+ val httpCode:Int = Http(uri.post(diffRDF, RDFXML) get_statusCode)
httpCode must_== 200
}
"append the diff graph to the initial graph" in {
- val model = Http(uri as_model(uriBase))
+ val model = Http(uri as_model(uriBase, RDFXML))
model must beIsomorphicWith (expectedFinalModel)
}
}
+
+ var createdDocURL: URL = _
+
+ "POSTing an RDF document to a Joe's directory/collection" should {
+ "succeed and create a resource on disk" in {
+ val handler = dirUri.post(diffRDF, RDFXML) >+ { req =>
+ val loc: Handler[String] = req.get_header("Location")
+ val status_code: Handler[Int] = req.get_statusCode
+ (status_code,loc)
+ }
+ val (code, head) = Http(handler)
+ code must_== 201
+ createdDocURL = new URL(head.trim)
+ val file = new File(root, createdDocURL.getPath.substring(baseURL.size))
+ file must exist
+ }
+
+ "the relative URLs of the POSTed doc are tied to the created URL" in {
+ val newModelShouldBe = modelFromString(diffRDF, createdDocURL, RDFXML).toOption.get
+ val rdfxml = Http(Request.strToRequest(createdDocURL.toString) as_model(createdDocURL, RDFXML))
+ rdfxml must beIsomorphicWith(newModelShouldBe)
+ val jl = rdfxml.getResource(createdDocURL+"#JL")
+ val clazz = jl.getPropertyResourceValue(RDF.`type`)
+ clazz must_== FOAF.Person
+ }
+
+ "the directory should say that it contains that resource" in {
+ val (statusCode, model): Pair[Int,Model] = Http(dirUri >+ {
+ req => (req.get_statusCode,
+ req as_model(uriBase, RDFXML))
+ } )
+ val sioc = "http://rdfs.org/sioc/ns#"
+ statusCode must_== 200
+ val newRes = model.createResource(createdDocURL.toURI.toString)
+ model.contains(model.createResource(uri.to_uri.toString),model.createProperty(sioc+"container_of"),newRes) mustBe true
+ model.contains(newRes,RDF.`type`,model.createResource(sioc+"Item")) mustBe true
+ }
+ }
+
+
}
@@ -76,7 +121,7 @@
"""PUTting not-valid RDF to Joe's URI""" should {
"return a 400 Bad Request" in {
- val statusCode = Http.when(_ == 400)(uri.put("that's bouleshit") get_statusCode)
+ val statusCode = Http.when(_ == 400)(uri.put(RDFXML, "that's bouleshit") get_statusCode)
statusCode must_== 400
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/scala/CreateDirectorySpec.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,32 @@
+package org.w3.readwriteweb
+
+import org.w3.readwriteweb.util._
+import org.w3.readwriteweb.utiltest._
+
+import dispatch._
+import com.hp.hpl.jena.rdf.model.Model
+import com.hp.hpl.jena.vocabulary.RDF
+
+object CreateDirSpec extends FilesystemBased with SomeRDF with SomeURI {
+
+ "PUTing an RDF document on /people/" should {
+ "return a 201" in {
+ val httpCode = Http(dirUri.put(RDFXML, rdfxml) get_statusCode)
+ httpCode must_== 201
+ }
+ "create a directory on disk" in {
+ directory must be directory
+ }
+ "return a directory listing" in {
+ val (statusCode, model): Pair[Int,Model] = Http(dirUri >+ {
+ req => (req.get_statusCode,
+ req as_model(uriBase, RDFXML))
+ } )
+ val sioc = "http://rdfs.org/sioc/ns#"
+ statusCode must_== 200
+ model.contains(model.createResource(uri.to_uri.toString),RDF.`type`,model.createResource(sioc+"Container")) mustBe true
+ model.listStatements(null,RDF.`type`,model.createResource(sioc+"Item")).hasNext mustBe false
+ }
+ }
+
+}
--- a/src/test/scala/OtherSpecs.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/test/scala/OtherSpecs.scala Wed May 23 23:47:37 2012 +0200
@@ -9,7 +9,7 @@
"""POSTing something that does not make sense to Joe's URI""" should {
"return a 400 Bad Request" in {
- val statusCode = Http.when(_ == 400)(uri.post("that's bouleshit") get_statusCode)
+ val statusCode = Http.when(_ == 400)(uri.post("that's bullshit", RDFXML) get_statusCode) //bulls and bears on the stock exchange
statusCode must_== 400
}
}
@@ -19,11 +19,27 @@
object DeleteResourceSpec extends SomeDataInStore {
- """a DELETE request""" should {
- "not be supported yet" in {
- val statusCode = Http.when(_ == 405)(uri.copy(method="DELETE") get_statusCode)
- statusCode must_== 405
+
+ "DELETEing Joe's URI" should {
+ "before doing it his resource must" in {
+ "be created and return a 201" in {
+ val httpCode = Http(uri.put(RDFXML, rdfxml) get_statusCode)
+ httpCode must_== 201
+ }
+ "create a document on disk" in {
+ resourceOnDisk must exist
+ }
+ }
+
+ "succeed" in {
+ val httpCode:Int = Http(uri.delete get_statusCode)
+ httpCode must_== 204
+ }
+
+ "delete the document on disk" in {
+ resourceOnDisk mustNot exist
}
}
+
}
--- a/src/test/scala/ReadWriteWebSpecs.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/test/scala/ReadWriteWebSpecs.scala Wed May 23 23:47:37 2012 +0200
@@ -7,11 +7,13 @@
// access content
GetStrictModeSpec, GetWikiModeSpec,
ContentNegociationSpec,
+ // create directory
+ CreateDirSpec,
// create content
PutRDFXMLSpec, PostRDFSpec,
PutInvalidRDFXMLSpec, PostOnNonExistingResourceSpec,
// sparql query
- PostSelectSpec, PostConstructSpec, PostAskSpec,
+ PostSelectSpec, PostConstructSpec, PostAskSpec,
// sparql update
PostInsertSpec,
// delete content
--- a/src/test/scala/SparqlQuerySpecs.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/test/scala/SparqlQuerySpecs.scala Wed May 23 23:47:37 2012 +0200
@@ -20,7 +20,7 @@
"""POSTing "SELECT ?name WHERE { [] foaf:name ?name }" to Joe's URI""" should {
"return Joe's name" in {
- val resultSet = Http(uri.post(selectFoafName) >- { body => ResultSetFactory.fromXML(body) } )
+ val resultSet = Http(uri.postSPARQL(selectFoafName) >- { body => ResultSetFactory.fromXML(body) } )
resultSet.next().getLiteral("name").getString must_== "Joe Lambda"
}
}
@@ -39,7 +39,7 @@
"""POSTing "ASK ?name WHERE { [] foaf:name ?name }" to Joe's URI""" should {
"return true" in {
val result: Boolean =
- Http(uri.post(askFoafName) >~ { s =>
+ Http(uri.postSPARQL(askFoafName) >~ { s =>
(XML.fromSource(s) \ "boolean" \ text).head.toBoolean
} )
result must_== true
@@ -57,7 +57,7 @@
"""POSTing "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }" to Joe's URI""" should {
"return an isomorphic RDF graph" in {
- val model = Http(uri as_model(uriBase))
+ val model = Http(uri as_model(uriBase, RDFXML))
model must beIsomorphicWith (referenceModel)
}
}
--- a/src/test/scala/SparqlUpdateSpecs.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/test/scala/SparqlUpdateSpecs.scala Wed May 23 23:47:37 2012 +0200
@@ -15,11 +15,11 @@
"POSTing an INSERT query on Joe's URI (which does not exist yet)" should {
"succeed" in {
- val httpCode = Http(uri.post(insertQuery) get_statusCode)
+ val httpCode = Http(uri.postSPARQL(insertQuery) get_statusCode)
httpCode must_== 200
}
"produce a graph with one more triple than the original one" in {
- val model = Http(uri as_model(uriBase))
+ val model = Http(uri as_model(uriBase, RDFXML))
model.size must_== (referenceModel.size + 1)
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/scala/auth/CreateWebIDSpec.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import org.w3.readwriteweb.utiltest._
+
+import dispatch._
+import java.security.cert.X509Certificate
+import java.security._
+import interfaces.RSAPublicKey
+import java.net.{Socket, URL}
+import scala.collection.mutable
+import javax.net.ssl._
+import java.io.File
+import org.w3.readwriteweb.{Post, RDFXML, TURTLE}
+import org.apache.commons.codec.binary.Hex
+
+
+/**
+ * A key manager that can contain multiple keys, but where the client can take one of a number of identities
+ * One at a time - so this is not synchronised. It also assumes that the server will accept all CAs, which in
+ * these test cases it does.
+ */
+class FlexiKeyManager extends X509ExtendedKeyManager {
+ val keys = mutable.Map[String, (Array[X509Certificate], PrivateKey)]()
+
+ def addClientCert(alias: String,certs: Array[X509Certificate], privateKey: PrivateKey) {
+ keys += (alias -> (certs -> privateKey))
+ }
+
+ var currentId: String = null
+
+ def setId(alias: String) { currentId = if (keys.contains(alias)) alias else null }
+
+ def getClientAliases(keyType: String, issuers: Array[Principal]) = if (currentId!=null) Array(currentId) else null
+
+ def chooseClientAlias(keyType: Array[String], issuers: Array[Principal], socket: Socket) = currentId
+
+ def getServerAliases(keyType: String, issuers: Array[Principal]) = null
+
+ def chooseServerAlias(keyType: String, issuers: Array[Principal], socket: Socket) = ""
+
+ def getCertificateChain(alias: String) = keys.get(alias) match { case Some(certNKey) => certNKey._1; case None => null}
+
+ def getPrivateKey(alias: String) = keys.get(alias).map(ck=>ck._2).getOrElse(null)
+
+ override def chooseEngineClientAlias(keyType: Array[String], issuers: Array[Principal], engine: SSLEngine): String = currentId
+}
+
+/**
+ * @author hjs
+ * @created: 23/10/2011
+ */
+
+object CreateWebIDSpec extends SecureFileSystemBased {
+ lazy val peopleDirUri = host / "wiki/people/"
+ lazy val webidProfileDir = peopleDirUri / "Lambda/"
+ lazy val webidProfile = webidProfileDir / "Joe"
+ lazy val joeProfileOnDisk = new File(root,"people/Lambda/Joe")
+ lazy val lambdaMetaURI = webidProfileDir/".meta.n3"
+
+ lazy val directory = new File(root, "people")
+ lazy val lambdaDir = new File(directory,"Lambda")
+ lazy val lambdaMeta = new File(lambdaDir,".meta.n3")
+
+
+
+ val foaf = """
+ @prefix foaf: <http://xmlns.com/foaf/0.1/> .
+ @prefix : <#> .
+
+ <> a foaf:PersonalProfileDocument;
+ foaf:primaryTopic :me .
+
+ :jL a foaf:Person;
+ foaf:name "Joe Lambda"@en .
+ """
+
+ val webID = new URL(webidProfile.secure.to_uri + "#jL")
+
+
+ val updatePk = """
+ PREFIX cert: <http://www.w3.org/ns/auth/cert#>
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+ PREFIX : <#>
+ INSERT DATA {
+ :jL cert:key [ cert:modulus "%s"^^xsd:hexBinary;
+ cert:exponent "%s"^^xsd:integer ] .
+ }
+ """
+
+ val updateFriend = """
+ PREFIX foaf: <http://xmlns.com/foaf/0.1/>
+ PREFIX : <#>
+ INSERT DATA {
+ :jL foaf:knows <%s> .
+ }
+ """
+
+
+ "PUTing nothing on /people/" should {
+ "return a 201" in {
+ val httpCode = Http(peopleDirUri.secure.put(TURTLE, "") get_statusCode)
+ httpCode must_== 201
+ }
+ "create a directory on disk" in {
+ directory must be directory
+ }
+ }
+
+
+ "PUTing nothing on /people/Lambda/" should { // but should it really? Should it not create a resource too? Perhaps index.html?
+ "return a 201" in {
+ val httpCode = Http(webidProfileDir.secure.put(TURTLE, "") get_statusCode)
+ httpCode must_== 201
+ }
+ "create a directory on disk" in {
+ lambdaDir must be directory
+ }
+ }
+
+
+ "PUTing a WebID Profile on /people/Lambda/" should {
+ "return a 201" in {
+ val httpCode = Http( webidProfile.secure.put(TURTLE, foaf) get_statusCode )
+ httpCode must_== 201
+ }
+ "create a resource on disk" in {
+ joeProfileOnDisk must be file
+ }
+ }
+
+
+ "POSTing public key into the /people/Lambda/Joe profile" should {
+
+ "first create signed WebID certificate and add it to local SSL keystore" in {
+ val keystore = getClass.getClassLoader.getResource("KEYSTORE.jks")
+ val signer = X509CertSigner(
+ keystore,
+ "JKS",
+ "secret",
+ "selfsigned"
+ )
+
+ val rsagen = KeyPairGenerator.getInstance("RSA")
+ rsagen.initialize(512)
+ val rsaKP = rsagen.generateKeyPair()
+
+
+ val testCert = signer.generate("CN=JoeLambda, OU=DIG, O=W3C", rsaKP.getPublic.asInstanceOf[RSAPublicKey], 1, webID)
+
+ testCert mustNotBe null
+
+ testKeyManager.addClientCert("JoeLambda",Array(testCert),rsaKP.getPrivate)
+ }
+
+ "return a 200 when POSTing relations to profile" in {
+ val joeCert = testKeyManager.getCertificateChain("JoeLambda")
+
+ joeCert mustNotBe null
+
+ val joeKey = joeCert(0).getPublicKey.asInstanceOf[RSAPublicKey]
+
+ val hex = new String(Hex.encodeHex(joeKey.getModulus.toByteArray))
+ val updateQStr = updatePk.format(
+ hex.stripPrefix("00"),
+ joeKey.getPublicExponent()
+ )
+
+ val httpCode = Http(
+ webidProfile.secure.postSPARQL(updateQStr) get_statusCode )
+ httpCode must_== 200
+ }
+
+ "create 3 more relations" in {
+ val model = Http(webidProfile.secure as_model(baseURI(webidProfile.secure), RDFXML))
+ model.size() must_== 7
+
+ }
+ }
+
+ val aclRestriction = """
+ @prefix acl: <http://www.w3.org/ns/auth/acl#> .
+ @prefix foaf: <http://xmlns.com/foaf/0.1/> .
+ @prefix : <#> .
+
+ :a1 a acl:Authorization;
+ acl:accessTo <Joe>;
+ acl:mode acl:Write;
+ acl:agent <%s>, <http://bblfish.net/people/henry/card#me> .
+
+ :allRead a acl:Authorization;
+ acl:accessTo <Joe>;
+ acl:mode acl:Read;
+ acl:agentClass foaf:Agent .
+ """
+
+
+ "PUT access control statements in directory" should {
+ "return a 201" in {
+ val httpCode = Http( lambdaMetaURI.secure.put(TURTLE, aclRestriction.format(webID.toExternalForm)) get_statusCode )
+ httpCode must_== 201
+ }
+
+ "create a resource on disk" in {
+ lambdaMeta must be file
+ }
+
+ "everybody can still read the profile" in {
+ testKeyManager.setId(null)
+ val model = Http(webidProfile.secure as_model(baseURI(webidProfile.secure), RDFXML))
+ model.size() must_== 7
+ }
+
+ "no one other than the user can change the profile" in {
+ val httpCode = Http.when(_ == 401)(webidProfile.secure.put(TURTLE, foaf) get_statusCode)
+ httpCode must_== 401
+ }
+
+ "access it as the user - allow him to add a friend" in {
+ testKeyManager.setId("JoeLambda")
+
+/* The code below was very useful to help me debug this.
+ Sometimes it helps to get back to basics. So I will leave this here.
+
+ val scon =webidProfile.secure.to_uri.toURL.openConnection().asInstanceOf[HttpsURLConnection]
+ scon.setSSLSocketFactory(sslContext.getSocketFactory)
+ scon.setRequestProperty("Content-Type",Post.SPARQL)
+ scon.setRequestProperty("User-Agent" , "Java/1.7.0")
+ scon.setRequestMethod("POST")
+ val msg = updateFriend.format("http://bblfish.net/#hjs").getBytes("UTF-8")
+ scon.setRequestProperty("Content-Length",msg.length.toString)
+ scon.setDoOutput(true)
+ scon.setDoInput(true)
+
+ val out = scon.getOutputStream
+ out.write(msg)
+ out.flush()
+ out.close()
+ scon.connect()
+
+ val httpCode = scon.getResponseCode
+*/
+
+ val req =webidProfile.secure.PUT <:< Map("User-Agent" -> "Java/1.7.0","Content-Type"->Post.SPARQL)
+ val req2 = req.copy(
+ method="POST",
+ body=Some(new RefStringEntity(updateFriend.format(webID.toExternalForm),Post.SPARQL,"UTF-8"))
+ )
+
+ val httpCode = Http( req2 get_statusCode )
+ httpCode must_== 200
+ }
+
+ "and so have one more relation in the foaf" in {
+ val model = Http(webidProfile.secure as_model(baseURI(webidProfile.secure), RDFXML))
+ model.size() must_== 8
+ }
+
+ }
+
+
+
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/scala/auth/SecureReadWriteWebSpec.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import org.specs.Specification
+
+/**
+ * @author hjs
+ * @created: 25/10/2011
+ */
+
+object SecureReadWriteWebSpec extends Specification {
+ try {
+ "The Secure Read Write Web".isSpecifiedBy(
+ CreateWebIDSpec
+ )
+ } catch {
+ case e => e.printStackTrace(System.out)
+ }
+
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/scala/auth/secure_specs.scala Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined at
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.auth
+
+import unfiltered.spec.netty.Started
+import org.specs.Specification
+import unfiltered.netty.{ReceivedMessage, ServerErrorResponse, cycle}
+import java.io.File
+import org.w3.readwriteweb._
+import grizzled.file.GrizzledFile._
+
+import java.security.cert.X509Certificate
+import org.apache.http.conn.scheme.Scheme
+import dispatch.Http
+import org.apache.http.client.HttpClient
+import javax.net.ssl.{SSLContext, X509TrustManager, KeyManager}
+import util.trySome
+import java.nio.file.Files
+
+/**
+ * @author hjs
+ * @created: 24/10/2011
+ */
+
+
+trait SecureServed extends Started {
+ import org.w3.readwriteweb.netty._
+
+ //todo: replace this with non property method of setting this.
+ System.setProperty("netty.ssl.keyStore",getClass.getClassLoader.getResource("KEYSTORE.jks").getFile)
+ System.setProperty("netty.ssl.keyStoreType","JKS")
+ System.setProperty("netty.ssl.keyStorePassword","secret")
+
+ def setup: (Https => Https)
+ lazy val server = setup( new KeyAuth_Https(port) )
+
+
+}
+
+object AcceptAllTrustManager extends X509TrustManager {
+ def checkClientTrusted(chain: Array[X509Certificate], authType: String) {}
+ def checkServerTrusted(chain: Array[X509Certificate], authType: String) {}
+ def getAcceptedIssuers = Array[X509Certificate]()
+}
+
+/**
+ * Netty resource managed with access control enabled
+ */
+trait SecureResourceManaged extends Specification with SecureServed {
+ import org.jboss.netty.handler.codec.http._
+
+ def resourceManager: ResourceManager
+
+ /**
+ * Inject flexible behavior into the client ssl so that it does not
+ * break on every localhost problem. It returns a key manager which can be used
+ * to allow the client to take on various guises
+ */
+ def flexi(client: HttpClient, km: KeyManager): SSLContext = {
+
+ val sslContext = javax.net.ssl.SSLContext.getInstance("TLS");
+
+ sslContext.init(Array[KeyManager](km), Array(AcceptAllTrustManager),null); // we are not trying to test our trust of localhost server
+
+ import org.apache.http.conn.ssl._
+ val sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
+ val scheme = new Scheme("https", 443, sf);
+ client.getConnectionManager.getSchemeRegistry.register(scheme)
+
+ sslContext
+ }
+
+
+
+ val webCache = GraphCache
+ val serverSslContext = javax.net.ssl.SSLContext.getInstance("TLS");
+
+
+
+ flexi(webCache.http.client, new FlexiKeyManager)
+
+
+ val testKeyManager = new FlexiKeyManager();
+ val sslContext = flexi(Http.client,testKeyManager)
+
+
+
+
+ val rww = new cycle.Plan with cycle.ThreadPool with ServerErrorResponse with ReadWriteWeb[ReceivedMessage,HttpResponse] {
+ val rm = resourceManager
+ def manif = manifest[ReceivedMessage]
+ override val authz = new RDFAuthZ[ReceivedMessage,HttpResponse](resourceManager)
+ }
+
+ def setup = { _.plan(rww) }
+
+}
+
+trait SecureFileSystemBased extends SecureResourceManaged {
+ lazy val mode: RWWMode = ResourcesDontExistByDefault
+
+ lazy val lang = TURTLE
+
+ lazy val baseURL = "/wiki"
+
+ /**
+ * finding where the specs2 output directory is, so that we can create temporary directories there,
+ * which can then be viewed if tests are unsuccessful, but that will also be removed on "sbt clean"
+ */
+ lazy val outDirBase = new File(trySome { System.getProperty("spec2.outDir") } getOrElse "target/specs2-reports/")
+
+ lazy val root = {
+ outDirBase.mkdirs()
+ val dir = Files.createTempDirectory(outDirBase.toPath, "test_rww_")
+ System.out.println("Temp directory: "+dir.toString)
+ dir.toFile
+ }
+
+ lazy val resourceManager = new Filesystem(root, baseURL, lang)(mode)
+
+ doBeforeSpec {
+ if (root.exists) root.deleteRecursively()
+ root.mkdir()
+ }
+
+}
--- a/src/test/scala/util/specs.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/test/scala/util/specs.scala Wed May 23 23:47:37 2012 +0200
@@ -2,48 +2,68 @@
import org.w3.readwriteweb._
+import auth.RDFAuthZ
import org.specs._
-import java.net.URL
-import unfiltered.response._
-import unfiltered.request._
import dispatch._
import java.io._
-import com.codecommit.antixml._
import grizzled.file.GrizzledFile._
-import com.hp.hpl.jena.rdf.model._
-import com.hp.hpl.jena.query._
-import com.hp.hpl.jena.update._
+import org.w3.readwriteweb.utiltest._
+import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
+import unfiltered.filter.Planify
+import unfiltered.netty.{ReceivedMessage, ServerErrorResponse, cycle}
+import unfiltered.spec.netty.Started
-import org.w3.readwriteweb.util._
-import org.w3.readwriteweb.utiltest._
-
-trait ResourceManaged extends Specification with unfiltered.spec.jetty.Served {
+trait JettyResourceManaged extends Specification with unfiltered.spec.jetty.Served {
def resourceManager: ResourceManager
-
- def setup = { _.filter(new ReadWriteWeb(resourceManager).plan) }
+
+ val rww = new ReadWriteWeb[HttpServletRequest,HttpServletResponse] {
+ val rm = resourceManager
+ def manif = manifest[HttpServletRequest]
+ }
+
+ def setup = { _.filter(Planify(rww.intent)) }
}
+/**
+ * Netty Resource managed.
+ **/
+trait ResourceManaged extends Specification with unfiltered.spec.netty.Served {
+ import org.jboss.netty.handler.codec.http._
+
+ def resourceManager: ResourceManager
+
+ val rww = new cycle.Plan with cycle.ThreadPool with ServerErrorResponse with ReadWriteWeb[ReceivedMessage,HttpResponse] {
+ val rm = resourceManager
+ def manif = manifest[ReceivedMessage]
+ }
+
+ def setup = { _.plan(rww) }
+
+}
+
+
+
trait FilesystemBased extends ResourceManaged {
-
+
lazy val mode: RWWMode = ResourcesDontExistByDefault
-
- lazy val language = "RDF/XML-ABBREV"
-
- lazy val baseURL = "/2007/wiki"
-
+
+ lazy val lang = RDFXML
+
+ lazy val baseURL = "/wiki"
+
lazy val root = new File(new File(System.getProperty("java.io.tmpdir")), "readwriteweb")
- lazy val resourceManager = new Filesystem(root, baseURL, language)(mode)
-
+ lazy val resourceManager = new Filesystem(root, baseURL, lang)(mode)
+
doBeforeSpec {
if (root.exists) root.deleteRecursively()
root.mkdir()
}
-
+
}
trait SomeRDF extends SomeURI {
@@ -62,27 +82,42 @@
"""
"""
- val referenceModel = modelFromString(rdfxml, uriBase).toOption.get
+ val referenceModel = modelFromString(rdfxml, uriBase, RDFXML).toOption.get
}
trait SomeURI extends FilesystemBased {
val emptyModel = com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel()
+
+ val peopleDirPath = "wiki/people/"
+
+ lazy val dirUri = host / peopleDirPath
- lazy val uri = host / "2007/wiki/people/JoeLambda"
+ lazy val uri = host / "wiki/people/JoeLambda"
lazy val uriBase = baseURI(uri)
+ lazy val directory = new File(root, "people")
+
lazy val resourceOnDisk = new File(root, "people/JoeLambda")
}
-trait SomeDataInStore extends FilesystemBased with SomeRDF with SomeURI {
+trait SomePeopleDirectory extends SomeRDF with SomeURI {
doBeforeSpec {
- val httpCode = Http(uri.put(rdfxml) get_statusCode)
+ val httpCode = Http(dirUri.put(RDFXML, rdfxml) get_statusCode)
httpCode must_== 201
}
}
+
+trait SomeDataInStore extends SomePeopleDirectory {
+
+ doBeforeSpec {
+ val httpCode = Http(uri.put(RDFXML, rdfxml) get_statusCode)
+ httpCode must_== 201
+ }
+
+}
--- a/src/test/scala/util/utiltest.scala Thu Oct 13 13:34:16 2011 +0200
+++ b/src/test/scala/util/utiltest.scala Wed May 23 23:47:37 2012 +0200
@@ -1,5 +1,6 @@
package org.w3.readwriteweb
+import java.net.URL
import javax.servlet._
import javax.servlet.http._
import unfiltered.request._
@@ -27,40 +28,52 @@
package object utiltest {
- def baseURI(req:Request):String = "%s%s" format (req.host, req.path)
+ def baseURI(req: Request): URL = new URL("%s%s" format (req.host, req.path))
- def beIsomorphicWith(that:Model):Matcher[Model] =
+ def beIsomorphicWith(that: Model): Matcher[Model] =
new Matcher[Model] {
- def apply(otherModel: => Model) =
+ def apply(otherModel: => Model) =
(that isIsomorphicWith otherModel,
"Model A is isomorphic to model B",
"%s not isomorphic with %s" format (otherModel.toString, that.toString))
}
- class RequestW(req:Request) {
+ class RequestW(req: Request) {
- def as_model(base:String, lang:String = "RDF/XML-ABBREV"):Handler[Model] =
+ def as_model(base: URL, lang: Lang): Handler[Model] =
req >> { is => modelFromInputStream(is, base, lang).toOption.get }
- def post(body:String):Request =
- (req <<< body).copy(method="POST")
-
- def put(body:String):Request = req <<< body
+ def post(body: String, lang: Lang): Request =
+ post(body, lang.contentType)
+
+ def postSPARQL(body: String): Request =
+ post(body, Post.SPARQL)
- def get_statusCode:Handler[Int] = new Handler(req, (c, r, e) => c, { case t => () })
+ private def post(body: String, contentType: String): Request =
+ (req <:< Map("Content-Type" -> contentType) <<< body).copy(method="POST")
+
+
+ def put(lang: Lang, body: String): Request =
+ req <:< Map("Content-Type" -> lang.contentType) <<< body
+
+ def get_statusCode: Handler[Int] = new Handler(req, (c, r, e) => c, { case t => () })
- def get_header(header:String):Handler[String] = req >:> { _(header).head }
+ def get_header(header: String): Handler[String] = req >:> { _(header).head }
+
+ def get: Request = req.copy(method="GET")
+
+ def get(lang: Lang): Request = req.copy(method="GET") <:< Map("Accept"->lang.contentType)
+
+ def delete: Request = req.copy(method="DELETE")
- def get:Request = req.copy(method="GET")
-
- def >++ [A, B, C] (block: Request => (Handler[A], Handler[B], Handler[C])) = {
+ def >++ [A, B, C] (block: Request => (Handler[A], Handler[B], Handler[C])) = {
Handler(req, { (code, res, opt_ent) =>
val (a, b, c) = block( /\ )
(a.block(code, res, opt_ent), b.block(code,res,opt_ent), c.block(code,res,opt_ent))
} )
}
- def >+ [A, B] (block: Request => (Handler[A], Handler[B])) = {
+ def >+ [A, B] (block: Request => (Handler[A], Handler[B])) = {
Handler(req, { (code, res, opt_ent) =>
val (a, b) = block( /\ )
(a.block(code, res, opt_ent), b.block(code,res,opt_ent))
@@ -69,7 +82,7 @@
}
- implicit def wrapRequest(req:Request):RequestW = new RequestW(req)
+ implicit def wrapRequest(req: Request): RequestW = new RequestW(req)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test_www/.meta.n3 Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,23 @@
+@prefix acl: <http://www.w3.org/ns/auth/acl#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix : <#> .
+
+:a1 a acl:Authorization;
+ acl:accessTo <foaf.n3>;
+ acl:mode acl:Write;
+ acl:agent <https://localhost:8443/2012/foaf.n3#joe> .
+
+:a2 a acl:Authorization;
+ acl:accessTo <private.n3>;
+ acl:mode acl:Write, acl:Read;
+ acl:agent <https://localhost:8443/2012/foaf.n3#joe> .
+
+:readAll a acl:Authorization;
+ acl:accessTo <hello.n3>;
+ acl:mode acl:Read;
+ acl:agentClass foaf:Agent .
+
+:readAll a acl:Authorization;
+ acl:accessTo <foaf.n3>;
+ acl:mode acl:Read;
+ acl:agentClass foaf:Agent .
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test_www/foaf.n3 Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,18 @@
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix cert: <http://www.w3.org/ns/auth/cert#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+@prefix : <#> .
+
+<> a foaf:PersonalProfileDocument;
+ foaf:primaryTopic :joe .
+
+:joe a foaf:Person;
+ foaf:name "John Doe";
+ foaf:knows <http://bblfish.net/people/henry/card#me> ;
+ cert:key [
+ rdfs:comment "create using https://my-profile.eu/certgen.php on 23 May 2012";
+ cert:modulus "ad8751acee3204b7285d2e519e5ef9774f7e34e4e50500a1a1c2752948c7a4b285072d93d012d6453b5bf170a70c10ef3d64482286099a127711283e54eee1cf1c8e1aafa2233ad29cad1d1677b34c1f45ea2f296e522423777fd4b463d922de5f016711adc24177e4755e27ba4fb178a1c4b4689845763e6d6c2d32a5ffeddf9f5fadb9c8e2e7b2a7e86d6c6642d5ae8d9fc7a82c57ac0cd75b797c8386dcb223e6ba938358ab31acddf35beea5fc5e965acf705dd848740c3d17772001419dfca5a7672e29dafa130d2d37f79ed262a58c98b5f3172704d73d0c91e8f6bb046c7d623fe6be1b56199f96bf9fac559607a01445e1198618433659209cf4c919"^^xsd:hexBinary;
+ cert:exponent 65537
+ ] .
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test_www/hello.n3 Wed May 23 23:47:37 2012 +0200
@@ -0,0 +1,5 @@
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+
+<> a foaf:Document ;
+ foaf:topic "Hello World!" .
+