├── README.md ├── build ├── sbt-launch-0.7.4.jar └── sbt-launch.jar ├── config ├── TwitterStreamer.conf ├── kafka │ └── server.properties ├── log4j │ └── log4j.properties ├── sensei │ └── chirper │ │ ├── custom-facets.xml │ │ ├── plugins.xml │ │ ├── schema.xml │ │ └── sensei.properties ├── voldemort │ └── config │ │ ├── cluster.xml │ │ ├── server.properties │ │ └── stores.xml └── zookeeper │ └── zoo.cfg ├── lib ├── bobo-browse-2.5.0.jar ├── configgy-1.5.2.jar ├── je-4.0.92.jar ├── jetty-6.1.18.jar ├── jetty-util-6.1.18.jar ├── kafka-0.05.jar ├── log4j.jar ├── norbert-cluster-2.8.0-0.5.1.jar ├── norbert-java-cluster-2.8.0-0.5.1.jar ├── norbert-java-network-2.8.0-0.5.1.jar ├── norbert-network-2.8.0-0.5.1.jar ├── scalmert_2.8.0-0.1.0.jar ├── sensei-0.0.1.jar ├── twitterstreamer_2.8.0-1.0.2.jar ├── velocity-1.6.2.jar ├── voldemort-0.81.jar ├── zkclient-0.1.0.jar ├── zoie-2.5.0.jar └── zookeeper-3.3.0.jar ├── project ├── boot │ ├── sbt.boot.lock │ ├── scala-2.7.7 │ │ ├── lib │ │ │ ├── scala-compiler.jar │ │ │ └── scala-library.jar │ │ └── org.scala-tools.sbt │ │ │ └── sbt │ │ │ └── 0.7.4 │ │ │ ├── classpath_2.7.7-0.7.4.jar │ │ │ ├── compile_2.7.7-0.7.4.jar │ │ │ ├── compiler-interface-bin_2.7.7.final │ │ │ └── compiler-interface-bin-0.7.4.jar │ │ │ ├── compiler-interface-bin_2.8.0.RC2 │ │ │ └── compiler-interface-bin-0.7.4.jar │ │ │ ├── compiler-interface-src │ │ │ ├── compiler-interface-src-0.7.4.jar │ │ │ └── jline-0.9.94.jar │ │ │ ├── control_2.7.7-0.7.4.jar │ │ │ ├── io_2.7.7-0.7.4.jar │ │ │ ├── ivy-2.1.0.jar │ │ │ ├── ivy_2.7.7-0.7.4.jar │ │ │ ├── jsch-0.1.31.jar │ │ │ ├── launcher-interface-0.7.4.jar │ │ │ ├── sbt_2.7.7-0.7.4.jar │ │ │ ├── test-interface-0.5.jar │ │ │ └── xsbti │ │ │ └── interface-0.7.4.jar │ └── update.log ├── build.properties └── build │ └── ChirperStreamerProject.scala ├── sbt └── src ├── .DS_Store └── main ├── .DS_Store ├── scala ├── .DS_Store └── com │ └── linkedin │ └── chirper │ ├── DefaultConfigs.scala │ ├── frontend │ └── ChirperServlet.scala │ ├── search │ ├── ChirpSearchNode.scala │ ├── ChirperJsonFilter.scala │ └── ChirperQueryBuilderFactory.scala │ ├── services │ ├── KafkaRunner.scala │ ├── VoldemortRunner.scala │ └── ZookeeperRunner.scala │ └── streamer │ ├── ChirpStreamer.scala │ └── ChirperStreamProcessor.scala └── webapp ├── .DS_Store ├── WEB-INF └── web.xml ├── css ├── baseline.css └── styles.css ├── images ├── .DS_Store └── sprite.png ├── index.ssp └── js ├── app.js ├── backbone.js ├── easydate.js ├── jquery.js ├── mustache.js └── underscore.js /README.md: -------------------------------------------------------------------------------- 1 | What is Chirper? 2 | ================== 3 | ([http://javasoze.github.com/chirper/](http://javasoze.github.com/chirper/)) 4 | 5 | Chirper is a real time tweet search engine (written in Scala) using open source technology built by the [LinkedIn SNA team](http://sna-projects.com): 6 | 7 | * [Twitter Streamer](https://github.com/acrosa/Scala-TwitterStreamer) 8 | * [Kafka - Distributed Messaging System](http://sna-projects.com/kafka/) 9 | * [Voldemort - Distribute Key/Value Store](http://sna-projects.com/voldemort/) 10 | * [Sensei - Distributed Realtime Faceted Search System](http://sna-projects.com/sensei/) 11 | 12 | Although the amount of code is minimal, the system can scale horizontally infinitely by leveraging the distributed systems above. See this [blog post](http://sna-projects.com/blog/2011/02/build-a-distributed-realtime-tweet-search-system-in-no-time-part-12/) on design considerations. 13 | 14 | ### Build and run the system: 15 | 16 | From the top level directory, e.g. ~/chirper 17 | 18 | 1. sbt update (do this once to setup the probject) 19 | 2. Make sure your twitter username/password is set in the [config file](https://github.com/javasoze/chirper/blob/master/config/TwitterStreamer.conf) 20 | 3. sbt run 21 | 22 | You will see a list of classes that ca be run: 23 | 24 | Multiple main classes detected, select one to run: 25 | 26 | [1] com.linkedin.chirper.streamer.ChirpStream 27 | [2] com.linkedin.chirper.services.ZookeeperRunner 28 | [3] com.linkedin.chirper.services.KafkaRunner 29 | [4] com.linkedin.chirper.services.VoldemortRunner 30 | [5] com.linkedin.chirper.search.ChirpSearchNode 31 | 32 | Enter number: 33 | 34 | Select a class to run (you'll need to run one per console window) 35 | 36 | The order of class to be run are: 37 | 38 | 1. [2] - Zookeeper 39 | 2. [3] - Kafka 40 | 3. [4] - Voldemort 41 | 4. [1] - Streamer 42 | 5. [5] - Search Node 43 | 44 | Each of the components are pre-configured, details see [configs](https://github.com/javasoze/chirper/tree/master/config). 45 | 46 | The last thing to run is a Restful servlet that interacts with the system (Comes with a beautiful UI): 47 | 48 | chirper$ sbt 49 | [info] Building project Chirper 1.0 against Scala 2.8.0 50 | [info] using ChirperStreamerProject with sbt 0.7.4 and Scala 2.7.7 51 | > jetty-run 52 | 53 | Now you can point to: 54 | 55 | * [Chirp UI - http://localhost:8080](http://localhost:8080) 56 | * [Chirp API - http://localhost:8080/search?q=](http://localhost:8080/search?q=) 57 | 58 | -------------------------------------------------------------------------------- /build/sbt-launch-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/build/sbt-launch-0.7.4.jar -------------------------------------------------------------------------------- /build/sbt-launch.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/build/sbt-launch.jar -------------------------------------------------------------------------------- /config/TwitterStreamer.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Config file for the Streaming Service 3 | # 4 | username = "USERNAME!" 5 | password = "PASSWORD!" 6 | 7 | userAgent = "StreamingClient/1.0 (compatible; Mozilla/5.0; Jakarta Commons-HttpClient/3.1 +http://github.com/acrosa/Scala-TwitterStreamer)" 8 | 9 | twitterStreamUrl = "http://stream.twitter.com/1/statuses/sample.json" 10 | twitterFilterUrl = "http://stream.twitter.com/1/statuses/filter.json" 11 | twitterFirehoseUrl = "http://stream.twitter.com/1/statuses/firehose.json" 12 | twitterLinksUrl = "http://stream.twitter.com/1/statuses/links.json" 13 | twitterRetweetUrl = "http://stream.twitter.com/1/statuses/retweet.json" 14 | 15 | useJmx = true 16 | # the time it takes to timeout when no data is streamed from Twitter 17 | socketTimeout = 60000 18 | 19 | 20 | # chirp specific confs 21 | kafka.host = "localhost" 22 | kafka.port = 9092 23 | 24 | tweet.kafka.topic = "tweets" 25 | 26 | voldemort.url = "tcp://localhost:6666" 27 | tweet.voldemort.store = "tweets" 28 | 29 | sensei.search.spring.url = "http://localhost:18080/sensei-rpc/SenseiSpringRPCService" 30 | 31 | search.perPage = 10 32 | 33 | search.highlight.dohighlight = false 34 | search.highlight.pretag = "" 35 | search.highlight.posttag = "" 36 | 37 | log { 38 | filename = "logs/query.log" 39 | roll = "daily" 40 | level = "info" 41 | } 42 | 43 | -------------------------------------------------------------------------------- /config/kafka/server.properties: -------------------------------------------------------------------------------- 1 | # the id of the broker 2 | brokerid=0 3 | 4 | # number of logical partitions on this broker 5 | num.partitions=1 6 | 7 | # the port the socket server runs on 8 | port=9092 9 | 10 | # the number of processor threads the socket server uses. Defaults to the number of cores on the machine 11 | num.threads=8 12 | 13 | # the directory in which to store log files 14 | log.dir=config/kafka/logs 15 | 16 | # the send buffer used by the socket server 17 | socket.send.buffer=1048576 18 | 19 | # the receive buffer used by the socket server 20 | socket.receive.buffer=1048576 21 | 22 | # the maximum size of a log segment 23 | log.file.size=536870912 24 | 25 | # the interval between running cleanup on the logs 26 | log.cleanup.interval.mins=1 27 | 28 | # the minimum age of a log file to eligible for deletion 29 | log.retention.hours=168 30 | 31 | #the number of messages to accept without flushing the log to disk 32 | log.flush.interval=1000 33 | 34 | #topic.log.flush.interval=tweets:1000,logs:10 35 | 36 | #set the following properties to use zookeeper 37 | 38 | # enable connecting to zookeeper 39 | enable.zookeeper=true 40 | 41 | # zk connection string 42 | # comma separated host:port pairs, each corresponding to a zk 43 | # server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" 44 | zk.connect=localhost:2181 45 | 46 | # timeout in ms for connecting to zookeeper 47 | zk.connectiontimeout.ms=1000000 48 | 49 | # time based topic flush intervals in ms 50 | #topic.flush.intervals.ms=topic:1000 51 | 52 | # default time based flush interval in ms 53 | log.default.flush.interval.ms=2000 54 | 55 | # time based topic flasher time rate in ms 56 | log.default.flush.scheduler.interval.ms=1000 57 | 58 | # topic partition count map 59 | # topic.partition.count.map=topic1:3, topic2:4 60 | -------------------------------------------------------------------------------- /config/log4j/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=INFO, chirper 2 | 3 | log4j.appender.console1=org.apache.log4j.ConsoleAppender 4 | log4j.appender.console1.layout=org.apache.log4j.PatternLayout 5 | log4j.appender.console1.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %p [%c] [%x] %m%n 6 | 7 | log4j.appender.chirper=org.apache.log4j.DailyRollingFileAppender 8 | log4j.appender.chirper.encoding=UTF-8 9 | 10 | log4j.appender.chirper.File=logs/chirper.log 11 | 12 | log4j.appender.chirper.DatePattern='.'yyyy-MM-dd 13 | 14 | log4j.appender.chirper.layout=org.apache.log4j.PatternLayout 15 | log4j.appender.chirper.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %p [%c{1}] [%x] %m%n 16 | 17 | 18 | log4j.appender.sensei=org.apache.log4j.DailyRollingFileAppender 19 | log4j.appender.sensei.encoding=UTF-8 20 | 21 | log4j.appender.sensei.File=logs/sensei-server.log 22 | 23 | log4j.appender.sensei.DatePattern='.'yyyy-MM-dd 24 | 25 | log4j.appender.sensei.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.sensei.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %p [%c{1}] [%x] %m%n 27 | 28 | log4j.appender.voldemort=org.apache.log4j.DailyRollingFileAppender 29 | log4j.appender.voldemort.encoding=UTF-8 30 | 31 | log4j.appender.voldemort.File=logs/voldemort-server.log 32 | 33 | log4j.appender.voldemort.DatePattern='.'yyyy-MM-dd 34 | 35 | log4j.appender.voldemort.layout=org.apache.log4j.PatternLayout 36 | log4j.appender.voldemort.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %p [%c{1}] [%x] %m%n 37 | 38 | log4j.appender.kafka=org.apache.log4j.DailyRollingFileAppender 39 | log4j.appender.kafka.encoding=UTF-8 40 | 41 | log4j.appender.kafka.File=logs/kafka-server.log 42 | 43 | log4j.appender.kafka.DatePattern='.'yyyy-MM-dd 44 | 45 | log4j.appender.kafka.layout=org.apache.log4j.PatternLayout 46 | log4j.appender.kafka.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %p [%c{1}] [%x] %m%n 47 | 48 | 49 | log4j.appender.zookeeper=org.apache.log4j.DailyRollingFileAppender 50 | log4j.appender.zookeeper.encoding=UTF-8 51 | 52 | log4j.appender.zookeeper.File=logs/zookeeper.log 53 | 54 | log4j.appender.zookeeper.DatePattern='.'yyyy-MM-dd 55 | 56 | log4j.appender.zookeeper.layout=org.apache.log4j.PatternLayout 57 | log4j.appender.zookeeper.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %p [%c{1}] [%x] %m%n 58 | 59 | log4j.appender.streamer=org.apache.log4j.DailyRollingFileAppender 60 | log4j.appender.streamer.encoding=UTF-8 61 | 62 | log4j.appender.streamer.File=logs/streamer.log 63 | 64 | log4j.appender.streamer.DatePattern='.'yyyy-MM-dd 65 | 66 | log4j.appender.streamer.layout=org.apache.log4j.PatternLayout 67 | log4j.appender.streamer.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %p [%c{1}] [%x] %m%n 68 | 69 | log4j.logger.voldemort=DEBUG,voldemort 70 | log4j.logger.com.sensei=INFO,sensei 71 | log4j.logger.kafka=INFO,kafka 72 | log4j.logger.com.linkedin.chirper.streamer=DEBUG,streamer 73 | log4j.logger.org.apache.zookeeper=INFO,zookeeper 74 | -------------------------------------------------------------------------------- /config/sensei/chirper/custom-facets.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /config/sensei/chirper/plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /config/sensei/chirper/schema.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 32 | 33 | 34 | 35 |
36 | -------------------------------------------------------------------------------- /config/sensei/chirper/sensei.properties: -------------------------------------------------------------------------------- 1 | # sensei node parameters 2 | sensei.node.id=1 3 | sensei.node.partitions=0,1 4 | 5 | # sensei network server parameters 6 | sensei.server.port=1234 7 | sensei.server.requestThreadCorePoolSize=20 8 | sensei.server.requestThreadMaxPoolSize=70 9 | sensei.server.requestThreadKeepAliveTimeSecs=300 10 | 11 | # sensei cluster parameters 12 | sensei.cluster.name=tweets 13 | sensei.cluster.url=localhost:2181 14 | sensei.cluster.timeout=30000 15 | 16 | # sensei indexing parameters 17 | sensei.index.directory = config/sensei/chirper-index 18 | 19 | sensei.index.batchSize = 10000 20 | sensei.index.batchDelay = 300000 21 | sensei.index.maxBatchSize = 10000 22 | sensei.index.realtime = true 23 | sensei.index.freshness = 1000 24 | 25 | # index manager parameters 26 | 27 | sensei.index.manager.default.maxpartition.id = 1 28 | sensei.index.manager.default.type = kafka 29 | sensei.index.manager.default.kafka.host = localhost 30 | sensei.index.manager.default.kafka.port = 9092 31 | sensei.index.manager.default.kafka.topic = tweets 32 | sensei.index.manager.default.kafka.batchsize = 100 33 | sensei.index.manager.default.filter = tweets-filter 34 | 35 | sensei.query.builder.factory = chirper-query-builder-factory 36 | 37 | 38 | # indexer type, zoie/hourglass/ 39 | 40 | sensei.indexer.type=hourglass 41 | 42 | #extra parameters for hourglass 43 | 44 | sensei.indexer.hourglass.schedule = 00 00 00 45 | 46 | # retention 47 | sensei.indexer.hourglass.timethreshold = 7 48 | 49 | # frequency for a roll, minute/hour/day 50 | sensei.indexer.hourglass.frequency = day 51 | 52 | # sensei 53 | 54 | # extra services 55 | sensei.plugin.services = 56 | 57 | # broker properties 58 | sensei.broker.port = 18080 59 | sensei.broker.minThread = 50 60 | sensei.broker.maxThread = 100 61 | sensei.broker.maxWaittime = 2000 62 | 63 | sensei.broker.webapp.path=src/main/webapp 64 | 65 | sensei.search.cluster.name = tweets 66 | sensei.search.cluster.zookeeper.url = localhost:2181 67 | sensei.search.cluster.zookeeper.conn.timeout = 30000 68 | -------------------------------------------------------------------------------- /config/voldemort/config/cluster.xml: -------------------------------------------------------------------------------- 1 | 2 | mycluster 3 | 4 | 0 5 | localhost 6 | 6061 7 | 6666 8 | 0, 1 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /config/voldemort/config/server.properties: -------------------------------------------------------------------------------- 1 | # The ID of *this* particular cluster node 2 | node.id=0 3 | 4 | max.threads=100 5 | 6 | ############### DB options ###################### 7 | 8 | http.enable=true 9 | socket.enable=true 10 | 11 | # BDB 12 | bdb.write.transactions=false 13 | bdb.flush.transactions=false 14 | bdb.cache.size=50M 15 | 16 | # Mysql 17 | mysql.host=localhost 18 | mysql.port=1521 19 | mysql.user=root 20 | mysql.password=3306 21 | mysql.database=test 22 | 23 | #NIO connector settings. 24 | enable.nio.connector=false 25 | 26 | storage.configs=voldemort.store.bdb.BdbStorageConfiguration, voldemort.store.readonly.ReadOnlyStorageConfiguration 27 | -------------------------------------------------------------------------------- /config/voldemort/config/stores.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | tweets 4 | bdb 5 | client 6 | 1 7 | 1 8 | 1 9 | 10 | string 11 | UTF-8 12 | 13 | 14 | string 15 | UTF-8 16 | 17 | 10 18 | 19 | 20 | -------------------------------------------------------------------------------- /config/zookeeper/zoo.cfg: -------------------------------------------------------------------------------- 1 | # The number of milliseconds of each tick 2 | tickTime=2000 3 | # The number of ticks that the initial 4 | # synchronization phase can take 5 | initLimit=10 6 | # The number of ticks that can pass between 7 | # sending a request and getting an acknowledgement 8 | syncLimit=5 9 | # the directory where the snapshot is stored. 10 | dataDir=config/zookeeper/zoo_data 11 | # the port at which the clients will connect 12 | clientPort=2181 13 | -------------------------------------------------------------------------------- /lib/bobo-browse-2.5.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/bobo-browse-2.5.0.jar -------------------------------------------------------------------------------- /lib/configgy-1.5.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/configgy-1.5.2.jar -------------------------------------------------------------------------------- /lib/je-4.0.92.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/je-4.0.92.jar -------------------------------------------------------------------------------- /lib/jetty-6.1.18.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/jetty-6.1.18.jar -------------------------------------------------------------------------------- /lib/jetty-util-6.1.18.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/jetty-util-6.1.18.jar -------------------------------------------------------------------------------- /lib/kafka-0.05.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/kafka-0.05.jar -------------------------------------------------------------------------------- /lib/log4j.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/log4j.jar -------------------------------------------------------------------------------- /lib/norbert-cluster-2.8.0-0.5.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/norbert-cluster-2.8.0-0.5.1.jar -------------------------------------------------------------------------------- /lib/norbert-java-cluster-2.8.0-0.5.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/norbert-java-cluster-2.8.0-0.5.1.jar -------------------------------------------------------------------------------- /lib/norbert-java-network-2.8.0-0.5.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/norbert-java-network-2.8.0-0.5.1.jar -------------------------------------------------------------------------------- /lib/norbert-network-2.8.0-0.5.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/norbert-network-2.8.0-0.5.1.jar -------------------------------------------------------------------------------- /lib/scalmert_2.8.0-0.1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/scalmert_2.8.0-0.1.0.jar -------------------------------------------------------------------------------- /lib/sensei-0.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/sensei-0.0.1.jar -------------------------------------------------------------------------------- /lib/twitterstreamer_2.8.0-1.0.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/twitterstreamer_2.8.0-1.0.2.jar -------------------------------------------------------------------------------- /lib/velocity-1.6.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/velocity-1.6.2.jar -------------------------------------------------------------------------------- /lib/voldemort-0.81.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/voldemort-0.81.jar -------------------------------------------------------------------------------- /lib/zkclient-0.1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/zkclient-0.1.0.jar -------------------------------------------------------------------------------- /lib/zoie-2.5.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/zoie-2.5.0.jar -------------------------------------------------------------------------------- /lib/zookeeper-3.3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/lib/zookeeper-3.3.0.jar -------------------------------------------------------------------------------- /project/boot/sbt.boot.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/sbt.boot.lock -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/lib/scala-compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/lib/scala-compiler.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/lib/scala-library.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/lib/scala-library.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/classpath_2.7.7-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/classpath_2.7.7-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compile_2.7.7-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compile_2.7.7-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-bin_2.7.7.final/compiler-interface-bin-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-bin_2.7.7.final/compiler-interface-bin-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-bin_2.8.0.RC2/compiler-interface-bin-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-bin_2.8.0.RC2/compiler-interface-bin-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-src/compiler-interface-src-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-src/compiler-interface-src-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-src/jline-0.9.94.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-src/jline-0.9.94.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/control_2.7.7-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/control_2.7.7-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/io_2.7.7-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/io_2.7.7-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/ivy-2.1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/ivy-2.1.0.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/ivy_2.7.7-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/ivy_2.7.7-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/jsch-0.1.31.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/jsch-0.1.31.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/launcher-interface-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/launcher-interface-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/sbt_2.7.7-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/sbt_2.7.7-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/test-interface-0.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/test-interface-0.5.jar -------------------------------------------------------------------------------- /project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/xsbti/interface-0.7.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/xsbti/interface-0.7.4.jar -------------------------------------------------------------------------------- /project/boot/update.log: -------------------------------------------------------------------------------- 1 | setting 'ivy.default.settings.dir' to 'jar:file:/Users/john/bin/sbt-launch-0.7.3.jar!/org/apache/ivy/core/settings' 2 | setting 'ivy.basedir' to '/Users/john/github/chirper/.' 3 | setting 'ivy.default.conf.dir' to 'jar:file:/Users/john/bin/sbt-launch-0.7.3.jar!/org/apache/ivy/core/settings' 4 | impossible to define new type: class not found: org.apache.ivy.plugins.version.PatternVersionMatcher in [] nor Ivy classloader 5 | impossible to define new type: class not found: org.apache.ivy.plugins.trigger.LogTrigger in [] nor Ivy classloader 6 | impossible to define new type: class not found: org.apache.ivy.plugins.resolver.VsftpResolver in [] nor Ivy classloader 7 | impossible to define new type: class not found: org.apache.ivy.plugins.conflict.RegexpConflictManager in [] nor Ivy classloader 8 | impossible to define new type: class not found: org.apache.ivy.plugins.resolver.SshResolver in [] nor Ivy classloader 9 | impossible to define new type: class not found: org.apache.ivy.plugins.resolver.VfsResolver in [] nor Ivy classloader 10 | impossible to define new type: class not found: org.apache.ivy.plugins.resolver.SFTPResolver in [] nor Ivy classloader 11 | impossible to define new type: class not found: org.apache.ivy.plugins.resolver.packager.PackagerResolver in [] nor Ivy classloader 12 | impossible to define new type: class not found: org.apache.ivy.ant.AntCallTrigger in [] nor Ivy classloader 13 | impossible to define new type: class not found: org.apache.ivy.plugins.resolver.IvyRepResolver in [] nor Ivy classloader 14 | impossible to define new type: class not found: org.apache.ivy.ant.AntBuildTrigger in [] nor Ivy classloader 15 | impossible to define glob matcher: org.apache.ivy.plugins.matcher.GlobPatternMatcher was not found. 16 | setting 'java.runtime.name' to 'Java(TM) SE Runtime Environment' 17 | setting 'sun.boot.library.path' to '/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries' 18 | setting 'java.vm.version' to '17.1-b03-307' 19 | setting 'awt.nativeDoubleBuffering' to 'true' 20 | setting 'gopherProxySet' to 'false' 21 | setting 'mrj.build' to '10M3261' 22 | setting 'java.vm.vendor' to 'Apple Inc.' 23 | setting 'java.vendor.url' to 'http://www.apple.com/' 24 | setting 'path.separator' to ':' 25 | setting 'java.vm.name' to 'Java HotSpot(TM) 64-Bit Server VM' 26 | setting 'file.encoding.pkg' to 'sun.io' 27 | setting 'sun.java.launcher' to 'SUN_STANDARD' 28 | setting 'user.country' to 'US' 29 | setting 'sun.os.patch.level' to 'unknown' 30 | setting 'java.vm.specification.name' to 'Java Virtual Machine Specification' 31 | setting 'user.dir' to '/Users/john/github/chirper' 32 | setting 'java.runtime.version' to '1.6.0_22-b04-307-10M3261' 33 | setting 'java.awt.graphicsenv' to 'apple.awt.CGraphicsEnvironment' 34 | setting 'java.endorsed.dirs' to '/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/endorsed' 35 | setting 'os.arch' to 'x86_64' 36 | setting 'java.io.tmpdir' to '/var/folders/TY/TYho7leDFYCRpAlsqFgHc++++TI/-Tmp-/' 37 | setting 'line.separator' to ' 38 | ' 39 | setting 'java.vm.specification.vendor' to 'Sun Microsystems Inc.' 40 | setting 'os.name' to 'Mac OS X' 41 | setting 'sun.jnu.encoding' to 'MacRoman' 42 | setting 'java.library.path' to ':/Applications/YourKit_Java_Profiler_7.5.11.app/bin/mac:.:/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java' 43 | setting 'java.specification.name' to 'Java Platform API Specification' 44 | setting 'java.class.version' to '50.0' 45 | setting 'sun.management.compiler' to 'HotSpot 64-Bit Server Compiler' 46 | setting 'os.version' to '10.6.6' 47 | setting 'http.nonProxyHosts' to 'local|*.local|169.254/16|*.169.254/16' 48 | setting 'user.home' to '/Users/john' 49 | setting 'user.timezone' to 'America/Los_Angeles' 50 | setting 'java.awt.printerjob' to 'apple.awt.CPrinterJob' 51 | setting 'file.encoding' to 'MacRoman' 52 | setting 'java.specification.version' to '1.6' 53 | setting 'java.class.path' to '/Users/john/bin/sbt-launch-0.7.3.jar' 54 | setting 'user.name' to 'john' 55 | setting 'java.vm.specification.version' to '1.0' 56 | setting 'java.home' to '/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home' 57 | setting 'sun.arch.data.model' to '64' 58 | setting 'user.language' to 'en' 59 | setting 'java.specification.vendor' to 'Sun Microsystems Inc.' 60 | setting 'awt.toolkit' to 'apple.awt.CToolkit' 61 | setting 'java.vm.info' to 'mixed mode' 62 | setting 'java.version' to '1.6.0_22' 63 | setting 'java.ext.dirs' to '/Library/Java/Extensions:/System/Library/Java/Extensions:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext' 64 | setting 'sun.boot.class.path' to '/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/jsfd.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar:/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/Resources/Java/JavaRuntimeSupport.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/ui.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/laf.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/sunrsasign.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/jsse.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/jce.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/charsets.jar' 65 | setting 'java.vendor' to 'Apple Inc.' 66 | setting 'file.separator' to '/' 67 | setting 'java.vendor.url.bug' to 'http://bugreport.apple.com/' 68 | setting 'sun.io.unicode.encoding' to 'UnicodeLittle' 69 | setting 'sun.cpu.endian' to 'little' 70 | setting 'mrj.version' to '1060.1.6.0_22-307' 71 | setting 'socksNonProxyHosts' to 'local|*.local|169.254/16|*.169.254/16' 72 | setting 'ftp.nonProxyHosts' to 'local|*.local|169.254/16|*.169.254/16' 73 | setting 'org.apache.commons.logging.Log' to 'org.apache.commons.logging.impl.SimpleLog' 74 | setting 'sun.cpu.isalist' to '' 75 | setting 'ivy.default.ivy.user.dir' to '/Users/john/.ivy2' 76 | setting 'ivy.home' to '/Users/john/.ivy2' 77 | no default ivy user dir defined: set to /Users/john/.ivy2 78 | setting 'ivy.cache.dir' to '/Users/john/.ivy2/cache' 79 | no default cache defined: set to /Users/john/.ivy2/cache 80 | setting 'ivy.basedir' to '/Users/john/github/chirper/project/boot' 81 | setting 'basedir' to '/Users/john/github/chirper/project/boot' 82 | setting 'scala' to '2.8.0' 83 | :: resolving dependencies :: org.scala-tools.sbt#boot-scala;1.0 84 | confs: [default] 85 | validate = true 86 | refresh = false 87 | resolving dependencies for configuration 'default' 88 | == resolving dependencies for org.scala-tools.sbt#boot-scala;1.0 [default] 89 | loadData of org.scala-tools.sbt#boot-scala;1.0 of rootConf=default 90 | == resolving dependencies org.scala-tools.sbt#boot-scala;1.0->org.scala-lang#scala-compiler;2.8.0 [default->default] 91 | loadData of org.scala-lang#scala-compiler;2.8.0 of rootConf=default 92 | using redefined-public to resolve org.scala-lang#scala-compiler;2.8.0 93 | redefined-public: Checking cache for: dependency: org.scala-lang#scala-compiler;2.8.0 {default=[default]} 94 | redefined-public: no namespace defined: using system 95 | No entry is found in the ModuleDescriptorCache : /Users/john/.ivy2/cache/org.scala-lang/scala-compiler/ivy-2.8.0.xml 96 | installing class org.apache.ivy.util.url.IvyAuthenticator 97 | pre 1.3 ivy file: using exactOrRegexp as default matcher 98 | found ivy file in cache for org.scala-lang#scala-compiler;2.8.0 (resolved by redefined-public): /Users/john/.ivy2/cache/org.scala-lang/scala-compiler/ivy-2.8.0.xml 99 | redefined-public: module revision found in cache: org.scala-lang#scala-compiler;2.8.0 100 | redefined-public: no latest strategy defined: using default 101 | found org.scala-lang#scala-compiler;2.8.0 in redefined-public 102 | == resolving dependencies org.scala-tools.sbt#boot-scala;1.0->org.scala-lang#scala-compiler;2.8.0 [default->runtime] 103 | loadData of org.scala-lang#scala-compiler;2.8.0 of rootConf=default 104 | == resolving dependencies org.scala-tools.sbt#boot-scala;1.0->org.scala-lang#scala-compiler;2.8.0 [default->compile] 105 | loadData of org.scala-lang#scala-compiler;2.8.0 of rootConf=default 106 | == resolving dependencies org.scala-lang#scala-compiler;2.8.0->org.scala-lang#scala-library;2.8.0 [compile->master(*)] 107 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 108 | using redefined-public to resolve org.scala-lang#scala-library;2.8.0 109 | redefined-public: Checking cache for: dependency: org.scala-lang#scala-library;2.8.0 {compile=[compile(*), master(*)], runtime=[runtime(*)]} 110 | No entry is found in the ModuleDescriptorCache : /Users/john/.ivy2/cache/org.scala-lang/scala-library/ivy-2.8.0.xml 111 | pre 1.3 ivy file: using exactOrRegexp as default matcher 112 | found ivy file in cache for org.scala-lang#scala-library;2.8.0 (resolved by redefined-public): /Users/john/.ivy2/cache/org.scala-lang/scala-library/ivy-2.8.0.xml 113 | redefined-public: module revision found in cache: org.scala-lang#scala-library;2.8.0 114 | found org.scala-lang#scala-library;2.8.0 in redefined-public 115 | == resolving dependencies org.scala-lang#scala-compiler;2.8.0->org.scala-lang#scala-library;2.8.0 [compile->compile(*)] 116 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 117 | == resolving dependencies org.scala-lang#scala-compiler;2.8.0->org.scala-lang#scala-library;2.8.0 [compile->default] 118 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 119 | == resolving dependencies org.scala-lang#scala-compiler;2.8.0->org.scala-lang#scala-library;2.8.0 [compile->runtime] 120 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 121 | == resolving dependencies org.scala-lang#scala-compiler;2.8.0->org.scala-lang#scala-library;2.8.0 [compile->compile] 122 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 123 | == resolving dependencies org.scala-lang#scala-compiler;2.8.0->org.scala-lang#scala-library;2.8.0 [compile->master] 124 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 125 | == resolving dependencies org.scala-lang#scala-compiler;2.8.0->org.scala-lang#scala-library;2.8.0 [runtime->runtime(*)] 126 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 127 | == resolving dependencies org.scala-lang#scala-compiler;2.8.0->org.scala-lang#scala-library;2.8.0 [runtime->compile] 128 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 129 | default is loaded and no conf to load. Skip loading 130 | == resolving dependencies org.scala-tools.sbt#boot-scala;1.0->org.scala-lang#scala-compiler;2.8.0 [default->master] 131 | loadData of org.scala-lang#scala-compiler;2.8.0 of rootConf=default 132 | == resolving dependencies org.scala-tools.sbt#boot-scala;1.0->org.scala-lang#scala-library;2.8.0 [default->default] 133 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 134 | default is loaded and no conf to load. Skip loading 135 | == resolving dependencies org.scala-tools.sbt#boot-scala;1.0->org.scala-lang#scala-library;2.8.0 [default->runtime] 136 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 137 | default is loaded and no conf to load. Skip loading 138 | == resolving dependencies org.scala-tools.sbt#boot-scala;1.0->org.scala-lang#scala-library;2.8.0 [default->compile] 139 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 140 | default is loaded and no conf to load. Skip loading 141 | == resolving dependencies org.scala-tools.sbt#boot-scala;1.0->org.scala-lang#scala-library;2.8.0 [default->master] 142 | loadData of org.scala-lang#scala-library;2.8.0 of rootConf=default 143 | default is loaded and no conf to load. Skip loading 144 | Nbr of module to sort : 2 145 | Sort dependencies of : org.scala-lang#scala-compiler;2.8.0 / Number of dependencies = 2 146 | Sort dependencies of : org.scala-lang#scala-library;2.8.0 / Number of dependencies = 0 147 | Sort done for : org.scala-lang#scala-library;2.8.0 148 | Sort done for : org.scala-lang#scala-compiler;2.8.0 149 | Module descriptor is processed : org.scala-lang#scala-library;2.8.0 150 | resolved ivy file produced in /Users/john/.ivy2/cache/resolved-org.scala-tools.sbt-boot-scala-1.0.xml 151 | :: downloading artifacts :: 152 | [NOT REQUIRED] org.scala-lang#scala-compiler;2.8.0!scala-compiler.jar 153 | [NOT REQUIRED] org.scala-lang#scala-library;2.8.0!scala-library.jar 154 | :: resolution report :: resolve 281ms :: artifacts dl 24ms 155 | Nbr of module to sort : 2 156 | Sort dependencies of : org.scala-lang#scala-compiler;2.8.0 / Number of dependencies = 2 157 | Sort dependencies of : org.scala-lang#scala-library;2.8.0 / Number of dependencies = 0 158 | Sort done for : org.scala-lang#scala-library;2.8.0 159 | Sort done for : org.scala-lang#scala-compiler;2.8.0 160 | Module descriptor is processed : org.scala-lang#scala-library;2.8.0 161 | report for org.scala-tools.sbt#boot-scala;1.0 default produced in /Users/john/.ivy2/cache/org.scala-tools.sbt-boot-scala-default.xml 162 | resolve done (281ms resolve - 24ms download) 163 | :: retrieving :: org.scala-tools.sbt#boot-scala 164 | checkUpToDate=true 165 | no explicit confs given for retrieve, using ivy file: /Users/john/.ivy2/cache/resolved-org.scala-tools.sbt-boot-scala-1.0.xml 166 | using ivy parser to parse /Users/john/.ivy2/cache/resolved-org.scala-tools.sbt-boot-scala-1.0.xml 167 | pre 1.3 ivy file: using exactOrRegexp as default matcher 168 | confs: [default] 169 | retrieving /Users/john/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.8.0.jar 170 | to /Users/john/github/chirper/project/boot/scala-2.8.0/lib/scala-library.jar 171 | retrieving /Users/john/.ivy2/cache/org.scala-lang/scala-compiler/jars/scala-compiler-2.8.0.jar 172 | to /Users/john/github/chirper/project/boot/scala-2.8.0/lib/scala-compiler.jar 173 | 2 artifacts copied, 0 already retrieved (14484kB/583ms) 174 | retrieve done (583ms) 175 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | #Project properties 2 | #Thu Feb 17 19:10:43 PST 2011 3 | project.organization=com.linkedin 4 | project.name=Chirper 5 | sbt.version=0.7.4 6 | project.version=1.0 7 | build.scala.versions=2.8.0 8 | project.initialize=false 9 | -------------------------------------------------------------------------------- /project/build/ChirperStreamerProject.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | 3 | class ChirperStreamerProject(info: ProjectInfo) extends DefaultWebProject(info) with AutoCompilerPlugins 4 | { 5 | override def useDefaultConfigurations = true 6 | 7 | val httpclient = "commons-httpclient" % "commons-httpclient" % "3.1" 8 | val logging = "commons-logging" % "commons-logging" % "1.1" 9 | val json = "org.json" % "json" % "20080701" 10 | val scalaj_collection = "org.scalaj" %% "scalaj-collection" % "1.0" 11 | 12 | val commonsIo = "commons-io" % "commons-io" % "2.0.1" % "runtime" 13 | val commonsCollection = "commons-collections" % "commons-collections" % "3.2.1" % "runtime" 14 | 15 | val commonsConfiguration = "commons-configuration" % "commons-configuration" % "1.6" % "compile" 16 | 17 | val commonsLang = "commons-lang" % "commons-lang" % "2.5" % "runtime" 18 | val jdom = "org.jdom" % "jdom" % "1.1" % "runtime" 19 | val googleCollections = "com.google.collections" % "google-collections" % "1.0" % "runtime" 20 | 21 | val fastutil = "fastutil" % "fastutil" % "5.0.5" 22 | val lucene = "org.apache.lucene" % "lucene-core" % "3.0.2" 23 | val luceneHighlighter = "org.apache.lucene" % "lucene-highlighter" % "3.0.2" 24 | val kamikaze = "com.linkedin.kamikaze" % "kamikaze" % "3.0.4" % "runtime" 25 | val protobuf = "com.google.protobuf" % "protobuf-java" % "2.3.0" 26 | 27 | val netty = "org.jboss.netty" % "netty" % "3.2.3.Final" % "runtime" 28 | val spring = "org.springframework" % "spring" % "2.5.5" % "compile" 29 | // Logging 30 | System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); 31 | // System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true"); 32 | // System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "debug"); 33 | 34 | // From FE 35 | val jettyVersion = "6.1.22" 36 | val servletVersion = "2.5" 37 | val slf4jVersion = "1.6.0" 38 | val scalatraVersion = "2.0.0-SNAPSHOT" 39 | val scalateVersion = "1.2" 40 | val scalaTestVersion = "1.2-for-scala-2.8.0.final-SNAPSHOT" 41 | 42 | val jetty6 = "org.mortbay.jetty" % "jetty" % jettyVersion % "test" 43 | val servletApi = "javax.servlet" % "servlet-api" % servletVersion % "provided" 44 | 45 | val scalaTest = "org.scalatest" % "scalatest" % scalaTestVersion % "test" 46 | val scalatra = "org.scalatra" %% "scalatra" % scalatraVersion 47 | val scalate = "org.fusesource.scalate" % "scalate-core" % scalateVersion 48 | val scalatraScalate = "org.scalatra" %% "scalatra-scalate" % scalatraVersion 49 | 50 | val sfl4japi = "org.slf4j" % "slf4j-api" % slf4jVersion % "runtime" 51 | val sfl4jnop = "org.slf4j" % "slf4j-nop" % slf4jVersion % "runtime" 52 | 53 | // repositories 54 | val scalaToolsSnapshots = "Scala Tools Repository" at "http://nexus.scala-tools.org/content/repositories/snapshots/" 55 | val sonatypeNexusSnapshots = "Sonatype Nexus Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" 56 | val sonatypeNexusReleases = "Sonatype Nexus Releases" at "https://oss.sonatype.org/content/repositories/releases" 57 | val fuseSourceSnapshots = "FuseSource Snapshot Repository" at "http://repo.fusesource.com/nexus/content/repositories/snapshots" 58 | val jbossReleases = "Jboss releases" at "https://repository.jboss.org/nexus/content/repositories/releases" 59 | 60 | // Show unchecked errors when compiling 61 | override def compileOptions = super.compileOptions ++ Seq(Unchecked) 62 | 63 | override def fork = forkRun("-Xmx100M" :: Nil) 64 | override def runClasspath = super.runClasspath +++ ("config" / "log4j") 65 | } 66 | -------------------------------------------------------------------------------- /sbt: -------------------------------------------------------------------------------- 1 | java -Xmx2048M -jar `dirname $0`/build/sbt-launch.jar "$@" 2 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/src/.DS_Store -------------------------------------------------------------------------------- /src/main/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/src/main/.DS_Store -------------------------------------------------------------------------------- /src/main/scala/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/src/main/scala/.DS_Store -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/DefaultConfigs.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper; 2 | 3 | import com.linkedin.led.twitter.config._ 4 | 5 | import java.nio.charset.Charset 6 | import proj.zoie.impl.indexing.ZoieConfig 7 | 8 | 9 | import org.apache.lucene.analysis.standard.StandardAnalyzer 10 | import org.apache.lucene.queryParser.QueryParser 11 | import org.apache.lucene.queryParser.QueryParser.Operator 12 | import org.apache.lucene.util.Version 13 | 14 | import com.sensei.search.nodes.SenseiQueryBuilderFactory 15 | import com.sensei.search.nodes.impl.DefaultJsonQueryBuilderFactory 16 | 17 | object DefaultConfigs{ 18 | val UTF8Charset = Charset.forName("UTF-8") 19 | 20 | val kafkahost = Config.readString("kafka.host") 21 | val kafkaport = Config.readInt("kafka.port") 22 | 23 | // zoie configuration, use default 24 | val zoieConfig = new ZoieConfig(); 25 | 26 | // voldemort configuration 27 | val voldemortUrl = Config.readString("voldemort.url") 28 | 29 | // query builder 30 | // define query parser builder 31 | val queryParser = new QueryParser(Version.LUCENE_29,"text",new StandardAnalyzer(Version.LUCENE_29)) 32 | queryParser.setDefaultOperator(Operator.AND) 33 | 34 | val queryBuilderFactory = new com.linkedin.chirper.search.ChirperQueryBuilderFactory() 35 | 36 | // highlighting 37 | val formatter = new org.apache.lucene.search.highlight.SimpleHTMLFormatter(Config.readString("search.highlight.pretag"),Config.readString("search.highlight.posttag")) 38 | val encoder = new org.apache.lucene.search.highlight.SimpleHTMLEncoder() 39 | 40 | def addShutdownHook(body: => Unit) = 41 | Runtime.getRuntime.addShutdownHook(new Thread { 42 | override def run { body } 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/frontend/ChirperServlet.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.servlet 2 | 3 | import com.linkedin.led.twitter.config._ 4 | import com.linkedin.chirper.DefaultConfigs 5 | import com.linkedin.chirper.search._ 6 | import javax.servlet._ 7 | import org.scalatra._ 8 | import org.scalatra._ 9 | import org.apache.lucene.search._ 10 | import scalate.ScalateSupport 11 | import org.fusesource.scalate._ 12 | import org.fusesource.scalate.TemplateEngine 13 | import com.sensei.search.req.SenseiRequest 14 | import com.sensei.search.req.StringQuery 15 | import com.sensei.search.svc.api.SenseiService 16 | import com.sensei.search.client.servlet.DefaultSenseiJSONServlet 17 | import voldemort.scalmert.client.StoreClient 18 | import voldemort.client.ClientConfig 19 | import voldemort.client.SocketStoreClientFactory 20 | import voldemort.scalmert.Implicits._ 21 | import voldemort.scalmert.versioning._ 22 | import org.json._ 23 | import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean 24 | import org.apache.lucene.search.highlight._ 25 | import org.apache.commons.lang.StringEscapeUtils 26 | 27 | import org.apache.commons.configuration.DataConfiguration 28 | import org.apache.commons.configuration.web.ServletRequestConfiguration 29 | 30 | import net.lag.logging.Logger 31 | 32 | object ChirperServlet{ 33 | val logger = org.apache.log4j.Logger.getLogger(classOf[ChirperServlet]); 34 | } 35 | 36 | class ChirperServlet extends ScalatraServlet with ScalateSupport { 37 | var t1: Long = 0 38 | var t2: Long = 0 39 | 40 | val log = Logger.get 41 | 42 | 43 | val voldemortStore = Config.readString("tweet.voldemort.store") 44 | 45 | val factory = new SocketStoreClientFactory(new ClientConfig().setBootstrapUrls(DefaultConfigs.voldemortUrl)); 46 | val tweetStore: StoreClient[String, String] = factory.getStoreClient[String, String](voldemortStore) 47 | 48 | val defaultPageSize = Config.readString("search.perPage") 49 | 50 | val doHighlighting = Config.readBoolean("search.highlight.dohighlight") 51 | 52 | 53 | val springInvokerBean = new HttpInvokerProxyFactoryBean() 54 | springInvokerBean.setServiceUrl(Config.readString("sensei.search.spring.url")) 55 | springInvokerBean.setServiceInterface(classOf[SenseiService]) 56 | springInvokerBean.afterPropertiesSet() 57 | val tweetSearchSvc = springInvokerBean.getObject().asInstanceOf[SenseiService] 58 | 59 | before { 60 | t1 = System.currentTimeMillis() 61 | contentType = "application/json; charset=utf-8" 62 | } 63 | 64 | after { 65 | t2 = System.currentTimeMillis() 66 | response.setHeader("X-Runtime", (t2-t1).toString) // Display the time it took to complete the request 67 | } 68 | 69 | /** 70 | * Application Routes 71 | */ 72 | get("/") { 73 | contentType = "text/html" 74 | templateEngine.layout("index.ssp") 75 | } 76 | 77 | get("/search"){ 78 | //log.info(request.getQueryString) 79 | val start = System.currentTimeMillis() 80 | // params 81 | var q = params.getOrElse("q", "").trim() 82 | 83 | val req = DefaultSenseiJSONServlet.convertSenseiRequest(new DataConfiguration(new ServletRequestConfiguration(request))) 84 | 85 | // sort by time 86 | req.addSortField(new SortField("time", SortField.CUSTOM, true)) 87 | 88 | req.setFetchStoredFields(false) 89 | 90 | var highlightScorer : Option[QueryScorer] = None 91 | // Parse a query 92 | if (doHighlighting && q.length()>2){ 93 | try { 94 | val sq = req.getQuery() 95 | val luceneQ = DefaultConfigs.queryBuilderFactory.getQueryBuilder(sq).buildQuery() 96 | highlightScorer = Some(new QueryScorer(luceneQ)) 97 | } catch { 98 | case e: Exception => e.printStackTrace() 99 | } 100 | } 101 | 102 | // do search 103 | val searchStart = System.currentTimeMillis() 104 | val results = tweetSearchSvc.doQuery(req) // no facets for this 105 | val searchEnd = System.currentTimeMillis() 106 | 107 | // build a json object 108 | val resultJSON = DefaultSenseiJSONServlet.buildJSONResult(req,results) 109 | val hitsArray = resultJSON.getJSONArray("hits") 110 | val hitsArrayLen = hitsArray.length() 111 | val fetchStart = System.currentTimeMillis() 112 | var i = 0 113 | while (i < hitsArrayLen){ 114 | val hit = hitsArray.getJSONObject(i) 115 | val uid = hit.getString("uid") 116 | try{ 117 | val statusString = tweetStore(uid) 118 | var statusJsonObj = new JSONObject(); 119 | if (statusString!=null){ 120 | 121 | // go to voldemort store to get the original tweet text for display 122 | val voldObj = new JSONObject(statusString) 123 | val tweetString = voldObj.getString("value") 124 | statusJsonObj = new JSONObject(tweetString) 125 | highlightScorer match { 126 | case Some(x) => { 127 | var text = statusJsonObj.optString("text") 128 | if (text.length()>0){ 129 | text = StringEscapeUtils.escapeHtml(text) 130 | } 131 | val highlighter = new Highlighter(DefaultConfigs.formatter,DefaultConfigs.encoder,x) 132 | val segments = highlighter.getBestFragments(DefaultConfigs.zoieConfig.getAnalyzer(),"contents",text,1) 133 | if (segments.length > 0) text = segments(0) 134 | statusJsonObj.put("text",text) 135 | } 136 | case _ => 137 | } 138 | 139 | hit.put("status",statusJsonObj) 140 | } 141 | } 142 | catch{ 143 | case e : Exception => e.printStackTrace() 144 | } 145 | i+=1 146 | } 147 | val fetchEnd = System.currentTimeMillis() 148 | val end = System.currentTimeMillis() 149 | 150 | 151 | ChirperServlet.logger.info(request.getQueryString+" took: "+(end-start)+"ms") 152 | 153 | resultJSON.put("fetchtime",(fetchEnd-fetchStart)) 154 | resultJSON.put("searchtime",(searchEnd-searchStart)) 155 | resultJSON.put("totaltime",(end-start)) 156 | resultJSON.toString() 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/search/ChirpSearchNode.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.search 2 | 3 | import com.sensei.search.nodes.SenseiServer 4 | 5 | 6 | import java.io.File 7 | 8 | // Build a search node 9 | object ChirpSearchNode{ 10 | def main(args: Array[String]) = { 11 | val params = new Array[String](1) 12 | params(0) = "config/sensei/chirper" 13 | SenseiServer.main(params) 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/search/ChirperJsonFilter.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.search 2 | 3 | import java.text._ 4 | import com.sensei.indexing.api.JsonFilter 5 | import org.json.JSONObject 6 | 7 | class ChirperJsonFilter extends JsonFilter{ 8 | override def filter(obj:JSONObject): JSONObject = { 9 | val date = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy").parse(obj.getString("created_at")) 10 | val time = date.getTime() 11 | obj.put("time",time) 12 | obj 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/search/ChirperQueryBuilderFactory.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.search; 2 | 3 | import org.apache.lucene.analysis.standard.StandardAnalyzer 4 | import org.apache.lucene.queryParser.QueryParser 5 | import org.apache.lucene.queryParser.QueryParser.Operator 6 | import org.apache.lucene.util.Version 7 | 8 | import com.sensei.search.nodes.impl.DefaultJsonQueryBuilderFactory 9 | import com.linkedin.chirper.DefaultConfigs 10 | 11 | class ChirperQueryBuilderFactory extends DefaultJsonQueryBuilderFactory(DefaultConfigs.queryParser){ 12 | } 13 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/services/KafkaRunner.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.services 2 | 3 | import kafka.Kafka 4 | 5 | object KafkaRunner { 6 | def main(args: Array[String]) = { 7 | val params = new Array[String](1) 8 | params(0) = "config/kafka/server.properties" 9 | Kafka.main(params) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/services/VoldemortRunner.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.services 2 | 3 | import voldemort.server.VoldemortServer 4 | 5 | object VoldemortRunner { 6 | def main(args: Array[String]) = { 7 | val params = new Array[String](1) 8 | params(0) = "config/voldemort" 9 | VoldemortServer.main(params) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/services/ZookeeperRunner.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.services 2 | import org.apache.zookeeper.server.quorum.QuorumPeerMain 3 | 4 | object ZookeeperRunner { 5 | def main(args: Array[String]) = { 6 | val params = new Array[String](1) 7 | params(0) = "config/zookeeper/zoo.cfg" 8 | QuorumPeerMain.main(params) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/streamer/ChirpStreamer.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.streamer 2 | 3 | import com.linkedin.chirper.DefaultConfigs 4 | import com.linkedin.led.twitter.config._ 5 | import com.linkedin.led.twitter.streaming.StreamingClient 6 | 7 | // Runner that starts a streamer via Twitter sample API, can be change to pull in other stream types, 8 | // e.g. gardenhost etc. 9 | object ChirpStream { 10 | def main(args: Array[String]) = { 11 | val username = Config.readString("username") 12 | val password = Config.readString("password") 13 | 14 | val processor = new ChirperStreamProcessor() 15 | 16 | DefaultConfigs.addShutdownHook(processor.shutdown()) 17 | val twitterClient = new StreamingClient(username, password, processor) 18 | twitterClient.sample 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/scala/com/linkedin/chirper/streamer/ChirperStreamProcessor.scala: -------------------------------------------------------------------------------- 1 | package com.linkedin.chirper.streamer 2 | 3 | 4 | import java.io.InputStream 5 | import java.io.InputStreamReader 6 | import java.io.BufferedReader 7 | 8 | import org.json._ 9 | 10 | import com.linkedin.led.twitter.config._ 11 | import com.linkedin.led.twitter.streaming.StreamProcessor 12 | 13 | 14 | import kafka.message._ 15 | import kafka.producer._ 16 | import org.apache.log4j.Logger 17 | import voldemort.scalmert.client.StoreClient 18 | import voldemort.client.{SocketStoreClientFactory,ClientConfig} 19 | import voldemort.scalmert.Implicits._ 20 | import voldemort.scalmert.versioning._ 21 | import com.linkedin.chirper.DefaultConfigs 22 | 23 | // processes each tweet from the streamer 24 | class ChirperStreamProcessor extends StreamProcessor{ 25 | 26 | val log = Logger.getLogger(classOf[ChirperStreamProcessor]) 27 | 28 | val kafkaTopic = Config.readString("tweet.kafka.topic") 29 | val voldemortStore = Config.readString("tweet.voldemort.store") 30 | 31 | val factory = new SocketStoreClientFactory(new ClientConfig().setBootstrapUrls(DefaultConfigs.voldemortUrl)); 32 | val tweetStore: StoreClient[String, String] = factory.getStoreClient[String, String](voldemortStore) 33 | val kafkaProducer = new SimpleProducer(DefaultConfigs.kafkahost,DefaultConfigs.kafkaport, 64 * 1024, 100000, 10000) 34 | 35 | def shutdown() = { 36 | kafkaProducer.close() 37 | factory.close() 38 | } 39 | 40 | override def process(is: InputStream): Unit = { 41 | val reader: BufferedReader = new BufferedReader(new InputStreamReader(is,DefaultConfigs.UTF8Charset)) 42 | var line = reader.readLine() 43 | while (line != null) { 44 | // for each tweet 45 | try{ 46 | // output to console 47 | /// println(line) 48 | val jsonObj = new JSONObject(line) 49 | val id = jsonObj.getString("id_str") 50 | // send to voldemort store 51 | tweetStore(id) = line 52 | 53 | val tweetString = tweetStore.get(id) 54 | log.debug("tweetid: "+id) 55 | // send to kafka 56 | kafkaProducer.send(kafkaTopic,new ByteBufferMessageSet(new Message(line.getBytes(DefaultConfigs.UTF8Charset)))) 57 | 58 | } 59 | catch{ 60 | case je: JSONException => je.printStackTrace() 61 | case e: Exception => e.printStackTrace() 62 | } 63 | line = reader.readLine() 64 | } 65 | is.close 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/webapp/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/src/main/webapp/.DS_Store -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | ChirperServlet 9 | com.linkedin.chirper.servlet.ChirperServlet 10 | 1 11 | 12 | dir 13 | /src/main/webapp 14 | 15 | 16 | 17 | 18 | ChirperServlet 19 | /* 20 | 21 | 22 | 23 | default 24 | /images/* 25 | /css/* 26 | /js/* 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/webapp/css/baseline.css: -------------------------------------------------------------------------------- 1 | /* Baseline - a designer framework, Copyright (C) 2009 Stephane Curzi, ProjetUrbain.com, Creative Commons Attribution-Share Alike 3.0 License */ 2 | /* reset */ 3 | html,body,div,span,a,img,h1,h2,h3,h4,h5,h6,hgroup,p,dl,dialog,dt,dd,ol,ul,li,abbr,acronym,address,b,big,blockquote,cite,code,del,dfn,em,i,ins,kbd,pre,q,samp,tt,var,small,strong,sub,sup,object,iframe,form,fieldset,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,footer,header,nav,section,figure,menu,time,mark,audio,video{font-family:inherit;font-size:100%;font-weight:inherit;font-style:inherit;vertical-align:baseline;white-space:normal;text-align:left;margin:0;padding:0;border:0;outline:0;background:transparent}textarea{font-family:inherit;font-size:100%;font-weight:normal;font-style:normal;white-space:normal;text-align:left;margin:0;padding:0}article,aside,footer,header,nav,section,dialog,figure,hgroup,menu{display:block}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}del,ins{text-decoration:none}ol,ul{list-style:none}nav ul{list-style-type:none}table{border-collapse:separate;border-spacing:0;background-color:transparent;width:auto;height:auto}:focus{outline:0}blockquote:before,blockquote:after,q:before,q:after{content:""}blockquote,q{quotes:"" ""}input{margin:0}applet,basefont,dir,font,isindex,menu,s,strike,u{font-family:inherit;font-size:100%;font-weight:normal;font-style:normal;white-space:normal;vertical-align:baseline;text-decoration:inherit;text-align:left;color:inherit;margin:0;padding:0;border:0;outline:0}dir,menu{list-style:none}nobr{white-space:normal}blink{text-decoration:none}marquee{overflow:visible} 4 | /* base */ 5 | body{font-family:helvetica,arial,sans-serif;line-height:1.5;background:white;color:black}h1,h2,h3,h4,h5,h6{line-height:1.2}h4,h5,h6{font-weight:bold}b,strong,caption,th,thead,dt,legend{font-weight:bold}cite,dfn,em,i{font-style:italic}code,kbd,samp,pre,tt,var{font-family:mono-space,monospace}h1,h2,h3,h4,h5,h6{word-spacing:-0.125em}p{word-spacing:0.125em;hyphenate:auto;hyphenate-lines:3}p+p{text-indent:1.5em}p+p.no-indent{text-indent:0}pre{white-space:pre}del{text-decoration:line-through}mark{background:rgba(255, 255, 0, 0.4);padding:0 .25em}ins{color:#f00}small,sup,sub{font-size:80%}big{font-size:125%;line-height:80%}abbr,acronym{font-size:85%;text-transform:uppercase;letter-spacing:.1em}abbr[title],acronym[title],dfn[title]{border-bottom:1px dotted black;cursor:help}sup,sub{line-height:0}sup{vertical-align:super}sub{vertical-align:sub}blockquote{padding:1.5em}hr{border:none;background:#ddd;width:100%}ul,ol{margin-left:1.5em}ul{list-style:disc outside}ol{list-style:decimal outside}input,select,button{cursor:pointer}table{font:inherit;width:100%}article,aside,header,hgroup,nav,figure,section,footer{display:block}.debug{outline:solid gold 1px}.debug-background{background:rgba(255, 215, 0, 0.2) !important} 6 | /* type */ 7 | body{font-size:75%;line-height:1.5}h1,h2,h3,h4,h5,h6{position:relative}h1,h2{line-height:36px;margin-bottom:18px}h1,h2,h3,h4{margin-top:18px}h3,h4,h5,h6{line-height:18px}h1{font-size:36px;top:5px}h2{font-size:28px;top:8px}h3{font-size:22px;top:1px}h4{font-size:18px;top:2px}h5{font-size:15px;top:4px}h6{font-size:13px;top:5px}h1:first-child,h2:first-child,h3:first-child,h4:first-child{margin-top:0}p,pre,address{font-size:13px;line-height:18px;position:relative;top:5px}small{font-size:11px}abbr,code,kbd,samp,small,var{line-height:15px}ul,ol,dl,dialog{font-size:13px;line-height:18px;position:relative;top:5px;margin-top:18px;margin-bottom:18px}li ul,li ol,ul ul,ol ol{top:0;margin-top:0;margin-bottom:0}li h1,li h2,li h3,li h4,li h5,li h6,li p{top:0}form,legend,label{font-size:13px;line-height:18px}legend{position:relative;top:5px}table{font-size:13px}caption{font-size:13px;line-height:18px;position:relative}hr{position:relative;height:4px;margin:18px 0 14px 0} 8 | /* table */ 9 | table{border-collapse:collapse;border-top:solid 3px #000;position:relative;margin-top:18px}th,td{line-height:18px;padding:9px 18px 8px 0}thead th,thead td{padding-top:7px}tfoot th,tfoot td{padding-bottom:8px}tbody th,tbody td,tfoot th,tfoot td{border-top:solid 1px #000} th:first-child,td:first-child{padding-left:0}th:last-child,td:last-child{padding-right:0}tr:nth-child(even) td{}tbody tr:nth-child(odd) th,tbody tr:nth-child(odd) td{background:rgba(0, 0, 0, 0.035)}caption{top:5px;margin-bottom:18px} 10 | /* grid */ 11 | #page{width:990px;position:relative}#page:after{content:".";display:block;height:0;clear:both;visibility:hidden}.column{margin-left:18px;display:block;float:left}.colgroup{display:block;float:left}.first{margin-left:0;clear:left}.gutter{margin-left:18px}.no-gutter{margin-left:0}.align-left{float:left}.align-right{float:right;text-align:right}.clear{float:left}header,section{padding-bottom:18px}.leading{margin-bottom:18px}.noleading{margin-bottom:0 !important}.width1{width:234px}.width2{width:486px}.width3{width:738px}.width4{width:990px;margin-left:0 !important}.full{display:block;float:left;width:100%;margin-left:0 !important}.unitx1{width:108px}.unitx2{width:234px}.unitx3{width:360px}.unitx4{width:486px}.unitx5{width:612px}.unitx6{width:738px}.unitx7{width:864px}.unitx8{width:990px;margin-left:0 !important}.columnsx2{-webkit-column-count:2;-webkit-column-gap:18px;-moz-column-count:2;-moz-column-gap:18px;column-count:2;column-gap:18px}.columnsx4{-webkit-column-count:4;-webkit-column-gap:18px;-moz-column-count:4;-moz-column-gap:18px;column-count:4;column-gap:18px}th.width1,td.width1{width:234px}th.width2,td.width2{width:486px}th.width3,td.width3{width:738px}th.width4,td.width4{width:990px}th.unitx1,th.unitx1{width:108px}th.unitx2,td.unitx2{width:234px}th.unitx3,td.unitx3{width:360px}th.unitx4,td.unitx4{width:486px}th.unitx5,td.unitx5{width:612px}th.unitx6,td.unitx6{width:738px}th.unitx7,td.unitx7{width:864px}th.unitx8,td.unitx8{width:990px}label.width1,label.width2,label.width3,label.width4{margin-left:18px;float:left}label.unitx1,label.unitx2,label.unitx3,label.unitx4,label.unitx5,label.unitx6,label.unitx7,label.unitx8{margin-left:18px;float:left}label.first{margin-left:0}label.width4,label.unitx8{width:990px;overflow:hidden}label.width1 input[type="text"],label.width1 input[type="password"],label.width1 input[type="select"],label.width1 input[type="search"]{width:228px}label.width2 input[type="text"],label.width2 input[type="password"],label.width2 input[type="select"],label.width2 input[type="search"]{width:480px}label.width3 input[type="text"],label.width3 input[type="password"],label.width3 input[type="select"],label.width3 input[type="search"]{width:732px}label.width4 input[type="text"],label.width4 input[type="password"],label.width4 input[type="select"],label.width4 input[type="search"]{width:984px}label.width1 select{width:234px}label.width2 select{width:486px}label.width3 select{width:738px}label.width4 select{width:990px}label.unitx1 input[type="text"],label.unitx1 input[type="password"],label.unitx1 input[type="select"],label.unitx1 input[type="search"]{width:102px}label.unitx2 input[type="text"],label.unitx2 input[type="password"],label.unitx2 input[type="select"],label.unitx2 input[type="search"]{width:228px}label.unitx3 input[type="text"],label.unitx3 input[type="password"],label.unitx3 input[type="select"],label.unitx3 input[type="search"]{width:354px}label.unitx4 input[type="text"],label.unitx4 input[type="password"],label.unitx4 input[type="select"],label.unitx4 input[type="search"]{width:480px}label.unitx5 input[type="text"],label.unitx5 input[type="password"],label.unitx5 input[type="select"],label.unitx5 input[type="search"]{width:606px}label.unitx6 input[type="text"],label.unitx6 input[type="password"],label.unitx6 input[type="select"],label.unitx6 input[type="search"]{width:732px}label.unitx7 input[type="text"],label.unitx7 input[type="password"],label.unitx7 input[type="select"],label.unitx7 input[type="search"]{width:858px}label.unitx8 input[type="text"],label.unitx8 input[type="password"],label.unitx8 input[type="select"],label.unitx8 input[type="search"]{width:984px}label.unitx1 select{width:108px}label.unitx2 select{width:234px}label.unitx3 select{width:360px}label.unitx4 select{width:486px}label.unitx5 select{width:612px}label.unitx6 select{width:738px}label.unitx7 select{width:864px}label.unitx8 select{width:990px} -------------------------------------------------------------------------------- /src/main/webapp/css/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Chirper Styles 3 | */ 4 | body { 5 | background-color: #F3F3F3; 6 | font-family: Helvetica, Arial, sans-serif; 7 | padding: 18px 0; 8 | text-align: center; 9 | } 10 | a { 11 | color: black; 12 | text-decoration: none; 13 | } 14 | #main { 15 | margin: 1em auto; 16 | padding-bottom: 54px; 17 | width: 990px; 18 | } 19 | #main .main-header { 20 | background: url("/images/sprite.png") no-repeat scroll 235px -350px transparent; 21 | height: 108px; 22 | text-align: center; 23 | } 24 | #main h2 { 25 | font-family: 'Puritan', Helvetica, Arial, sans-serif; 26 | } 27 | #main .chirper-search-app .header, #main .chirper-search-tech .header { 28 | display: block; 29 | height: 200px; 30 | } 31 | #main .chirper-search-app, #main .chirper-search-tech { 32 | background-color: #fff; 33 | border: 1px solid #ddd; 34 | box-shadow: 0 1px 1px #ccc; 35 | -webkit-box-shadow: 0 1px 1px #ccc; 36 | -moz-box-shadow: 0 1px 1px #ccc; 37 | height: 1200px; 38 | overflow: hidden; 39 | width: 484px; 40 | } 41 | #main .chirper-search-app .header .about { 42 | color: #666; 43 | float: right; 44 | font-size: 13px; 45 | padding: 18px 27px 18px 18px; 46 | text-align: right; 47 | width: 200px; 48 | } 49 | #main .chirper-search-app { 50 | border-top-left-radius: 8px 8px; 51 | border-bottom-left-radius: 8px 8px; 52 | -moz-border-radius-topleft: 8px; 53 | -moz-border-radius-bottomleft: 8px; 54 | } 55 | #main .chirper-search-app .header { 56 | background: #B5D3F2 url("/images/sprite.png") scroll repeat 0 90px; 57 | -webkit-transition: all 10s linear; 58 | } 59 | #main .chirper-search-tech .header { 60 | background: #FFF url("/images/sprite.png") scroll repeat 35px -150px; 61 | text-indent: -1000px; 62 | } 63 | #main .chirper-search-app .content, #main .chirper-search-tech .content { 64 | padding: 0 27px; 65 | } 66 | #main .chirper-search-app .content #total-tweets { 67 | padding: 9px 0 0 0; 68 | clear: both; 69 | color: #666; 70 | } 71 | #main .chirper-search-app .content form { 72 | padding-top: 18px; 73 | text-align: center; 74 | } 75 | 76 | #main .chirper-search-app .tweet .user { 77 | font-size: 14px; 78 | font-weight: bold; 79 | } 80 | #main .chirper-search-app .tweet .user img { 81 | border-radius: 6px; 82 | float: left; 83 | width: 48px; 84 | height: 48px; 85 | margin-right: 9px; 86 | border-top-left-radius: 6px 6px; 87 | border-top-right-radius: 6px 6px; 88 | border-bottom-right-radius: 6px 6px; 89 | border-bottom-left-radius: 6px 6px; 90 | -moz-border-radius: 6px; 91 | } 92 | #main .chirper-search-app .tweet { 93 | margin-bottom: 18px; 94 | } 95 | #main .chirper-search-app .tweet .ts { 96 | color: #999; 97 | font-size: 12px; 98 | } 99 | #main .chirper-search-tech { 100 | border-top-right-radius: 8px 8px; 101 | border-bottom-right-radius: 8px 8px; 102 | -moz-border-radius-topright: 8px; 103 | -moz-border-radius-bottomright: 8px; 104 | } 105 | #main .chirper-search-tech h1 { 106 | } 107 | #main .chirper-search-app ul, #main .chirper-search-tech ul { 108 | margin-left: 0; 109 | padding-left: 0; 110 | } 111 | #main .chirper-search-tech ul li { 112 | list-style-type: none; 113 | margin-bottom: 36px; 114 | } 115 | #main .chirper-search-tech ul li p a { 116 | display: inline-block; 117 | font-size: 14px; 118 | color: #666; 119 | text-decoration: none; 120 | } 121 | #main .main-divider { 122 | background-color: #EEE; 123 | border-top: 1px solid #ddd; 124 | border-bottom: 1px solid #ddd; 125 | box-shadow: 0 1px 1px #ccc; 126 | height: 1200px; 127 | left: 486px; 128 | position: relative; 129 | -webkit-box-shadow: 0 1px 1px #ccc; 130 | -moz-box-shadow: 0 1px 1px #ccc; 131 | width: 18px; 132 | } 133 | input#q { 134 | background: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#fff)); 135 | background: -moz-linear-gradient(top, #eee, #fff); 136 | border: 1px solid #AAA; 137 | border-radius: 3px; 138 | font-size: 18px; 139 | padding: 6px 9px; 140 | width: 296px; 141 | -webkit-border-radius: 3px; 142 | -moz-border-radius: 3px; 143 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff'); 144 | } 145 | p { 146 | font-family: 'Puritan', Helvetica, Arial, sans-serif; 147 | font-size: 15px; 148 | line-height: 22.5px; 149 | } 150 | 151 | /* 152 | * Credit http://robots.thoughtbot.com/post/2716885147/make-css-buttons-like-a-boss 153 | */ 154 | button { 155 | background: #3b88d8; 156 | background: -moz-linear-gradient(0% 100% 90deg, #377ad0, #52a8e8); 157 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#52a8e8), to(#377ad0)); 158 | border-top: 1px solid #4081af; 159 | border-right: 1px solid #2e69a3; 160 | border-bottom: 1px solid #20559a; 161 | border-left: 1px solid #2e69a3; 162 | -moz-border-radius: 16px; 163 | -webkit-border-radius: 16px; 164 | border-radius: 16px; 165 | -moz-box-shadow: inset 0 1px 0 0 #72b9eb, 0 1px 2px 0 #b3b3b3; 166 | -webkit-box-shadow: inset 0 1px 0 0 #72b9eb, 0 1px 2px 0 #b3b3b3; 167 | color: #fff; 168 | font-family: Helvetica, sans-serif; 169 | font-size: 15px; 170 | font-weight: normal; 171 | line-height: 1; 172 | padding: 3px 0 5px 0; 173 | text-align: center; 174 | text-shadow: 0 -1px 1px #3275bc; 175 | width: 112px; 176 | -webkit-background-clip: padding-box; 177 | } 178 | 179 | button:hover { 180 | background: #2a81d7; 181 | background: -moz-linear-gradient(0% 100% 90deg, #206bcb, #3e9ee5); 182 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#3e9ee5), to(#206bcb)); 183 | border-top: 1px solid #2a73a6; 184 | border-right: 1px solid #165899; 185 | border-bottom: 1px solid #07428f; 186 | border-left: 1px solid #165899; 187 | -moz-box-shadow: inset 0 1px 0 0 #62b1e9; 188 | -webkit-box-shadow: inset 0 1px 0 0 #62b1e9; 189 | cursor: pointer; 190 | text-shadow: 0 -1px 1px #1d62ab; 191 | -webkit-background-clip: padding-box; 192 | } 193 | 194 | button:active { 195 | background: #3282d3; 196 | border: 1px solid #154c8c; 197 | border-bottom: 1px solid #0e408e; 198 | -moz-box-shadow: inset 0 0 6px 3px #1657b5, 0 1px 0 0 #fff; 199 | -webkit-box-shadow: inset 0 0 6px 3px #1657b5, 0 1px 0 0 #fff; 200 | text-shadow: 0 -1px 1px #2361a4; 201 | -webkit-background-clip: padding-box; 202 | } 203 | 204 | button[disabled], 205 | button[disabled]:hover, 206 | button[disabled]:active { 207 | background: #999; 208 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#dadada), to(#f3f3f3)); 209 | border-top: 1px solid #c5c5c5; 210 | border-right: 1px solid #cecece; 211 | border-bottom: 1px solid #d9d9d9; 212 | border-left: 1px solid #cecece; 213 | color: #8f8f8f; 214 | box-shadow: none; 215 | -moz-box-shadow: none; 216 | -webkit-box-shadow: none; 217 | cursor: not-allowed; 218 | text-shadow: 0 -1px 1px #ebebeb; 219 | } 220 | 221 | button::-moz-focus-inner { 222 | border: 0; 223 | padding: 0; 224 | } 225 | .search-button { 226 | margin-left: 18px; 227 | position: relative; 228 | top: -2px; 229 | height: 27px; 230 | width: 90px; 231 | } 232 | 233 | .hl 234 | { 235 | font-weight:bold; 236 | background-color: yellow 237 | } 238 | -------------------------------------------------------------------------------- /src/main/webapp/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/src/main/webapp/images/.DS_Store -------------------------------------------------------------------------------- /src/main/webapp/images/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javasoze/chirper/41432465a837361a8a835a249e925f5a0a3a5675/src/main/webapp/images/sprite.png -------------------------------------------------------------------------------- /src/main/webapp/index.ssp: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Chirper 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 35 | 36 |
37 |
38 | 39 |
40 |
41 |

42 | Type your query in the search box below to search in real-time the indexed stream of tweets. 43 |

44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 |
52 |
    53 |
54 |
55 |
56 | 57 | 58 |
59 |
60 |

The Tools

61 |
62 |
63 |
    64 |
  • 65 |

    SNA

    66 |

    67 | The Search, Network, and Analytics team at LinkedIn works on LinkedIn's information retrieval systems, the social graph system, data driven features, and supporting data infrastructure. This site hosts the open source projects that have been built by members of our team (and our friends). 68 | Learn More.. 69 |

    70 |
  • 71 |
  • 72 |

    Sensei

    73 |

    74 | A distributed searchable database that handles complex semi-structured queries. It can be used to power consumer search systems with rich structured data. 75 | Learn More.. 76 |

    77 |
  • 78 |
  • 79 |

    Voldemort

    80 |

    81 | Is a Distributed key-value store used at LinkedIn for certain high-scalability storage problems where simple functional partitioning is not sufficient. 82 | Learn More.. 83 |

    84 |
  • 85 |
  • 86 |

    Kafka

    87 |

    88 | Provides a publish-subscribe solution that can handle all activity stream data and processing on a consumer-scale web site. 89 | Learn More.. 90 |

    91 |
  • 92 |
  • 93 |

    TweetStreamer

    94 |

    95 | A simple library for the Twitter streaming API, implements the reconnect strategy, and error policies specified on Twitter's documentation. 96 | Learn More.. 97 |

    98 |
  • 99 |
  • 100 |

    And More..

    101 | Scalatra, 102 | Zookeeper, 103 | Scalmert, 104 | Norbert, 105 | Jetty, 106 | Undercore.js, 107 | Backbone.js, 108 | Mustache.js, 109 | JQuery, 110 | Google Font Directory, 111 | and many more. 112 |
  • 113 |
114 |
115 |
116 | 117 |
118 |
119 |
120 | 121 | 122 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /src/main/webapp/js/app.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | /** 3 | * Tweet Model 4 | * It's a JSON object coming from the scalatra servlet response, it inherits from Backbone.Model. 5 | */ 6 | window.Tweet = Backbone.Model.extend({ 7 | }); 8 | 9 | /** 10 | * TweetList 11 | * It's a collection object with some properties and methods that are inherited from Backbone.Collection. 12 | */ 13 | var TweetList = Backbone.Collection.extend({ 14 | 15 | model: Tweet, // The model we are storing inside the collection, defined previously. 16 | 17 | url: "/search", // JSON endpoint that returns the list of results. 18 | 19 | // We want to redefine the parse function from Backbone because we are storing custom fields like the time it took to search, and the number of documents. 20 | parse: function(resp) { 21 | this.total = resp.totaldocs; 22 | this.numhits = resp.numhits; 23 | this.totaltime = resp.totaltime; 24 | this.query = resp.parsedquery; 25 | this.models = resp.hits; 26 | return resp.hits; 27 | } 28 | }); 29 | window.Tweets = new TweetList(); 30 | 31 | /** 32 | * TweetView 33 | * A view that represents a tweet model. 34 | */ 35 | window.TweetView = Backbone.View.extend({ 36 | 37 | // A tweet is represented as a
  • element. 38 | tag: "li", 39 | 40 | initialize: function() { 41 | this.model.bind('change', this.render); // If we update the collection of tweets, we should re-render the view automatically. 42 | this.model.view = this; // Just in case we want to reference the view in the model. 43 | }, 44 | 45 | render: function() { 46 | $(this.el).html(Mustache.to_html($('#tweet-view').html(), this.model.toJSON())); // Takes the Mustache template from "#tweet-view", and renders the Model. 47 | return this; // We always return this on render so we can chain calls. 48 | } 49 | }); 50 | 51 | /** 52 | * AppView 53 | * A view that represents the Application. 54 | */ 55 | window.AppView = Backbone.View.extend({ 56 | 57 | // We define the DOM element that contains the application 58 | el: $("#chirper-search-app"), 59 | 60 | // We move the clouds every 10 seconds, we want to hold a reference for the interval on the view. 61 | cloudsInterval: undefined, 62 | 63 | // Setup event listeners such as when the user types something on the search box, we want ot trigger a search to the server. 64 | events: { 65 | "keyup #q": "search", 66 | "click button": "search" 67 | }, 68 | 69 | initialize: function() { 70 | // Bindings for updating the view when the collection changes, etc. 71 | _.bindAll(this, 'addAll', 'render'); 72 | Tweets.bind('refresh', this.addAll); 73 | Tweets.bind('all', this.render); 74 | 75 | // On initalize, let's fetch the inital list of tweets with an empty search. 76 | Tweets.fetch(); 77 | 78 | // We are not really going to fire a search for each keystroke, so we need to wait until the user stops typing (300ms) and then fire the search. 79 | this.timeout = undefined; 80 | this.delay = 300; 81 | this.isLoading = false; 82 | 83 | // Clouds movement 84 | this.cloudsInterval = setInterval(this.refreshUIElements, 10000); 85 | this.totalInterval = setInterval(this.refreshTotalCount, 4000); 86 | this.refreshUIElements(); 87 | }, 88 | 89 | refreshUIElements: function() { 90 | // Refresh clouds 91 | var div = $("#chirper-search-app .header").css("background-position-x"); 92 | var x_position = div.substring(0, div.length - 2); 93 | $("#chirper-search-app .header").css("background-position-x", (parseInt(x_position, 10) + 50) + "px"); 94 | // Refresh dates x seconds ago, etc. after rendering. 95 | $(".ts").easydate({ live: false }); 96 | }, 97 | 98 | refreshTotalCount: function() { 99 | // Refresh total hit count periodically 100 | $.get('/search?offset=0&count=0', function(data) { // we setup offset=0 and count=0 beacuase it makes the search on the backend more efficient. We just want the absolute totals. 101 | $('#total-tweets').html("Indexed "+ data.totaldocs + " tweets"); 102 | }); 103 | }, 104 | 105 | render: function() { 106 | $("#search-form").submit(function() { return false; }); // Don't submit the form, use live JS search. 107 | }, 108 | 109 | addAll: function() { 110 | this.$("#tweets").html(""); 111 | Tweets.each(this.addTweet); // For all the tweets in the collection, render them on the list. 112 | $(".ts").easydate({ live: false }); // Live update timestamps x seconds ago, etc. 113 | }, 114 | 115 | addTweet: function(tweet) { 116 | var view = new TweetView({ model: tweet }); // Get the mustache template for the tweet and render it accordingly. 117 | this.$("#tweets").append(view.render().el); 118 | }, 119 | 120 | // This function is kinda tricky at first sight. We are actually not running a search everytime the user types a letter, we wait until the user stops typing (300ms) and then after that fire the search event. 121 | search: function() { 122 | var that = this; 123 | if(!that.isLoading) { // If we are not loading a search already 124 | that.timeout = setTimeout(function() { 125 | that.isLoading = true; 126 | Tweets.url = "/search?q="+ this.$("#q").val(); // Let's update the collection url with the extra params we want to send (the search term) 127 | Tweets.fetch({ 128 | success: function() { 129 | that.isLoading = false; // After we fetched the results, we should allow new searches. 130 | $('#found-tweets').html("Found "+ Tweets.numhits +" tweets in ("+ Tweets.totaltime +" ms )") 131 | } 132 | }); 133 | }, that.delay); // Wait before performing the search, the user might want to type more. 134 | } else { 135 | // "Already there's a search in progress..just wait 136 | } 137 | } 138 | }); 139 | 140 | $(document).ready(function() { // Only run after everything loads on the page. 141 | window.App = new AppView; // Let's run it! 142 | }); 143 | }); 144 | -------------------------------------------------------------------------------- /src/main/webapp/js/backbone.js: -------------------------------------------------------------------------------- 1 | // Backbone.js 0.3.3 2 | // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc. 3 | // Backbone may be freely distributed under the MIT license. 4 | // For all details and documentation: 5 | // http://documentcloud.github.com/backbone 6 | (function(){var e;e=typeof exports!=="undefined"?exports:this.Backbone={};e.VERSION="0.3.3";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var h=this.jQuery||this.Zepto;e.emulateHTTP=false;e.emulateJSON=false;e.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=0,g=c.length;d/g,">").replace(/"/g, 9 | """)},set:function(a,b){b||(b={});if(!a)return this;if(a.attributes)a=a.attributes;var c=this.attributes,d=this._escapedAttributes;if(!b.silent&&this.validate&&!this._performValidation(a,b))return false;if("id"in a)this.id=a.id;for(var g in a){var i=a[g];if(!f.isEqual(c[g],i)){c[g]=i;delete d[g];if(!b.silent){this._changed=true;this.trigger("change:"+g,this,i,b)}}}!b.silent&&this._changed&&this.change(b);return this},unset:function(a,b){b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&& 10 | !this._performValidation(c,b))return false;delete this.attributes[a];delete this._escapedAttributes[a];if(!b.silent){this._changed=true;this.trigger("change:"+a,this,void 0,b);this.change(b)}return this},clear:function(a){a||(a={});var b=this.attributes,c={};for(attr in b)c[attr]=void 0;if(!a.silent&&this.validate&&!this._performValidation(c,a))return false;this.attributes={};this._escapedAttributes={};if(!a.silent){this._changed=true;for(attr in b)this.trigger("change:"+attr,this,void 0,a);this.change(a)}return this}, 11 | fetch:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("read",this,function(d){if(!b.set(b.parse(d),a))return false;a.success&&a.success(b,d)},c);return this},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return false;var c=this,d=j(b.error,c,b),g=this.isNew()?"create":"update";(this.sync||e.sync)(g,this,function(i){if(!c.set(c.parse(i),b))return false;b.success&&b.success(c,i)},d);return this},destroy:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("delete", 12 | this,function(d){b.collection&&b.collection.remove(b);a.success&&a.success(b,d)},c);return this},url:function(){var a=k(this.collection);if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+this.id},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return!this.id},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=false},hasChanged:function(a){if(a)return this._previousAttributes[a]!= 13 | this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=false,d;for(d in a)if(!f.isEqual(b[d],a[d])){c=c||{};c[d]=a[d]}return c},previous:function(a){if(!a||!this._previousAttributes)return null;return this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},_performValidation:function(a,b){var c=this.validate(a);if(c){b.error?b.error(this,c):this.trigger("error",this,c,b);return false}return true}}); 14 | e.Collection=function(a,b){b||(b={});if(b.comparator){this.comparator=b.comparator;delete b.comparator}this._boundOnModelEvent=f.bind(this._onModelEvent,this);this._reset();a&&this.refresh(a,{silent:true});this.initialize(a,b)};f.extend(e.Collection.prototype,e.Events,{model:e.Model,initialize:function(){},toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c').hide().appendTo("body")[0].contentWindow; 22 | "onhashchange"in window&&!a?h(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);return this.loadUrl()},route:function(a,b){this.handlers.push({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();if(a==this.fragment&&this.iframe)a=this.getFragment(this.iframe.location);if(a==this.fragment||a==decodeURIComponent(this.fragment))return false;if(this.iframe)window.location.hash=this.iframe.location.hash=a;this.loadUrl()},loadUrl:function(){var a=this.fragment= 23 | this.getFragment();return f.any(this.handlers,function(b){if(b.route.test(a)){b.callback(a);return true}})},saveLocation:function(a){a=(a||"").replace(l,"");if(this.fragment!=a){window.location.hash=this.fragment=a;if(this.iframe&&a!=this.getFragment(this.iframe.location)){this.iframe.document.open().close();this.iframe.location.hash=a}}}});e.View=function(a){this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize(a)};var q=/^(\w+)\s*(.*)$/;f.extend(e.View.prototype,e.Events, 24 | {tagName:"div",$:function(a){return h(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){h(this.el).remove();return this},make:function(a,b,c){a=document.createElement(a);b&&h(a).attr(b);c&&h(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events)){h(this.el).unbind();for(var b in a){var c=a[b],d=b.match(q),g=d[1];d=d[2];c=f.bind(this[c],this);d===""?h(this.el).bind(g,c):h(this.el).delegate(d,g,c)}}},_configure:function(a){if(this.options)a=f.extend({}, 25 | this.options,a);if(a.model)this.model=a.model;if(a.collection)this.collection=a.collection;if(a.el)this.el=a.el;if(a.id)this.id=a.id;if(a.className)this.className=a.className;if(a.tagName)this.tagName=a.tagName;this.options=a},_ensureElement:function(){if(!this.el){var a={};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});var m=function(a,b){var c=r(this,a,b);c.extend=m;return c};e.Model.extend=e.Collection.extend=e.Controller.extend=e.View.extend= 26 | m;var s={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,b,c,d){var g=s[a];a=a==="create"||a==="update"?JSON.stringify(b.toJSON()):null;b={url:k(b),type:g,contentType:"application/json",data:a,dataType:"json",processData:false,success:c,error:d};if(e.emulateJSON){b.contentType="application/x-www-form-urlencoded";b.processData=true;b.data=a?{model:a}:{}}if(e.emulateHTTP)if(g==="PUT"||g==="DELETE"){if(e.emulateJSON)b.data._method=g;b.type="POST";b.beforeSend=function(i){i.setRequestHeader("X-HTTP-Method-Override", 27 | g)}}h.ajax(b)};var n=function(){},r=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};n.prototype=a.prototype;d.prototype=new n;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},k=function(a){if(!(a&&a.url))throw Error("A 'url' property or function must be specified");return f.isFunction(a.url)?a.url():a.url},j=function(a,b,c){return function(d){a?a(b,d):b.trigger("error",b,d,c)}}})(); -------------------------------------------------------------------------------- /src/main/webapp/js/easydate.js: -------------------------------------------------------------------------------- 1 | (function($) 2 | { 3 | /* 4 | * jQuery EasyDate 0.2.4 ($Rev: 54 $) 5 | * Copyright (c) 2009 Parsha Pourkhomami (parshap@gmail.com) 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | $.easydate = { }; 10 | $.easydate.locales = { }; 11 | $.easydate.locales.enUS = { 12 | "future_format": "%s %t", 13 | "past_format": "%t %s", 14 | "second": "second", 15 | "seconds": "seconds", 16 | "minute": "minute", 17 | "minutes": "minutes", 18 | "hour": "hour", 19 | "hours": "hours", 20 | "day": "day", 21 | "days": "days", 22 | "week": "week", 23 | "weeks": "weeks", 24 | "month": "month", 25 | "months": "months", 26 | "year": "year", 27 | "years": "years", 28 | "yesterday": "yesterday", 29 | "tomorrow": "tomorrow", 30 | "now": "just now", 31 | "ago": "ago", 32 | "in": "in" 33 | }; 34 | 35 | var defaults = { 36 | live: true, 37 | set_title: true, 38 | format_future: true, 39 | format_past: true, 40 | units: [ 41 | { name: "now", limit: 5 }, 42 | { name: "second", limit: 60, in_seconds: 1 }, 43 | { name: "minute", limit: 3600, in_seconds: 60 }, 44 | { name: "hour", limit: 86400, in_seconds: 3600 }, 45 | { name: "yesterday", limit: 172800, past_only: true }, 46 | { name: "tomorrow", limit: 172800, future_only: true }, 47 | { name: "day", limit: 604800, in_seconds: 86400 }, 48 | { name: "week", limit: 2629743, in_seconds: 604800 }, 49 | { name: "month", limit: 31556926, in_seconds: 2629743 }, 50 | { name: "year", limit: Infinity, in_seconds: 31556926 } 51 | ], 52 | uneasy_format: function(date) 53 | { 54 | return date.toLocaleDateString(); 55 | }, 56 | locale: $.easydate.locales.enUS 57 | }; 58 | 59 | // Difference (in milliseconds) between the local system time and the time 60 | // that should be used as "now". This is set by using set_now. 61 | var now_diff = 0; 62 | 63 | // A mapping of unique element IDs of elements that are waiting to be 64 | // updated to the ID of the timeout returned by setTimeOut. 65 | var updates = {}; 66 | 67 | // A la updates, but contains element IDs for elements that are paused. 68 | var paused_updates = {}; 69 | 70 | // A mapping of unique element IDs to the jQuery DOM elements it 71 | // represents. 72 | var elements = {}; 73 | 74 | function __(str, value, settings) 75 | { 76 | if(!isNaN(value) && value != 1) 77 | str = str + "s"; 78 | return settings.locale[str] || str; 79 | } 80 | 81 | // Pauses live updates of elements matching the given selector. If the 82 | // selector argument is omitted then all updating will be paused. 83 | var pause = $.easydate.pause = function(selector) 84 | { 85 | var p = function(element_id) 86 | { 87 | clearTimeout(updates[element_id]); 88 | delete updates[element_id]; 89 | paused_updates[element_id] = true; 90 | }; 91 | 92 | if(!selector) 93 | { 94 | for(var element_id in updates) 95 | p(element_id) 96 | } 97 | else 98 | { 99 | $(selector).each(function() 100 | { 101 | var element_id = jQuery.data(this); 102 | if(!isNaN(updates[element_id])) 103 | p(element_id); 104 | }); 105 | } 106 | }; 107 | 108 | // Pauses updates on paused elements matching the given selector. If no 109 | // selector is provided, all updates will be resumed. 110 | var resume = $.easydate.resume = function(selector) 111 | { 112 | var r = function(element_id) 113 | { 114 | delete paused_updates[element_id]; 115 | update_time(elements[element_id]); 116 | }; 117 | 118 | if(!selector) 119 | { 120 | for(var element_id in paused_updates) 121 | r(element_id); 122 | } 123 | else 124 | { 125 | $(selector).each(function() 126 | { 127 | var element_id = jQuery.data(this); 128 | if(!isNaN(paused_updates[element_id])) 129 | r(element_id); 130 | }); 131 | } 132 | }; 133 | 134 | // Makes all future time calculations relative to the given date argument 135 | // instead of the system clock. The date argument can be a JavaScript Date 136 | // object or a RFC 1123 valid timestamp string. This is useful for 137 | // synchronizing the user's clock with a server-side clock. 138 | var set_now = $.easydate.set_now = function(date) 139 | { 140 | var time; 141 | if(date instanceof Date) 142 | time = date.getTime(); 143 | else 144 | time = Date.parse(date); 145 | 146 | if(isNaN(time)) 147 | return; 148 | 149 | now_diff = time - (new Date()).getTime(); 150 | 151 | // Re-adjust any previously formatted dates. 152 | for(var element_id in elements) 153 | { 154 | if(!isNaN[updates[element_id]]) 155 | clearTimeout(updates[element_id]); 156 | update_time(elements[element_id]); 157 | } 158 | }; 159 | 160 | var get_now = $.easydate.get_now = function() 161 | { 162 | var now = new Date(); 163 | now.setTime(now.getTime() + now_diff); 164 | return now; 165 | }; 166 | 167 | // Formats a Date object to a human-readable localized string. 168 | var format_date = $.easydate.format_date = function(date, options) 169 | { 170 | var settings = $.extend({}, defaults, options); 171 | 172 | var diff = ((get_now().getTime() - date.getTime()) / 1000); 173 | var diff_abs = Math.abs(diff); 174 | 175 | if(isNaN(diff)) 176 | return; 177 | 178 | // Return if we shouldn't format this date because it is in the past 179 | // or future and our setting does not allow it. 180 | if((!settings.format_future && diff < 0) || 181 | (!settings.format_past && diff > 0)) 182 | return; 183 | 184 | for(var i in settings.units) 185 | { 186 | var unit = settings.units[i]; 187 | 188 | // Skip this unit if it's for past dates only and this is a future 189 | // date, or if it's for future dates only and this is a past date. 190 | if((unit.past_only && diff < 0) || (unit.future_only && diff > 0)) 191 | continue; 192 | 193 | if(diff_abs < unit.limit) 194 | { 195 | // Case for units that are not really measurement units - e.g., 196 | // "yesterday" or "now". 197 | if(isNaN(unit.in_seconds)) 198 | return __(unit.name, NaN, settings); 199 | 200 | var val = diff_abs / unit.in_seconds; 201 | val = Math.round(val); 202 | var format_string; 203 | if(diff < 0) 204 | format_string = __("future_format", NaN, settings) 205 | .replace("%s", __("in", NaN, settings)) 206 | else 207 | format_string = __("past_format", NaN, settings) 208 | .replace("%s", __("ago", NaN, settings)) 209 | return format_string 210 | .replace("%t", val + " " + __(unit.name, val, settings)); 211 | } 212 | } 213 | 214 | // The date does not fall into any units' limits - use uneasy format. 215 | return settings.uneasy_format(date); 216 | } 217 | 218 | // Returns how long (in milliseconds) the timout until the next update for 219 | // the given date should be. 220 | function get_timeout_delay(date, settings) 221 | { 222 | var now = get_now(); 223 | var diff = ((now.getTime() - date.getTime()) / 1000); 224 | var diff_abs = Math.abs(diff); 225 | 226 | if(isNaN(diff)) 227 | return; 228 | 229 | var last_limit = 0; 230 | for(var i in settings.units) 231 | { 232 | var unit = settings.units[i]; 233 | 234 | // Skip this unit if it's for past dates only and this is a future 235 | // date, or if it's for future dates only and this is a past date. 236 | if((unit.past_only && diff < 0) || (unit.future_only && diff > 0)) 237 | continue; 238 | 239 | if(diff_abs < unit.limit) 240 | { 241 | // @todo: check edge cases (diff == 0) 242 | if(isNaN(unit.in_seconds)) 243 | { 244 | // This is not a real unit of time, so only update once we 245 | // pass the limit of this unit. 246 | if(diff < 0) 247 | return (last_limit - diff_abs) * 1000 + 100; 248 | else 249 | return (unit.limit - diff_abs) * 1000 + 100; 250 | } 251 | else 252 | { 253 | // Real unit of time - update every tick of this time unit. 254 | if(diff < 0) 255 | return (diff_abs % unit.in_seconds) * 1000 + 100 256 | else 257 | return (unit.in_seconds - (diff_abs % unit.in_seconds)) * 258 | 1000 + 100 259 | } 260 | } 261 | last_limit = unit.limit; 262 | } 263 | 264 | // Date is out of range of all units' limits. If this is a future date, 265 | // update once the date comes in range of a future unit. 266 | if(diff < 0) 267 | { 268 | for(var i = settings.units.length - 1; i >= 0; i--) 269 | { 270 | var unit = settings.units[i]; 271 | 272 | if(unit.past_only) 273 | continue; 274 | 275 | return (unit.limit - diff_abs) * 1000 + 100 276 | } 277 | } 278 | } 279 | 280 | // Returns a date object for the date represented by the given DOM element 281 | // from the following sources (in order): 282 | // 1) element.data("easydate.date") (in case we previously cached it) 283 | // 2) DOM element's title (if it is a valid RFC 1123 timestamp) 284 | // 3) DOM element's innerHTML (if it is a valid RFC 1123 timestamp) 285 | function get_date(element, settings) 286 | { 287 | var date = element.data("easydate.date"); 288 | 289 | if(isNaN(date)) 290 | { 291 | var timestamp; 292 | var time = Date.parse(timestamp = element.attr("title")) || 293 | Date.parse(timestamp = element.html()); 294 | if(!isNaN(time)) 295 | { 296 | date = new Date(); 297 | date.setTime(time); 298 | element.data("easydate.date", date); 299 | if(settings.set_title && !element.attr("title")) 300 | element.attr("title", timestamp); 301 | } 302 | } 303 | 304 | return date; 305 | } 306 | 307 | // Updates the given element's innerHTML based on the time it represents. 308 | function update_time(element) 309 | { 310 | var settings = element.data("easydate.settings"); 311 | 312 | var element_id = $.data(element[0]); 313 | elements[element_id] = element; 314 | delete updates[element_id]; 315 | 316 | var date = get_date(element, settings); 317 | 318 | if(isNaN(date)) 319 | return; 320 | 321 | element.html(format_date(date, settings)); 322 | 323 | if(settings.live) 324 | { 325 | var timeout = get_timeout_delay(date, settings); 326 | if(!isNaN(timeout)) 327 | { 328 | if(timeout > 2147483647) 329 | timeout = 2147483647; // max Firefox timeout delay 330 | 331 | var id = setTimeout( 332 | function() { update_time(element); }, 333 | Math.round(timeout) 334 | ); 335 | updates[element_id] = id; 336 | } 337 | } 338 | } 339 | 340 | $.fn.easydate = function(options) 341 | { 342 | var settings = $.extend({}, defaults, options); 343 | this.data("easydate.settings", settings); 344 | 345 | // Clear any cached dates in case the timestamp has been updated since 346 | // the last easydate() call on any of these elements. 347 | this.removeData("easydate.date"); 348 | 349 | this.each(function() 350 | { 351 | // Make sure that we aren't updating the element multiple times in 352 | // case easydate() was called on the same element more than once. 353 | var element_id = $.data(this); 354 | if(!isNaN(updates[element_id])) 355 | { 356 | clearTimeout(updates[element_id]); 357 | delete updates[element_id]; 358 | } 359 | 360 | update_time($(this)); 361 | }); 362 | }; 363 | 364 | })(jQuery); -------------------------------------------------------------------------------- /src/main/webapp/js/jquery.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery JavaScript Library v1.5 3 | * http://jquery.com/ 4 | * 5 | * Copyright 2011, John Resig 6 | * Dual licensed under the MIT or GPL Version 2 licenses. 7 | * http://jquery.org/license 8 | * 9 | * Includes Sizzle.js 10 | * http://sizzlejs.com/ 11 | * Copyright 2011, The Dojo Foundation 12 | * Released under the MIT, BSD, and GPL Licenses. 13 | * 14 | * Date: Mon Jan 31 08:31:29 2011 -0500 15 | */ 16 | (function(a,b){function b$(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function bX(a){if(!bR[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bR[a]=c}return bR[a]}function bW(a,b){var c={};d.each(bV.concat.apply([],bV.slice(0,b)),function(){c[this]=a});return c}function bJ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f=a.converters,g,h=e.length,i,j=e[0],k,l,m,n,o;for(g=1;g=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(q,"`").replace(r,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,p,q=[],r=[],s=d._data(this,u);typeof s==="function"&&(s=s.events);if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;ic)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,p=f.handleObj.origHandler.apply(f.elem,arguments);if(p===!1||a.isPropagationStopped()){c=f.level,p===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function C(a,b,c){c[0].type=a;return d.event.handle.apply(b,c)}function w(){return!0}function v(){return!1}function f(a,c,f){if(f===b&&a.nodeType===1){f=a.getAttribute("data-"+c);if(typeof f==="string"){try{f=f==="true"?!0:f==="false"?!1:f==="null"?null:d.isNaN(f)?e.test(f)?d.parseJSON(f):f:parseFloat(f)}catch(g){}d.data(a,c,f)}else f=b}return f}var c=a.document,d=function(){function I(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(I,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,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=navigator.userAgent,w,x=!1,y,z="then done fail isResolved isRejected promise".split(" "),A,B=Object.prototype.toString,C=Object.prototype.hasOwnProperty,D=Array.prototype.push,E=Array.prototype.slice,F=String.prototype.trim,G=Array.prototype.indexOf,H={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5",length:0,size:function(){return this.length},toArray:function(){return E.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 e=this.constructor();d.isArray(a)?D.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),y.done(a);return this},eq:function(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(E.apply(this,arguments),"slice",E.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:D,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,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"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=!0;if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",A,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",A),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&I()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):H[B.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!C.call(a,"constructor")&&!C.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||C.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");e.type="text/javascript",d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g1?(g=Array(c),d.each(b,function(a,b){d.when(b).then(function(b){g[a]=arguments.length>1?E.call(arguments,0):b,--c||e.resolveWith(f,g)},e.reject)})):e!==a&&e.resolve(a);return f},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)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),y=d._Deferred(),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){H["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),G&&(d.inArray=function(a,b){return G.call(b,a)}),i.test(" ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?A=function(){c.removeEventListener("DOMContentLoaded",A,!1),d.ready()}:c.attachEvent&&(A=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",A),d.ready())});return a.jQuery=a.$=d}();(function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML="
    a";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option"));if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:b.getElementsByTagName("input")[0].value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,_scriptEval:null,noCloneEvent:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0},g.disabled=!0,d.support.optDisabled=!h.disabled,d.support.scriptEval=function(){if(d.support._scriptEval===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();e.type="text/javascript";try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(d.support._scriptEval=!0,delete a[f]):d.support._scriptEval=!1,b.removeChild(e),b=e=f=null}return d.support._scriptEval};try{delete b.test}catch(i){d.support.deleteExpando=!1}b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function j(){d.support.noCloneEvent=!1,b.detachEvent("onclick",j)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="";var k=c.createDocumentFragment();k.appendChild(b.firstChild),d.support.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",b.removeChild(a).style.display="none",a=e=null}});var l=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function"),b=null;return d};d.support.submitBubbles=l("submit"),d.support.changeBubbles=l("change"),b=e=f=null}})();var e=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.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?d.cache[a[d.expando]]:a[d.expando];return!!a&&!d.isEmptyObject(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={}),typeof c==="object"&&(f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c)),i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,g=b.nodeType,h=g?d.cache:b,i=g?b[d.expando]:d.expando;if(!h[i])return;if(c){var j=e?h[i][f]:h[i];if(j){delete j[c];if(!d.isEmptyObject(j))return}}if(e){delete h[i][f];if(!d.isEmptyObject(h[i]))return}var k=h[i][f];d.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},h[i][f]=k):g&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var g=this[0].attributes,h;for(var i=0,j=g.length;i-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,j=c.type==="select-one";if(f<0)return null;for(var k=j?f:0,l=j?f+1:h.length;k=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=j.test(c);if(c==="selected"&&!d.support.optSelected){var n=a.parentNode;n&&(n.selectedIndex,n.parentNode&&n.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&k.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var o=a.getAttributeNode("tabIndex");return o&&o.specified?o.value:l.test(a.nodeName)||m.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var p=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return p===null?b:p}h&&(a[c]=e);return a[c]}});var o=/\.(.*)$/,p=/^(?:textarea|input|select)$/i,q=/\./g,r=/ /g,s=/[^\w\s.|`]/g,t=function(a){return a.replace(s,"\\$&")},u="events";d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a);if(f===!1)f=v;else if(!f)return;var h,i;f.handler&&(h=f,f=h.handler),f.guid||(f.guid=d.guid++);var j=d._data(c);if(!j)return;var k=j[u],l=j.handle;typeof k==="function"?(l=k.handle,k=k.events):k||(c.nodeType||(j[u]=j=function(){}),j.events=k={}),l||(j.handle=l=function(){return typeof d!=="undefined"&&!d.event.triggered?d.event.handle.apply(l.elem,arguments):b}),l.elem=c,e=e.split(" ");var m,n=0,o;while(m=e[n++]){i=h?d.extend({},h):{handler:f,data:g},m.indexOf(".")>-1?(o=m.split("."),m=o.shift(),i.namespace=o.slice(0).sort().join(".")):(o=[],i.namespace=""),i.type=m,i.guid||(i.guid=f.guid);var p=k[m],q=d.event.special[m]||{};if(!p){p=k[m]=[];if(!q.setup||q.setup.call(c,g,o,l)===!1)c.addEventListener?c.addEventListener(m,l,!1):c.attachEvent&&c.attachEvent("on"+m,l)}q.add&&(q.add.call(c,i),i.handler.guid||(i.handler.guid=f.guid)),p.push(i),d.event.global[m]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=v);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),w=s&&s[u];if(!s||!w)return;typeof w==="function"&&(s=w,w=w.events),c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in w)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),t).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=w[h];if(!p)continue;if(!e){for(j=0;j=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=e.nodeType?d._data(e,"handle"):(d._data(e,u)||{}).handle;h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(o,""),n=d.nodeName(l,"a")&&m==="click",p=d.event.special[m]||{};if((!p._default||p._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=!0,l[m]())}catch(q){}k&&(l["on"+m]=k),d.event.triggered=!1}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,u),typeof i==="function"&&(i=i.events),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},B=function B(a){var c=a.target,e,f;if(p.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=A(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f){a.type="change",a.liveFired=b;return d.event.trigger(a,arguments[1],c)}}};d.event.special.change={filters:{focusout:B,beforedeactivate:B,click:function(a){var b=a.target,c=b.type;if(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")return B.call(this,a)},keydown:function(a){var b=a.target,c=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")return B.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",A(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in z)d.event.add(this,c+".specialChange",z[c]);return p.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return p.test(this.nodeName)}},z=d.event.special.change.filters,z.focus=z.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function c(a){a=d.event.fix(a),a.type=b;return d.event.handle.call(this,a)}d.event.special[b]={setup:function(){this.addEventListener(a,c,!0)},teardown:function(){this.removeEventListener(a,c,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function s(a,b,c,d,e,f){for(var g=0,h=d.length;g0){k=j;break}}j=j[a]}d[g]=k}}}function r(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0;[0,0].sort(function(){h=!1;return 0});var i=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var l,m,o,p,q,r,s,u,v=!0,w=i.isXML(d),x=[],y=b;do{a.exec(""),l=a.exec(y);if(l){y=l[3],x.push(l[1]);if(l[2]){p=l[3];break}}}while(l);if(x.length>1&&k.exec(b))if(x.length===2&&j.relative[x[0]])m=t(x[0]+x[1],d);else{m=j.relative[x[0]]?[d]:i(x.shift(),d);while(x.length)b=x.shift(),j.relative[b]&&(b+=x.shift()),m=t(b,m)}else{!g&&x.length>1&&d.nodeType===9&&!w&&j.match.ID.test(x[0])&&!j.match.ID.test(x[x.length-1])&&(q=i.find(x.shift(),d,w),d=q.expr?i.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:n(g)}:i.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),m=q.expr?i.filter(q.expr,q.set):q.set,x.length>0?o=n(m):v=!1;while(x.length)r=x.pop(),s=r,j.relative[r]?s=x.pop():r="",s==null&&(s=d),j.relative[r](o,s,w)}else o=x=[]}o||(o=m),o||i.error(r||b);if(f.call(o)==="[object Array]")if(v)if(d&&d.nodeType===1)for(u=0;o[u]!=null;u++)o[u]&&(o[u]===!0||o[u].nodeType===1&&i.contains(d,o[u]))&&e.push(m[u]);else for(u=0;o[u]!=null;u++)o[u]&&o[u].nodeType===1&&e.push(m[u]);else e.push.apply(e,o);else n(o,e);p&&(i(p,h,e,g),i.uniqueSort(e));return e};i.uniqueSort=function(a){if(p){g=h,a.sort(p);if(g)for(var b=1;b0},i.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=j.order.length;e":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!/\W/.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(/\\/g,"")},TAG:function(a,b){return a[1].toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||i.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]&&i.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(/\\/g,"");!f&&j.attrMap[g]&&(a[1]=j.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(/\\/g,""),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]=i(b[3],null,null,c);else{var g=i.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(j.match.POS.test(b[0])||j.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.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!i(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},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||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},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 bc[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=j.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||i.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,k=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||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=j.attrHandle[c]?j.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":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=j.setFilters[e];if(f)return f(a,c,b,d)}}},k=j.match.POS,l=function(a,b){return"\\"+(b-0+1)};for(var m in j.match)j.match[m]=new RegExp(j.match[m].source+/(?![^\[]*\])(?![^\(]*\))/.source),j.leftMatch[m]=new RegExp(/(^(?:.|\r|\n)*?)/.source+j.match[m].source.replace(/\\(\d+)/g,l));var n=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(o){n=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(j.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:[]}},j.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&&(j.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.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(j.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=i,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){i=function(b,e,f,g){e=e||c;if(!g&&!i.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return n(e.getElementsByTagName(b),f);if(h[2]&&j.find.CLASS&&e.getElementsByClassName)return n(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return n([e.body],f);if(h&&h[3]){var k=e.getElementById(h[3]);if(!k||!k.parentNode)return n([],f);if(k.id===h[3])return n([k],f)}try{return n(e.querySelectorAll(b),f)}catch(l){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e.getAttribute("id"),o=m||d,p=e.parentNode,q=/^\s*[+~]/.test(b);m?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),q&&p&&(e=e.parentNode);try{if(!q||p)return n(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(r){}finally{m||e.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)i[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector,d=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(e){d=!0}b&&(i.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!i.isXML(a))try{if(d||!j.match.PSEUDO.test(c)&&!/!=/.test(c))return b.call(a,c)}catch(e){}return i(c,null,null,[a]).length>0})}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;j.order.splice(1,0,"CLASS"),j.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?i.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?i.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:i.contains=function(){return!1},i.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var t=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=j.match.PSEUDO.exec(a))e+=c[0],a=a.replace(j.match.PSEUDO,"");a=j.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(var g=c;g0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=L.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(N(c[0])||N(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=K.call(arguments);G.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!M[a]?d.unique(f):f,(this.length>1||I.test(e))&&H.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},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 P=/ jQuery\d+="(?:\d+|null)"/g,Q=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,S=/<([\w:]+)/,T=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};X.optgroup=X.option,X.tbody=X.tfoot=X.colgroup=X.caption=X.thead,X.th=X.td,d.support.htmlSerialize||(X._default=[1,"div
    ","
    "]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(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 d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(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(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(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=d(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,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!0:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(P,""):null;if(typeof a!=="string"||V.test(a)||!d.support.leadingWhitespace&&Q.test(a)||X[(S.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(R,"<$1>");try{for(var c=0,e=this.length;c1&&l0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if(!d.support.noCloneEvent&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){f=a.getElementsByTagName("*"),g=e.getElementsByTagName("*");for(h=0;f[h];++h)$(f[h],g[h]);$(a,e)}if(b){Z(a,e);if(c&&"getElementsByTagName"in a){f=a.getElementsByTagName("*"),g=e.getElementsByTagName("*");if(f.length)for(h=0;f[h];++h)Z(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||U.test(i)){if(typeof i==="string"){i=i.replace(R,"<$1>");var j=(S.exec(i)||["",""])[1].toLowerCase(),k=X[j]||X._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=T.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]===""&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&Q.test(i)&&m.insertBefore(b.createTextNode(Q.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var ba=/alpha\([^)]*\)/i,bb=/opacity=([^)]*)/,bc=/-([a-z])/ig,bd=/([A-Z])/g,be=/^-?\d+(?:px)?$/i,bf=/^-?\d/,bg={position:"absolute",visibility:"hidden",display:"block"},bh=["Left","Right"],bi=["Top","Bottom"],bj,bk,bl,bm=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bj(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bj)return bj(a,c,g)},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]},camelCase:function(a){return a.replace(bc,bm)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bn(a,b,e):d.swap(a,bg,function(){f=bn(a,b,e)});if(f<=0){f=bj(a,b,b),f==="0px"&&bl&&(f=bl(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!be.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return bb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=ba.test(f)?f.replace(ba,e):c.filter+" "+e}}),c.defaultView&&c.defaultView.getComputedStyle&&(bk=function(a,c,e){var f,g,h;e=e.replace(bd,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bl=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!be.test(d)&&bf.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bj=bk||bl,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var bo=/%20/g,bp=/\[\]$/,bq=/\r?\n/g,br=/#.*$/,bs=/^(.*?):\s*(.*?)\r?$/mg,bt=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bu=/^(?:GET|HEAD)$/,bv=/^\/\//,bw=/\?/,bx=/)<[^<]*)*<\/script>/gi,by=/^(?:select|textarea)/i,bz=/\s+/,bA=/([?&])_=[^&]*/,bB=/^(\w+:)\/\/([^\/?#:]+)(?::(\d+))?/,bC=d.fn.load,bD={},bE={};d.fn.extend({load:function(a,b,c){if(typeof a!=="string"&&bC)return bC.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}var g="GET";b&&(d.isFunction(b)?(c=b,b=null):typeof b==="object"&&(b=d.param(b,d.ajaxSettings.traditional),g="POST"));var h=this;d.ajax({url:a,type:g,dataType:"html",data:b,complete:function(a,b,e){e=a.responseText,a.isResolved()&&(a.done(function(a){e=a}),h.html(f?d("
    ").append(e.replace(bx,"")).find(f):e)),c&&h.each(c,[e,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||by.test(this.nodeName)||bt.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(bq,"\r\n")}}):{name:b.name,value:c.replace(bq,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,b){d[b]=function(a,c,e,f){d.isFunction(c)&&(f=f||e,e=c,c=null);return d.ajax({type:b,url:a,data:c,success:e,dataType:f})}}),d.extend({getScript:function(a,b){return d.get(a,null,b,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a){d.extend(!0,d.ajaxSettings,a),a.context&&(d.ajaxSettings.context=a.context)},ajaxSettings:{url:location.href,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","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bF(bD),ajaxTransport:bF(bE),ajax:function(a,e){function w(a,c,e,l){if(t!==2){t=2,p&&clearTimeout(p),o=b,m=l||"",v.readyState=a?4:0;var n,q,r,s=e?bI(f,v,e):b,u,w;if(a>=200&&a<300||a===304){if(f.ifModified){if(u=v.getResponseHeader("Last-Modified"))d.lastModified[f.url]=u;if(w=v.getResponseHeader("Etag"))d.etag[f.url]=w}if(a===304)c="notmodified",n=!0;else try{q=bJ(f,s),c="success",n=!0}catch(x){c="parsererror",r=x}}else r=c,a&&(c="error",a<0&&(a=0));v.status=a,v.statusText=c,n?i.resolveWith(g,[q,c,v]):i.rejectWith(g,[v,c,r]),v.statusCode(k),k=b,f.global&&h.trigger("ajax"+(n?"Success":"Error"),[v,f,n?q:r]),j.resolveWith(g,[v,c]),f.global&&(h.trigger("ajaxComplete",[v,f]),--d.active||d.event.trigger("ajaxStop"))}}typeof e!=="object"&&(e=a,a=b),e=e||{};var f=d.extend(!0,{},d.ajaxSettings,e),g=(f.context=("context"in e?e:d.ajaxSettings).context)||f,h=g===f?d.event:d(g),i=d.Deferred(),j=d._Deferred(),k=f.statusCode||{},l={},m,n,o,p,q=c.location,r=q.protocol||"http:",s,t=0,u,v={readyState:0,setRequestHeader:function(a,b){t===0&&(l[a.toLowerCase()]=b);return this},getAllResponseHeaders:function(){return t===2?m:null},getResponseHeader:function(a){var b;if(t===2){if(!n){n={};while(b=bs.exec(m))n[b[1].toLowerCase()]=b[2]}b=n[a.toLowerCase()]}return b||null},abort:function(a){a=a||"abort",o&&o.abort(a),w(0,a);return this}};i.promise(v),v.success=v.done,v.error=v.fail,v.complete=j.done,v.statusCode=function(a){if(a){var b;if(t<2)for(b in a)k[b]=[k[b],a[b]];else b=a[v.status],v.then(b,b)}return this},f.url=(""+(a||f.url)).replace(br,"").replace(bv,r+"//"),f.dataTypes=d.trim(f.dataType||"*").toLowerCase().split(bz),f.crossDomain||(s=bB.exec(f.url.toLowerCase()),f.crossDomain=s&&(s[1]!=r||s[2]!=q.hostname||(s[3]||(s[1]==="http:"?80:443))!=(q.port||(r==="http:"?80:443)))),f.data&&f.processData&&typeof f.data!=="string"&&(f.data=d.param(f.data,f.traditional)),bG(bD,f,e,v),f.type=f.type.toUpperCase(),f.hasContent=!bu.test(f.type),f.global&&d.active++===0&&d.event.trigger("ajaxStart");if(!f.hasContent){f.data&&(f.url+=(bw.test(f.url)?"&":"?")+f.data);if(f.cache===!1){var x=d.now(),y=f.url.replace(bA,"$1_="+x);f.url=y+(y===f.url?(bw.test(f.url)?"&":"?")+"_="+x:"")}}if(f.data&&f.hasContent&&f.contentType!==!1||e.contentType)l["content-type"]=f.contentType;f.ifModified&&(d.lastModified[f.url]&&(l["if-modified-since"]=d.lastModified[f.url]),d.etag[f.url]&&(l["if-none-match"]=d.etag[f.url])),l.accept=f.dataTypes[0]&&f.accepts[f.dataTypes[0]]?f.accepts[f.dataTypes[0]]+(f.dataTypes[0]!=="*"?", */*; q=0.01":""):f.accepts["*"];for(u in f.headers)l[u.toLowerCase()]=f.headers[u];if(!f.beforeSend||f.beforeSend.call(g,v,f)!==!1&&t!==2){for(u in {success:1,error:1,complete:1})v[u](f[u]);o=bG(bE,f,e,v);if(o){t=v.readyState=1,f.global&&h.trigger("ajaxSend",[v,f]),f.async&&f.timeout>0&&(p=setTimeout(function(){v.abort("timeout")},f.timeout));try{o.send(l,w)}catch(z){status<2?w(-1,z):d.error(z)}}else w(-1,"No Transport")}else w(0,"abort"),v=!1;return v},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery)d.each(a,function(){f(this.name,this.value)});else for(var g in a)bH(g,a[g],c,f);return e.join("&").replace(bo,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bK=d.now(),bL=/(\=)\?(&|$)|()\?\?()/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bK++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){e=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bL.test(b.url)||e&&bL.test(b.data))){var f,g=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h=a[g],i=b.url,j=b.data,k="$1"+g+"$2";b.jsonp!==!1&&(i=i.replace(bL,k),b.url===i&&(e&&(j=j.replace(bL,k)),b.data===j&&(i+=(/\?/.test(i)?"&":"?")+b.jsonp+"="+g))),b.url=i,b.data=j,a[g]=function(a){f=[a]},b.complete=[function(){a[g]=h;if(h)f&&d.isFunction(h)&&a[g](f[0]);else try{delete a[g]}catch(b){}},b.complete],b.converters["script json"]=function(){f||d.error(g+" was not called");return f[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript"},contents:{script:/javascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=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(!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 bM=d.now(),bN={},bO,bP;d.ajaxSettings.xhr=a.ActiveXObject?function(){if(a.location.protocol!=="file:")try{return new a.XMLHttpRequest}catch(b){}try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(c){}}:function(){return new a.XMLHttpRequest};try{bP=d.ajaxSettings.xhr()}catch(bQ){}d.support.ajax=!!bP,d.support.cors=bP&&"withCredentials"in bP,bP=b,d.support.ajax&&d.ajaxTransport(function(b){if(!b.crossDomain||d.support.cors){var c;return{send:function(e,f){bO||(bO=1,d(a).bind("unload",function(){d.each(bN,function(a,b){b.onreadystatechange&&b.onreadystatechange(1)})}));var g=b.xhr(),h;b.username?g.open(b.type,b.url,b.async,b.username,b.password):g.open(b.type,b.url,b.async),(!b.crossDomain||b.hasContent)&&!e["x-requested-with"]&&(e["x-requested-with"]="XMLHttpRequest");try{d.each(e,function(a,b){g.setRequestHeader(a,b)})}catch(i){}g.send(b.hasContent&&b.data||null),c=function(a,e){if(c&&(e||g.readyState===4)){c=0,h&&(g.onreadystatechange=d.noop,delete bN[h]);if(e)g.readyState!==4&&g.abort();else{var i=g.status,j,k=g.getAllResponseHeaders(),l={},m=g.responseXML;m&&m.documentElement&&(l.xml=m),l.text=g.responseText;try{j=g.statusText}catch(n){j=""}i=i===0?!b.crossDomain||j?k?304:0:302:i==1223?204:i,f(i,j,l,k)}}},b.async&&g.readyState!==4?(h=bM++,bN[h]=g,g.onreadystatechange=c):c()},abort:function(){c&&c(0,1)}}}});var bR={},bS=/^(?:toggle|show|hide)$/,bT=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,bU,bV=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(bW("show",3),a,b,c);for(var g=0,h=this.length;g=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:bW("show",1),slideUp:bW("hide",1),slideToggle:bW("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},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={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.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(d.css(this.elem,this.prop));return a||0},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||"px",this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!bU&&(bU=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b
    ";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),a=b=e=f=g=h=null,d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=e==="absolute"&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.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):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=bZ.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!bZ.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=b$(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=b$(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}})})(window); -------------------------------------------------------------------------------- /src/main/webapp/js/mustache.js: -------------------------------------------------------------------------------- 1 | /* 2 | mustache.js — Logic-less templates in JavaScript 3 | 4 | See http://mustache.github.com/ for more info. 5 | */ 6 | 7 | var Mustache = function() { 8 | var Renderer = function() {}; 9 | 10 | Renderer.prototype = { 11 | otag: "{{", 12 | ctag: "}}", 13 | pragmas: {}, 14 | buffer: [], 15 | pragmas_implemented: { 16 | "IMPLICIT-ITERATOR": true 17 | }, 18 | context: {}, 19 | 20 | render: function(template, context, partials, in_recursion) { 21 | // reset buffer & set context 22 | if(!in_recursion) { 23 | this.context = context; 24 | this.buffer = []; // TODO: make this non-lazy 25 | } 26 | 27 | // fail fast 28 | if(!this.includes("", template)) { 29 | if(in_recursion) { 30 | return template; 31 | } else { 32 | this.send(template); 33 | return; 34 | } 35 | } 36 | 37 | template = this.render_pragmas(template); 38 | var html = this.render_section(template, context, partials); 39 | if(in_recursion) { 40 | return this.render_tags(html, context, partials, in_recursion); 41 | } 42 | 43 | this.render_tags(html, context, partials, in_recursion); 44 | }, 45 | 46 | /* 47 | Sends parsed lines 48 | */ 49 | send: function(line) { 50 | if(line != "") { 51 | this.buffer.push(line); 52 | } 53 | }, 54 | 55 | /* 56 | Looks for %PRAGMAS 57 | */ 58 | render_pragmas: function(template) { 59 | // no pragmas 60 | if(!this.includes("%", template)) { 61 | return template; 62 | } 63 | 64 | var that = this; 65 | var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + 66 | this.ctag); 67 | return template.replace(regex, function(match, pragma, options) { 68 | if(!that.pragmas_implemented[pragma]) { 69 | throw({message: 70 | "This implementation of mustache doesn't understand the '" + 71 | pragma + "' pragma"}); 72 | } 73 | that.pragmas[pragma] = {}; 74 | if(options) { 75 | var opts = options.split("="); 76 | that.pragmas[pragma][opts[0]] = opts[1]; 77 | } 78 | return ""; 79 | // ignore unknown pragmas silently 80 | }); 81 | }, 82 | 83 | /* 84 | Tries to find a partial in the curent scope and render it 85 | */ 86 | render_partial: function(name, context, partials) { 87 | name = this.trim(name); 88 | if(!partials || partials[name] === undefined) { 89 | throw({message: "unknown_partial '" + name + "'"}); 90 | } 91 | if(typeof(context[name]) != "object") { 92 | return this.render(partials[name], context, partials, true); 93 | } 94 | return this.render(partials[name], context[name], partials, true); 95 | }, 96 | 97 | /* 98 | Renders inverted (^) and normal (#) sections 99 | */ 100 | render_section: function(template, context, partials) { 101 | if(!this.includes("#", template) && !this.includes("^", template)) { 102 | return template; 103 | } 104 | 105 | var that = this; 106 | // CSW - Added "+?" so it finds the tighest bound, not the widest 107 | var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag + 108 | "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag + 109 | "\\s*", "mg"); 110 | 111 | // for each {{#foo}}{{/foo}} section do... 112 | return template.replace(regex, function(match, type, name, content) { 113 | var value = that.find(name, context); 114 | if(type == "^") { // inverted section 115 | if(!value || that.is_array(value) && value.length === 0) { 116 | // false or empty list, render it 117 | return that.render(content, context, partials, true); 118 | } else { 119 | return ""; 120 | } 121 | } else if(type == "#") { // normal section 122 | if(that.is_array(value)) { // Enumerable, Let's loop! 123 | return that.map(value, function(row) { 124 | return that.render(content, that.create_context(row), 125 | partials, true); 126 | }).join(""); 127 | } else if(that.is_object(value)) { // Object, Use it as subcontext! 128 | return that.render(content, that.create_context(value), 129 | partials, true); 130 | } else if(typeof value === "function") { 131 | // higher order section 132 | return value.call(context, content, function(text) { 133 | return that.render(text, context, partials, true); 134 | }); 135 | } else if(value) { // boolean section 136 | return that.render(content, context, partials, true); 137 | } else { 138 | return ""; 139 | } 140 | } 141 | }); 142 | }, 143 | 144 | /* 145 | Replace {{foo}} and friends with values from our view 146 | */ 147 | render_tags: function(template, context, partials, in_recursion) { 148 | // tit for tat 149 | var that = this; 150 | 151 | var new_regex = function() { 152 | return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + 153 | that.ctag + "+", "g"); 154 | }; 155 | 156 | var regex = new_regex(); 157 | var tag_replace_callback = function(match, operator, name) { 158 | switch(operator) { 159 | case "!": // ignore comments 160 | return ""; 161 | case "=": // set new delimiters, rebuild the replace regexp 162 | that.set_delimiters(name); 163 | regex = new_regex(); 164 | return ""; 165 | case ">": // render partial 166 | return that.render_partial(name, context, partials); 167 | case "{": // the triple mustache is unescaped 168 | return that.find(name, context); 169 | default: // escape the value 170 | return that.escape(that.find(name, context)); 171 | } 172 | }; 173 | var lines = template.split("\n"); 174 | for(var i = 0; i < lines.length; i++) { 175 | lines[i] = lines[i].replace(regex, tag_replace_callback, this); 176 | if(!in_recursion) { 177 | this.send(lines[i]); 178 | } 179 | } 180 | 181 | if(in_recursion) { 182 | return lines.join("\n"); 183 | } 184 | }, 185 | 186 | set_delimiters: function(delimiters) { 187 | var dels = delimiters.split(" "); 188 | this.otag = this.escape_regex(dels[0]); 189 | this.ctag = this.escape_regex(dels[1]); 190 | }, 191 | 192 | escape_regex: function(text) { 193 | // thank you Simon Willison 194 | if(!arguments.callee.sRE) { 195 | var specials = [ 196 | '/', '.', '*', '+', '?', '|', 197 | '(', ')', '[', ']', '{', '}', '\\' 198 | ]; 199 | arguments.callee.sRE = new RegExp( 200 | '(\\' + specials.join('|\\') + ')', 'g' 201 | ); 202 | } 203 | return text.replace(arguments.callee.sRE, '\\$1'); 204 | }, 205 | 206 | /* 207 | find `name` in current `context`. That is find me a value 208 | from the view object 209 | */ 210 | find: function(name, context) { 211 | name = this.trim(name); 212 | 213 | // Checks whether a value is thruthy or false or 0 214 | function is_kinda_truthy(bool) { 215 | return bool === false || bool === 0 || bool; 216 | } 217 | 218 | var value; 219 | if(is_kinda_truthy(context[name])) { 220 | value = context[name]; 221 | } else if(is_kinda_truthy(this.context[name])) { 222 | value = this.context[name]; 223 | } 224 | 225 | if(typeof value === "function") { 226 | return value.apply(context); 227 | } 228 | if(value !== undefined) { 229 | return value; 230 | } 231 | // silently ignore unkown variables 232 | return ""; 233 | }, 234 | 235 | // Utility methods 236 | 237 | /* includes tag */ 238 | includes: function(needle, haystack) { 239 | return haystack.indexOf(this.otag + needle) != -1; 240 | }, 241 | 242 | /* 243 | Does away with nasty characters 244 | */ 245 | escape: function(s) { 246 | s = String(s === null ? "" : s); 247 | return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) { 248 | switch(s) { 249 | case "&": return "&"; 250 | case "\\": return "\\\\"; 251 | case '"': return '"'; 252 | case "'": return '''; 253 | case "<": return "<"; 254 | case ">": return ">"; 255 | default: return s; 256 | } 257 | }); 258 | }, 259 | 260 | // by @langalex, support for arrays of strings 261 | create_context: function(_context) { 262 | if(this.is_object(_context)) { 263 | return _context; 264 | } else { 265 | var iterator = "."; 266 | if(this.pragmas["IMPLICIT-ITERATOR"]) { 267 | iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; 268 | } 269 | var ctx = {}; 270 | ctx[iterator] = _context; 271 | return ctx; 272 | } 273 | }, 274 | 275 | is_object: function(a) { 276 | return a && typeof a == "object"; 277 | }, 278 | 279 | is_array: function(a) { 280 | return Object.prototype.toString.call(a) === '[object Array]'; 281 | }, 282 | 283 | /* 284 | Gets rid of leading and trailing whitespace 285 | */ 286 | trim: function(s) { 287 | return s.replace(/^\s*|\s*$/g, ""); 288 | }, 289 | 290 | /* 291 | Why, why, why? Because IE. Cry, cry cry. 292 | */ 293 | map: function(array, fn) { 294 | if (typeof array.map == "function") { 295 | return array.map(fn); 296 | } else { 297 | var r = []; 298 | var l = array.length; 299 | for(var i = 0; i < l; i++) { 300 | r.push(fn(array[i])); 301 | } 302 | return r; 303 | } 304 | } 305 | }; 306 | 307 | return({ 308 | name: "mustache.js", 309 | version: "0.3.1-dev", 310 | 311 | /* 312 | Turns a template and view into HTML 313 | */ 314 | to_html: function(template, view, partials, send_fun) { 315 | var renderer = new Renderer(); 316 | if(send_fun) { 317 | renderer.send = send_fun; 318 | } 319 | renderer.render(template, view, partials); 320 | if(!send_fun) { 321 | return renderer.buffer.join("\n"); 322 | } 323 | } 324 | }); 325 | }(); 326 | -------------------------------------------------------------------------------- /src/main/webapp/js/underscore.js: -------------------------------------------------------------------------------- 1 | // Underscore.js 1.1.4 2 | // (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. 3 | // Underscore is freely distributable under the MIT license. 4 | // Portions of Underscore are inspired or borrowed from Prototype, 5 | // Oliver Steele's Functional, and John Resig's Micro-Templating. 6 | // For all details and documentation: 7 | // http://documentcloud.github.com/underscore 8 | (function(){var q=this,C=q._,m={},j=Array.prototype,n=Object.prototype,i=j.slice,D=j.unshift,E=n.toString,o=n.hasOwnProperty,s=j.forEach,t=j.map,u=j.reduce,v=j.reduceRight,w=j.filter,x=j.every,y=j.some,p=j.indexOf,z=j.lastIndexOf;n=Array.isArray;var F=Object.keys,c=function(a){return new l(a)};if(typeof module!=="undefined"&&module.exports){module.exports=c;c._=c}else q._=c;c.VERSION="1.1.4";var k=c.each=c.forEach=function(a,b,d){if(a!=null)if(s&&a.forEach===s)a.forEach(b,d);else if(c.isNumber(a.length))for(var e= 9 | 0,f=a.length;e=e.computed&&(e={value:f,computed:g})}); 13 | return e.value};c.min=function(a,b,d){if(!b&&c.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};k(a,function(f,g,h){g=b?b.call(d,f,g,h):f;gh?1:0}),"value")};c.sortedIndex=function(a,b,d){d=d||c.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};c.zip=function(){for(var a=i.call(arguments), 16 | b=c.max(c.pluck(a,"length")),d=Array(b),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};c.keys=F||function(a){if(c.isArray(a))return c.range(0,a.length);var b=[],d;for(d in a)if(o.call(a,d))b[b.length]=d;return b};c.values=function(a){return c.map(a,c.identity)};c.functions=c.methods=function(a){return c.filter(c.keys(a),function(b){return c.isFunction(a[b])}).sort()};c.extend=function(a){k(i.call(arguments,1),function(b){for(var d in b)a[d]= 20 | b[d]});return a};c.clone=function(a){return c.isArray(a)?a.slice():c.extend({},a)};c.tap=function(a,b){b(a);return a};c.isEqual=function(a,b){if(a===b)return true;var d=typeof a;if(d!=typeof b)return false;if(a==b)return true;if(!a&&b||a&&!b)return false;if(a._chain)a=a._wrapped;if(b._chain)b=b._wrapped;if(a.isEqual)return a.isEqual(b);if(c.isDate(a)&&c.isDate(b))return a.getTime()===b.getTime();if(c.isNaN(a)&&c.isNaN(b))return false;if(c.isRegExp(a)&&c.isRegExp(b))return a.source===b.source&&a.global=== 21 | b.global&&a.ignoreCase===b.ignoreCase&&a.multiline===b.multiline;if(d!=="object")return false;if(a.length&&a.length!==b.length)return false;d=c.keys(a);var e=c.keys(b);if(d.length!=e.length)return false;for(var f in a)if(!(f in b)||!c.isEqual(a[f],b[f]))return false;return true};c.isEmpty=function(a){if(c.isArray(a)||c.isString(a))return a.length===0;for(var b in a)if(o.call(a,b))return false;return true};c.isElement=function(a){return!!(a&&a.nodeType==1)};c.isArray=n||function(a){return E.call(a)=== 22 | "[object Array]"};c.isArguments=function(a){return!!(a&&o.call(a,"callee"))};c.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};c.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};c.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};c.isNaN=function(a){return a!==a};c.isBoolean=function(a){return a===true||a===false};c.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};c.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase|| 23 | a.ignoreCase===false))};c.isNull=function(a){return a===null};c.isUndefined=function(a){return a===void 0};c.noConflict=function(){q._=C;return this};c.identity=function(a){return a};c.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g};c.template=function(a,b){var d=c.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+ 24 | a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return b?d(b):d};var l=function(a){this._wrapped=a};c.prototype=l.prototype;var r=function(a,b){return b?c(a).chain():a},H=function(a,b){l.prototype[a]=function(){var d= 25 | i.call(arguments);D.call(d,this._wrapped);return r(b.apply(c,d),this._chain)}};c.mixin(c);k(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=j[a];l.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});k(["concat","join","slice"],function(a){var b=j[a];l.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})(); --------------------------------------------------------------------------------