incubator-esme-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject svn commit: r726084 [1/6] - in /incubator/esme/trunk/server: ./ src/ src/main/ src/main/resources/ src/main/resources/props/ src/main/scala/ src/main/scala/bootstrap/ src/main/scala/bootstrap/liftweb/ src/main/scala/us/ src/main/scala/us/esme/ src/main...
Date Fri, 12 Dec 2008 18:32:22 GMT
Author: dpp
Date: Fri Dec 12 10:32:17 2008
New Revision: 726084

URL: http://svn.apache.org/viewvc?rev=726084&view=rev
Log:
Initial server commit

Added:
    incubator/esme/trunk/server/
    incubator/esme/trunk/server/pom.xml
    incubator/esme/trunk/server/src/
    incubator/esme/trunk/server/src/main/
    incubator/esme/trunk/server/src/main/resources/
    incubator/esme/trunk/server/src/main/resources/props/
    incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml
    incubator/esme/trunk/server/src/main/resources/props/dpp.props
    incubator/esme/trunk/server/src/main/resources/props/project.props
    incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props
    incubator/esme/trunk/server/src/main/scala/
    incubator/esme/trunk/server/src/main/scala/bootstrap/
    incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/
    incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala
    incubator/esme/trunk/server/src/main/scala/us/
    incubator/esme/trunk/server/src/main/scala/us/esme/
    incubator/esme/trunk/server/src/main/scala/us/esme/actor/
    incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/api/
    incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/comet/
    incubator/esme/trunk/server/src/main/scala/us/esme/comet/.keep
    incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/external/
    incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/lib/
    incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgParser.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/lib/TagUtils.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/
    incubator/esme/trunk/server/src/main/scala/us/esme/model/.keep
    incubator/esme/trunk/server/src/main/scala/us/esme/model/Action.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/AuthToken.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/DidPerform.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/ExtSession.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/Group.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/Mailbox.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/Message.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/MessageTag.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/Relationship.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/Tag.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/Tracking.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/UrlStore.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/model/User.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/snippet/
    incubator/esme/trunk/server/src/main/scala/us/esme/snippet/.keep
    incubator/esme/trunk/server/src/main/scala/us/esme/snippet/Style.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/snippet/UserSnip.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/view/
    incubator/esme/trunk/server/src/main/scala/us/esme/view/.keep
    incubator/esme/trunk/server/src/main/scala/us/esme/view/ActionView.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/view/Auth.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/view/Track.scala
    incubator/esme/trunk/server/src/main/scala/us/esme/view/UserView.scala
    incubator/esme/trunk/server/src/main/webapp/
    incubator/esme/trunk/server/src/main/webapp/WEB-INF/
    incubator/esme/trunk/server/src/main/webapp/WEB-INF/web.xml
    incubator/esme/trunk/server/src/main/webapp/images/
    incubator/esme/trunk/server/src/main/webapp/images/bg-i.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/bg-left.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/bg-m.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/bg-right.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/bg-right1.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/bg-t.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/btn-send-m.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/btn-sign-in.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/esme-blue.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/esme.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/img-1.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/mail.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/send-message.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/sh-a.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/sh-b.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/sh-r.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/sh-t.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/images/sign-on.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/index.html
    incubator/esme/trunk/server/src/main/webapp/scripts/
    incubator/esme/trunk/server/src/main/webapp/scripts/countdown_timer.js
    incubator/esme/trunk/server/src/main/webapp/scripts/jquery-baf.js
    incubator/esme/trunk/server/src/main/webapp/scripts/jquery-cur.min.js
    incubator/esme/trunk/server/src/main/webapp/scripts/jquery.blockUI.js
    incubator/esme/trunk/server/src/main/webapp/scripts/jquery.dimensions.js
    incubator/esme/trunk/server/src/main/webapp/scripts/jquery.tooltips.js
    incubator/esme/trunk/server/src/main/webapp/scripts/json2.js
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon.js
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/b.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/background.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/l.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/lb.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/lt.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/r.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/rb.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/rt.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/stemb.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/stemt.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/t.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_centerwindow.js
    incubator/esme/trunk/server/src/main/webapp/scripts/tip_followscroll.js
    incubator/esme/trunk/server/src/main/webapp/scripts/ui.accordion.js
    incubator/esme/trunk/server/src/main/webapp/scripts/ui.dialog.js
    incubator/esme/trunk/server/src/main/webapp/scripts/ui.draggable.js
    incubator/esme/trunk/server/src/main/webapp/scripts/ui.mouse.js
    incubator/esme/trunk/server/src/main/webapp/scripts/ui.resizable.js
    incubator/esme/trunk/server/src/main/webapp/scripts/ui.tabs.js
    incubator/esme/trunk/server/src/main/webapp/scripts/wz_tooltip.js
    incubator/esme/trunk/server/src/main/webapp/static/
    incubator/esme/trunk/server/src/main/webapp/static/about.html
    incubator/esme/trunk/server/src/main/webapp/style/
    incubator/esme/trunk/server/src/main/webapp/style/b-back.css
    incubator/esme/trunk/server/src/main/webapp/style/b-content.css
    incubator/esme/trunk/server/src/main/webapp/style/b-edit.css
    incubator/esme/trunk/server/src/main/webapp/style/b-list-ie.css
    incubator/esme/trunk/server/src/main/webapp/style/b-list.css
    incubator/esme/trunk/server/src/main/webapp/style/b-menu.css
    incubator/esme/trunk/server/src/main/webapp/style/b-open.css
    incubator/esme/trunk/server/src/main/webapp/style/b-popup-c.css
    incubator/esme/trunk/server/src/main/webapp/style/b-popup-ie.css
    incubator/esme/trunk/server/src/main/webapp/style/b-popup.css
    incubator/esme/trunk/server/src/main/webapp/style/b-primary.css
    incubator/esme/trunk/server/src/main/webapp/style/b-sign-on.css
    incubator/esme/trunk/server/src/main/webapp/style/b-view-ie.css
    incubator/esme/trunk/server/src/main/webapp/style/b-view-menu.css
    incubator/esme/trunk/server/src/main/webapp/style/b-view.css
    incubator/esme/trunk/server/src/main/webapp/style/esme-ie.css
    incubator/esme/trunk/server/src/main/webapp/style/esme.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.accordion.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.all.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.calendar.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.dialog.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.menu.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.resizable.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.shadow.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.slider.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.tablesorter.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/flora.tabs.css
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-left-act.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-left-over.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-left.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-middle-act.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-middle-over.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-middle.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-right-act.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-right-over.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-right.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/asc.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/bg.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/desc.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-e.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-n.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-ne.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-nw.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-s.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-se.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-sw.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-title.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-titlebar-close-hover.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-titlebar-close.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-w.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/menu-submenu.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-e.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-n.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-ne.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-nw.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-s.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-se.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-sw.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-w.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/shadow.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/slider-bg-1.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/slider-bg-2.png   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/slider-handle.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/flora/i/tabs.gif   (with props)
    incubator/esme/trunk/server/src/main/webapp/style/l-page-content.css
    incubator/esme/trunk/server/src/main/webapp/style/l-page-login.css
    incubator/esme/trunk/server/src/main/webapp/style/l-page-message.css
    incubator/esme/trunk/server/src/main/webapp/style/l-page.css
    incubator/esme/trunk/server/src/main/webapp/style/l-top-ie.css
    incubator/esme/trunk/server/src/main/webapp/style/l-top.css
    incubator/esme/trunk/server/src/main/webapp/style/layout.css
    incubator/esme/trunk/server/src/main/webapp/style/print-ie.css
    incubator/esme/trunk/server/src/main/webapp/style/print.css
    incubator/esme/trunk/server/src/main/webapp/style/ui.tabs.css
    incubator/esme/trunk/server/src/main/webapp/templates-hidden/
    incubator/esme/trunk/server/src/main/webapp/templates-hidden/default.html
    incubator/esme/trunk/server/src/main/webapp/templates-hidden/login.html
    incubator/esme/trunk/server/src/main/webapp/templates-hidden/menu_footer.html
    incubator/esme/trunk/server/src/main/webapp/templates-hidden/message.html
    incubator/esme/trunk/server/src/test/
    incubator/esme/trunk/server/src/test/scala/
    incubator/esme/trunk/server/src/test/scala/LiftConsole.scala
    incubator/esme/trunk/server/src/test/scala/RunWebApp.scala
    incubator/esme/trunk/server/src/test/scala/us/
    incubator/esme/trunk/server/src/test/scala/us/esme/
    incubator/esme/trunk/server/src/test/scala/us/esme/AppTest.scala
    incubator/esme/trunk/server/src/test/scala/us/esme/lib/
    incubator/esme/trunk/server/src/test/scala/us/esme/lib/MsgParseTest.scala

Added: incubator/esme/trunk/server/pom.xml
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/pom.xml?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/pom.xml (added)
+++ incubator/esme/trunk/server/pom.xml Fri Dec 12 10:32:17 2008
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>us.esme</groupId>
+  <artifactId>esme</artifactId>
+  <version>0.2.3-SNAPSHOT</version>
+  <packaging>war</packaging>
+  <name>ESME</name>
+  <inceptionYear>2008</inceptionYear>
+  <properties>
+    <scala.version>2.7.2</scala.version>
+    <lucene.version>2.3.2</lucene.version>
+    <netbeans.hint.deploy.server>gfv3</netbeans.hint.deploy.server>
+  </properties>
+
+  <repositories>
+    <repository>
+      <id>scala-tools.org</id>
+      <name>Scala-Tools Maven2 Repository</name>
+      <url>http://scala-tools.org/repo-releases</url>
+    </repository>
+    <repository>
+      <id>scala-tools.org.snapshots</id>
+      <name>Scala-Tools Maven2 Repository for Snapshots</name>
+      <url>http://scala-tools.org/repo-snapshots</url>
+      <snapshots />
+    </repository>
+    <repository>
+      <id>compass-project.org</id>
+      <name>Compass</name>
+      <url>http://repo.compass-project.org</url>
+    </repository>
+  </repositories>
+
+  <pluginRepositories>
+    <pluginRepository>
+      <id>scala-tools.org</id>
+      <name>Scala-Tools Maven2 Repository</name>
+      <url>http://scala-tools.org/repo-releases</url>
+    </pluginRepository>
+  </pluginRepositories>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-library</artifactId>
+      <version>${scala.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>net.liftweb</groupId>
+      <artifactId>lift-core</artifactId>
+      <version>0.10-SNAPSHOT</version>
+    </dependency>
+        <dependency>
+      <groupId>net.liftweb</groupId>
+      <artifactId>lift-testkit</artifactId>
+      <version>0.10-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>net.liftweb</groupId>
+      <artifactId>lift-openid</artifactId>
+      <version>0.10-SNAPSHOT</version>
+    </dependency>
+    <!--
+    <dependency>
+      <groupId>com.socialmaterial</groupId>
+      <artifactId>social</artifactId>
+      <version>0.1-SNAPSHOT</version>
+    </dependency>
+    -->
+    <dependency>
+      <groupId>org.compass-project</groupId>
+      <artifactId>compass</artifactId>
+      <version>2.0.2</version>
+    </dependency>
+
+    <dependency>
+      <groupId>postgresql</groupId>
+      <artifactId>postgresql</artifactId>
+      <version>8.2-507.jdbc3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.derby</groupId>
+      <artifactId>derby</artifactId>
+      <version>10.2.2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>2.5</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+       <dependency>
+      <groupId>cglib</groupId>
+      <artifactId>cglib</artifactId>
+      <version>2.1_3</version>
+      <scope>test</scope>
+    </dependency>
+     <dependency>
+      <groupId>org.objenesis</groupId>
+      <artifactId>objenesis</artifactId>
+      <version>1.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>net.sourceforge.jwebunit</groupId>
+      <artifactId>jwebunit-htmlunit-plugin</artifactId>
+      <version>1.4.1</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>javax.servlet</groupId>
+          <artifactId>servlet-api</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.mortbay.jetty</groupId>
+      <artifactId>jetty</artifactId>
+      <version>[6.1.6,)</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- for LiftConsole -->
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-compiler</artifactId>
+      <version>${scala.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-snowball</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.specs</groupId>
+      <artifactId>specs</artifactId>
+      <version>1.3.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.4</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <sourceDirectory>src/main/scala</sourceDirectory>
+    <testSourceDirectory>src/test/scala</testSourceDirectory>
+
+    <plugins>
+      <plugin>
+        <groupId>org.scala-tools</groupId>
+        <artifactId>maven-scala-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>compile</goal>
+              <goal>testCompile</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <scalaVersion>${scala.version}</scalaVersion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.mortbay.jetty</groupId>
+        <artifactId>maven-jetty-plugin</artifactId>
+        <configuration>
+          <contextPath>/</contextPath>
+          <scanIntervalSeconds>0</scanIntervalSeconds>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>net.sf.alchim</groupId>
+        <artifactId>yuicompressor-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>compress</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <nosuffix>true</nosuffix>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-eclipse-plugin</artifactId>
+        <configuration>
+          <downloadSources>true</downloadSources>
+          <excludes>
+            <exclude>org.scala-lang:scala-library</exclude>
+          </excludes>
+          <classpathContainers>
+            <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
+          </classpathContainers>
+          <projectnatures>
+            <java.lang.String>ch.epfl.lamp.sdt.core.scalanature</java.lang.String>
+            <java.lang.String>org.eclipse.jdt.core.javanature</java.lang.String>
+          </projectnatures>
+          <buildcommands>
+            <java.lang.String>ch.epfl.lamp.sdt.core.scalabuilder</java.lang.String>
+          </buildcommands>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.scala-tools</groupId>
+        <artifactId>maven-scala-plugin</artifactId>
+        <configuration>
+          <scalaVersion>${scala.version}</scalaVersion>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>

Added: incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml (added)
+++ incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml Fri Dec 12 10:32:17 2008
@@ -0,0 +1,31 @@
+
+<compass-core-config xmlns="http://www.compass-project.org/schema/core-config"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://www.compass-project.org/schema/core-config
+  http://www.compass-project.org/schema/compass-core-config-2.0.xsd">
+
+  <compass name="default">
+
+    <connection>
+      <file path="compass-index"/>
+    </connection>
+    <searchEngine >
+      <analyzer name="default" type="Stop" />
+      <analyzer name="tag" type="Standard" />
+      <analyzer name="stemming" type="Snowball" snowballType="English">
+            <stopWords>
+                <stopWord value="no" />
+                <stopWord value="the" />
+                <stopWord value="and" />
+                <stopWord value="a" />
+                <stopWord value="this" />
+                <stopWord value="i" />
+                <stopWord value="is" />
+            </stopWords>
+      </analyzer>
+
+    </searchEngine>
+
+  </compass>
+
+</compass-core-config>

Added: incubator/esme/trunk/server/src/main/resources/props/dpp.props
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/resources/props/dpp.props?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/resources/props/dpp.props (added)
+++ incubator/esme/trunk/server/src/main/resources/props/dpp.props Fri Dec 12 10:32:17 2008
@@ -0,0 +1 @@
+use_local_psql=true

Added: incubator/esme/trunk/server/src/main/resources/props/project.props
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/resources/props/project.props?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/resources/props/project.props (added)
+++ incubator/esme/trunk/server/src/main/resources/props/project.props Fri Dec 12 10:32:17 2008
@@ -0,0 +1,4 @@
+# Properties file for COIL servers (user id = project)
+http.proxyHost=vsvGW000.pal.coil
+http.proxyPort=8080
+http.nonProxyHosts=*.sap.corp

Added: incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props (added)
+++ incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props Fri Dec 12 10:32:17 2008
@@ -0,0 +1,4 @@
+# Properties file for COIL servers (user id = project)
+http.proxyHost=vsvGW000.pal.coil
+http.proxyPort=8080
+http.nonProxyHosts=*.sap.corp

Added: incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,213 @@
+package bootstrap.liftweb
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+import net.liftweb.util._
+import net.liftweb.http._
+import net.liftweb.sitemap._
+import net.liftweb.sitemap.Loc._
+import Helpers._
+import net.liftweb.mapper.{DB, ConnectionManager, Schemifier, DefaultConnectionIdentifier, ConnectionIdentifier}
+import java.sql.{Connection, DriverManager}
+import us.esme._
+import model._
+import actor._
+import lib._
+import view._
+import api._
+import net.liftweb._
+import mapper._
+import javax.servlet.http.{HttpServlet, HttpServletRequest , HttpServletResponse, HttpSession}
+import org.compass.core._
+import org.compass.core.config.CompassConfiguration
+
+/**
+ * A class that's instantiated early and run.  It allows the application
+ * to modify lift's environment
+ */
+class Boot {
+  def boot {
+    DefaultConnectionIdentifier.jndiName = "esme"
+    
+    if (!DB.jndiJdbcConnAvailable_?) DB.defineConnectionManager(DefaultConnectionIdentifier, DBVendor)
+    // where to search snippet
+    LiftRules.addToPackages("us.esme")
+    
+    if (Props.mode == Props.RunModes.Test) {
+      Schemifier.destroyTables_!!(Log.infoF _, User, ExtSession,
+                                  Message, Mailbox, Tag,
+                                  Group, Relationship, MessageTag, 
+                                  AuthToken, UrlStore, Tracking,
+                                  Action, DidPerform)
+    }
+    
+    Schemifier.schemify(true, Log.infoF _, User, ExtSession, Message,
+                        Mailbox, Tag,
+                        Group, Relationship, MessageTag, AuthToken, 
+                        UrlStore, Tracking, Action, DidPerform)
+    
+    LiftRules.prependTemplate(User.templates)
+    
+    LiftRules.appendStatelessDispatch {
+      case r @ Req("api" :: "send_msg" :: Nil, "", PostRequest) 
+        if r.param("token").isDefined  => 
+        () => RestAPI.sendMsgWithToken(r)
+    }
+    
+    LiftRules.appendDispatch(ESMEOpenIDVendor.dispatchPF)
+    
+    LiftRules.siteMapFailRedirectLocation = List("static", "about")
+    
+    LiftRules.prependRewrite {
+      case RewriteRequest(ParsePath("user" :: user :: Nil,"", _,_), _, _) =>
+        RewriteResponse( List("user_view", "index"), Map("uid" -> user))
+      case RewriteRequest(ParsePath("tag" :: tag :: Nil,"", _,_), _, _) =>
+        RewriteResponse( List("user_view", "tag"), Map("tag" -> tag))
+        
+      case RewriteRequest(ParsePath("conversation" :: cid :: Nil, "", _, _),
+                          _, _) => 
+        RewriteResponse(List("user_view", "conversation"), Map("cid" -> cid))
+
+      case RewriteRequest(ParsePath("search" :: term :: Nil,"", _,_), _, _) =>
+        RewriteResponse( List("user_view", "search"), Map("term" -> term))
+    }
+
+    LiftRules.appendDispatch(UrlStore.redirectizer)
+
+
+    LiftRules.siteMapFailRedirectLocation = List("static", "about")
+
+    // Build SiteMap
+    val entries = Menu(Loc("Home", List("index"), "Home")) ::
+    Menu(Loc("list_users", List("user_view", "all"), "List Users")) ::
+    Menu(Loc("user", List("user_view", "index"), "User Info", Hidden)) ::
+    Menu(Loc("conv", List("user_view", "conversation"), "Conversation", Hidden)) ::
+    Menu(Loc("about", List("static", "about"), "About", Hidden)) ::
+    Menu(Loc("tag", List("user_view", "tag"), "Tag", Hidden)) ::
+    Menu(Loc("search", List("user_view", "search"), "Search", Hidden)) ::
+    User.sitemap :::
+    Track.menuItems :::
+    Auth.menuItems :::
+    ActionView.menuItems
+
+    LiftRules.setSiteMap(SiteMap(entries:_*))
+    S.addAround(User.requestLoans)
+    S.addAround(ExtSession.requestLoans)
+
+    LiftRules.appendViewDispatch {
+      case "user_view" :: _ => UserView
+    }
+
+    LiftRules.prependDispatch(RestAPI.dispatch)
+    
+    LiftRules.appendEarly(makeUtf8)
+
+    Distributor.touch
+
+    DB.addLogFunc(S.logQuery _)
+    S.addAnalyzer(RequestAnalyzer.analyze _)
+  }
+  private def makeUtf8(req: HttpServletRequest): Unit = {req.setCharacterEncoding("UTF-8")}
+}
+
+object Compass {
+  // Set up Compass for search
+  val conf = new CompassConfiguration().configure("/props/compass.cfg.xml").addClass((new Message).clazz)
+  val compass = conf.buildCompass()
+  if (!compass.getSearchEngineIndexManager.indexExists)
+  {
+    // Create Index if one does not exist
+    compass.getSearchEngineIndexManager().createIndex()
+  }
+}
+
+
+object RequestAnalyzer {
+
+  def analyze(req: Can[Req], time: Long, queries: List[(String, Long)]): Unit = {
+    val longQueries = (queries.filter(_._2 > 30))
+    if (time > 50 || longQueries.?) {
+      Log.info("Request "+req.map(_.uri).openOr("No Request")+
+               " took "+time+" query "+longQueries.comma)
+    }
+  }
+}
+
+object DBVendor extends ConnectionManager {
+  private var pool: List[Connection] = Nil
+  private var poolSize = 0
+  private val maxPoolSize = 4
+  
+  private def createOne: Can[Connection] = try {
+    if (Props.getBool("use_prod_psql", false)) {
+      Class.forName("org.postgresql.Driver")
+      val dm = DriverManager.
+      getConnection("jdbc:postgresql://localhost/esme_prod",
+                    Props.get("db_user", "dpp"),
+                    Props.get("db_pwd", ""))
+      Full(dm)
+    } else if (Props.getBool("use_local_psql", false)) {
+      Class.forName("org.postgresql.Driver")
+      val dm = DriverManager.
+      getConnection("jdbc:postgresql://localhost/esme_dev",
+                    Props.get("db_user", "dpp"),
+                    Props.get("db_pwd", ""))
+      Full(dm)
+    } else {
+      Class.forName("org.apache.derby.jdbc.EmbeddedDriver")
+      val driverName = Props.mode match {
+        case Props.RunModes.Test => "jdbc:derby:esme_test_db;create=true"
+        case _ => "jdbc:derby:esme_db;create=true"
+      }
+      
+      val dm = DriverManager.getConnection(driverName)
+      Full(dm)
+    }
+  } catch {
+    case e : Exception => e.printStackTrace; Empty
+  }
+  
+  def newConnection(name: ConnectionIdentifier): Can[Connection] = synchronized {
+    pool match {
+      case Nil if poolSize < maxPoolSize => val ret = createOne
+        poolSize = poolSize + 1
+        ret.foreach(c => pool = c :: pool)
+        ret
+
+      case Nil => wait(1000L); newConnection(name)
+      case x :: xs => try {
+          x.setAutoCommit(false)
+          Full(x)
+        } catch {
+          case e => try {
+              pool = xs
+              poolSize = poolSize - 1
+              x.close
+              newConnection(name)
+            } catch {
+              case e => newConnection(name)
+            }
+        }
+    }
+  }
+  
+  def releaseConnection(conn: Connection): Unit = synchronized {
+    pool = conn :: pool
+    notify
+  }
+}
+

Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+/*
+ * Distributor.scala
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package us.esme.actor
+
+import scala.actors.Actor
+import Actor._
+
+import net.liftweb._
+import http._
+import util._
+
+import us.esme._
+import model._
+
+import scala.xml.{Elem}
+
+object Distributor extends Actor {
+  def act = loop {
+    react {
+      case StartMeUp =>
+        link(ActorWatcher)
+        User.findAll.map(_.id.is).foreach(findOrCreateUser)
+        Group.findAll.map(_.id.is).foreach(findOrCreateGroup)
+
+      case UserCreatedMessage(user, text, tags, when, 
+                              metaData,
+                              source,
+                              inReplyTo) =>
+        findOrCreateUser(user) ! 
+        UserActor.CreateMessage(text, tags,
+                                when, metaData, source, inReplyTo)
+
+      case AddMessageToMailbox(user, message, reason) =>
+        findOrCreateUser(user) ! UserActor.AddToMailbox(message, reason)
+  
+      case Listen(user, who) =>
+        findOrCreateUser(user) ! UserActor.Listen(who)
+
+      case Unlisten(user, who) =>
+        findOrCreateUser(user) ! UserActor.Unlisten(who)
+
+      case LatestMessages(user, cnt) =>
+        findOrCreateUser(user).forward(UserActor.LatestMessages(cnt))
+
+      case m @ UserUpdated(id) =>
+        users.get(id).foreach(_ ! m)
+
+      case nm @ NewMessage(msg) =>
+        val toSend = UserActor.TestForTracking(msg)
+        users.values.foreach(_ ! toSend)
+        listeners.foreach(_ ! nm)
+
+      case UpdateTrackingFor(userId, ttype) =>
+        for (user <- users.get(userId))
+        user ! UserActor.UpdateTracking(ttype)
+          
+      case PublicTimelineListeners(who) =>
+        listeners = who :: listeners
+
+      case PublicTimelineUnlisteners(who) =>
+        listeners = listeners.filter(_ ne who)
+
+      case _ =>
+    }
+  }
+
+  private case object StartMeUp
+
+  case class UserCreatedMessage(user: Long, text: String, tags: List[String],
+                                when: Long,
+                                metaData: Can[Elem],
+                                source: String,
+                                replyTo: Can[Long])
+  case class AddMessageToMailbox(user: Long, message: Message, reason: MailboxReason)
+  case class Listen(user: Long, who: Actor)
+  case class Unlisten(user: Long, who: Actor)
+  case class LatestMessages(user: Long, cnt: Int)
+  case class NewMessage(msg: Message)
+  case class UpdateTrackingFor(user: Long, which: TrackingType)
+  case class UserUpdated(userId: Long)
+  case class PublicTimelineListeners(who: Actor)
+  case class PublicTimelineUnlisteners(who: Actor)
+  sealed trait TrackingType
+  case object PerformTrackingType extends TrackingType
+  case object TrackTrackingType extends TrackingType
+
+  start
+  this ! StartMeUp
+
+  // do nothing
+  def touch {
+
+  }
+
+  private var users: Map[Long, UserActor] = Map.empty
+  private var groups: Map[Long, GroupActor] = Map.empty
+  private var listeners: List[Actor] = Nil
+
+  private def findOrCreateUser(user: Long): UserActor = {
+    users.get(user) match {
+      case Some(ret) => ret
+      case _ =>
+        val ret = new UserActor
+        ret.start
+        ret ! UserActor.StartMeUp(user)
+        users = users + (user -> ret)
+        ret
+    }
+  }
+
+  private def findOrCreateGroup(group: Long) {
+    groups.get(group) match {
+      case Some(ret) => ret
+      case _ =>
+        val ret = new GroupActor
+        ret.start
+        ret ! GroupActor.StartMeUp(group)
+        groups = groups + (group -> ret)
+        ret
+    }
+  }
+}

Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+package us.esme.actor
+
+import scala.actors.Actor
+import Actor._
+
+
+import net.liftweb._
+import http._
+
+import us.esme._
+import model._
+
+object GroupActor {
+  case class StartMeUp(group: Long)
+}
+
+class GroupActor extends Actor {
+  import GroupActor._
+  
+  def act = loop {
+    react {
+      case StartMeUp =>
+        link(ActorWatcher)
+    }
+  } 
+}

Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+
+
+package us.esme.actor
+
+import scala.actors.Actor
+import Actor._
+
+import net.liftweb._
+import http._
+import util._
+import net.liftweb.http.testing._
+
+import us.esme._
+import model._
+import lib._
+
+import org.apache.commons.httpclient._
+
+object HttpSender extends Actor with GetPoster {
+  def act = loop {
+    react {
+      case StartMeUp =>
+        link(ActorWatcher)
+        
+
+      case SendAMessage(action, msg, token) =>
+        send(action, msg, token)
+
+      case _ =>
+    }
+  }
+
+  private case object StartMeUp
+  case class SendAMessage(action: Performances, msg: Message, token: String)
+
+  private def send(action: Performances, msg: Message, token: String) {
+    import Mailer._
+    
+    action match {
+      case MailTo(who) => Mailer.sendMail(From("i@esme.us"), Subject("msg"),
+                                          To(who),
+                                          XHTMLMailBodyType(msg.digestedXHTML))
+      case HttpTo(url, headers) =>
+        post(url, httpClient,
+             ("X-ESME-Token" -> token) :: headers,
+             msg.toXml)
+        
+      case PerformResend | PerformFilter => // IGNORE
+      
+    }
+  }
+  
+  def httpClient = {
+    val ret = new HttpClient(new SimpleHttpConnectionManager(false))
+
+    for (host <- Props.get("http.proxyHost"))
+    ret.getHostConfiguration.setProxy(host,
+                                      Props.getInt("http.proxyPort",80))
+    ret
+  }
+
+  start
+  this ! StartMeUp
+
+  def baseUrl = ""
+}

Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,55 @@
+package us.esme.actor
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+import scala.actors.Actor
+import scala.actors.TIMEOUT
+import scala.actors.Actor._
+import us.esme.actor.Distributor.{UserCreatedMessage=>Msg}
+
+class MessagePullActor(val messageProcessor: Actor, val refreshSeconds: Int, private var lastMessage: Option[Msg], val messageSource: UniqueMessageSource) extends Actor {
+
+  def act {
+    loop {
+      reactWithin (refreshSeconds * 1000) {
+        case (msgs: List[Msg]) => {
+          val lastMessages = messageSource.getLastSortedMessages(msgs, lastMessage)
+          for (message <- lastMessages) {
+            messageProcessor ! message
+            lastMessage = Some(message)
+          }
+        }
+        case TIMEOUT => actor {
+          // "this" used to reference invoking actor
+          this ! messageSource()
+        }
+      }
+    }
+  }
+  
+}
+
+trait UniqueMessageSource extends (() => List[Msg]) {
+  def messageSorter(a: Msg, b: Msg) = a.when < b.when
+
+  def getLastSortedMessages(msgs: List[Msg], lastMessage: Option[Msg]): List[Msg] = {
+    lastMessage match {
+      case Some(message: Msg) => msgs.filter{messageSorter(message, _)}
+      case None => msgs
+    }
+  }.sort(messageSorter)
+}

Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+package us.esme.actor
+
+import scala.actors.Actor
+import Actor._
+
+import net.liftweb._
+import http._
+import util._
+import mapper._
+
+import us.esme._
+import model._
+import lib._
+
+import java.util.logging._
+import java.util.{TimeZone, Calendar}
+import scala.xml.{Elem}
+
+object UserActor {
+  private[actor] case class StartMeUp(user: Long)
+  private[actor] case class CreateMessage(text: String, tags: List[String],
+                                          when: Long, metaData: Can[Elem],
+                                          source: String,
+                                          replyTo: Can[Long])
+  private[actor] case class AddToMailbox(msg: Message, reason: MailboxReason)
+  private[actor] case class Listen(who: Actor)
+  private[actor] case class Unlisten(who: Actor)
+  private[actor] case class LatestMessages(cnt: Int)
+  private[actor] case class TestForTracking(msg: Message)
+  private[actor] case class UpdateTracking(ttype: Distributor.TrackingType)
+  
+  case class MessageReceived(msg: Message, reason: MailboxReason)
+  
+  val logger: Logger = Logger.getLogger("us.esme.actor")
+}
+
+class UserActor extends Actor {
+  import UserActor._
+  
+  private var userId: Long = 0
+
+  private var userTimezone: TimeZone = _
+  
+  private var listeners: List[Actor] = Nil
+  
+  private var tracking: List[TrackingMatcher] = Nil
+
+  private var perform: List[PerformMatcher] = Nil
+  
+  private var _mailbox: Array[Long] = Array()
+
+  private def followers: List[Long] = User.followerIdsForUserId(userId)
+
+  private case class RunFunc(f: () => Unit)
+
+  def act = loop {
+    react {
+      case m @ Distributor.UserUpdated(_) =>
+        User.find(userId).
+        foreach(u => userTimezone = TimeZone.getTimeZone(u.timezone))
+        listeners.foreach(_ ! m)
+
+      case StartMeUp(user) =>
+        link(ActorWatcher)
+        userId = user
+        User.find(userId).
+        foreach(u => userTimezone = TimeZone.getTimeZone(u.timezone))
+
+        _mailbox = Mailbox.mostRecentMessagesFor(userId, 500).
+        map(_._1.id.is).toArray
+
+        this ! UpdateTracking(Distributor.TrackTrackingType)
+        this ! UpdateTracking(Distributor.PerformTrackingType)
+
+      case RunFunc(f) => f()
+        
+      case CreateMessage(text, tags, when, metaData, source, replyTo) =>
+        val tagLst = tags.removeDuplicates.map(Tag.findOrCreate)
+
+        Message.create.author(userId).when(when).
+        source(source).
+        setTextAndTags(text, tagLst, metaData).map{msg =>
+          // do some security... only reply to messages
+          // that are in our mailbox
+          for (rt <- replyTo;
+               mb <- Mailbox.find(By(Mailbox.message, rt),
+                                  By(Mailbox.user, userId))) msg.replyTo(rt)
+
+          msg.saveMe
+
+          Distributor ! Distributor.AddMessageToMailbox(userId, msg, NoReason)
+        
+          for (id <- followers)
+          Distributor ! Distributor.AddMessageToMailbox(id, msg, NoReason)
+        
+          for (id <- msg.sentToIds)
+          Distributor ! Distributor.AddMessageToMailbox(id, msg,
+                                                        DirectReason(userId))
+
+          for (convId <- msg.conversation.can ;
+               val msgId = Message.findMap(By(Message.conversation, convId))
+               (m => Full(m.id.is));
+               userId <- (Mailbox.findMap(InRaw(Mailbox.message, msgId.mkString(", "),
+                                                IHaveValidatedThisSQL("dpp", "Aug 27. 2008")))
+                          (mb => Full(mb.user.is))).removeDuplicates)
+          Distributor ! Distributor.AddMessageToMailbox(userId, msg, ConversationReason(convId))
+
+          Distributor ! Distributor.NewMessage(msg)
+        }
+
+      case AddToMailbox(msg, reason) => 
+        addToMailbox(msg, reason)
+        
+        
+      case TestForTracking(msg) =>
+        for (t <- tracking.find(_.doesMatch_?(msg)))
+        this ! AddToMailbox(msg, TrackReason(t.trackId))
+         
+          
+      case UpdateTracking(ttype) =>
+        ttype match {
+          case Distributor.TrackTrackingType =>
+            tracking = Tracking.findAll(By(Tracking.user, userId),
+                                        By(Tracking.disabled, false),
+                                        By(Tracking.removed, false)).
+            flatMap(_.matcher)
+        
+          case Distributor.PerformTrackingType =>
+            perform = Action.findAll(By(Action.user, userId),
+                                     By(Action.disabled, false),
+                                     By(Action.removed, false)).
+            map(_.matcher)
+        }
+  
+      case Listen(who) => listeners = who :: listeners
+    
+      case Unlisten(who) => listeners = listeners.filter(_ ne who)
+    
+      case LatestMessages(cnt) => reply(_mailbox.take(cnt).toList)
+    }
+  }
+
+  def buildCalendar = userTimezone match {
+    case null => Calendar.getInstance()
+    case tz => Calendar.getInstance(tz)
+  }
+  
+  private def addToMailbox(msg: Message, reason: MailboxReason) {
+    // if the message is not in my mailbox
+    if (Mailbox.find(By(Mailbox.message, msg),
+                     By(Mailbox.user, userId)).isEmpty) {
+      
+      // get all the performance things
+      val cal = buildCalendar
+      val toDo = perform.filter(_.func(msg, userId, cal))
+
+      // is one of those reasons rejection of the message
+      val reject = toDo.exists(_.filter_?)
+
+      // if we're not rejecting the message
+      if (!reject) {
+        val mb = Mailbox.create.user(userId).message(msg)
+        reason match {
+          case TrackReason(trackId) => mb.viaTrack(trackId)
+          case DirectReason(fromId) => mb.directlyFrom(fromId)
+          case ConversationReason(convId) => mb.conversation(convId)
+          case ResendReason(resender) => mb.resentBy(resender)
+          case NoReason =>
+        }
+        mb.saveMe
+          
+        _mailbox = (msg.id.is :: _mailbox.toList).take(500).toArray
+
+        listeners.foreach(_ ! MessageReceived(msg, reason))
+            
+        toDo.foreach {
+          td =>
+
+          td.whatToDo match {
+            case m @ MailTo(_) =>
+              HttpSender ! HttpSender.SendAMessage(m, msg, td.uniqueId)
+             
+            case h @ HttpTo(_, _) =>
+              HttpSender ! HttpSender.SendAMessage(h, msg, td.uniqueId)
+
+            case PerformResend =>
+              for (id <- followers)
+              Distributor !
+              Distributor.AddMessageToMailbox(id, msg, ResendReason(userId))
+
+            case PerformFilter => // IGNORE
+          }
+        }
+      }
+    }
+  }
+}

Added: incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+/*
+ * RestAPI.scala
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package us.esme.api
+
+import net.liftweb._
+import http._
+import rest._
+import util._
+import mapper._
+import Helpers._
+
+import us.esme._
+import model._
+import actor._
+
+import scala.xml.{NodeSeq, Text, Elem, XML}
+import scala.actors.Actor
+import Actor._
+
+import scala.collection.mutable.ListBuffer
+import java.util.logging._
+
+object RestAPI extends XMLApiHelper {
+  val logger: Logger = Logger.getLogger("us.esme.api")
+
+  def dispatch: LiftRules.DispatchPF = {
+    case Req("api" :: "status" :: Nil, "", GetRequest) => status
+    case Req("api" :: "login" :: Nil, "", PostRequest) => login
+    case Req("api" :: "logout" :: Nil, "", GetRequest) => logout
+    case Req("api" :: "get_msgs" :: Nil, "", GetRequest) => getMsgs
+    case Req("api" :: "wait_for_msgs" :: Nil, "", GetRequest) =>
+      waitForMsgs
+      
+    case Req("api" :: "send_msg" :: Nil, "", PostRequest) => 
+      () => sendMsg(User.currentUser.map(_.id.is), S)
+
+    case Req("api" :: "get_following" :: Nil, _, GetRequest) =>
+      following(calcUser)
+    case Req("api" :: "get_followers" :: Nil, _, GetRequest) =>
+      followers(calcUser)
+    case Req("api" :: "follow" :: Nil, _, PostRequest) =>
+      performFollow(S.param("user"))
+    case Req("api" :: "unfollow" :: Nil, _, PostRequest) => 
+      performUnfollow(S.param("user"))
+    case Req("api" :: "all_users" ::
+                      Nil, _, GetRequest) => allUsers _
+    case Req("api" :: "get_tagcloud" :: Nil, "", GetRequest) =>
+      () => getTagCloud(S)
+
+      // DPP to document
+    case Req("api" :: "get_tracking" :: Nil, "", GetRequest) =>
+      getTracking
+
+    case Req("api" :: "add_tracking" :: Nil, "", PostRequest) =>
+      addTracking
+
+    case Req("api" :: "remove_tracking" :: Nil, "", PostRequest) =>
+      removeTracking
+
+    case Req("api" :: "get_conversation" :: Nil, "", GetRequest) =>
+      getConversation
+      
+    case Req("api" :: "get_actions" :: Nil, "", GetRequest) =>
+      getActions _
+        
+    case Req("api" :: "add_action" :: Nil, "", PostRequest) =>
+      addAction _
+        
+    case Req("api" :: "enable_action" :: Nil, "", PostRequest) =>
+      enableAction _
+        
+    case Req("api" :: "delete_action" :: Nil, "", PostRequest) =>
+      deleteAction _
+  }
+
+  def findAction: Can[Action] =
+  for (user <- User.currentUser ?~ "Not Logged In";
+       id <- S.param("actionid") ?~ "id param not supplied";
+       action <- Action.find(By(Action.user, user),
+                             By(Action.id, id.toLong),
+                             By(Action.removed, false))) yield action
+
+  def addAction(): LiftResponse = {
+    val ret: Can[NodeSeq] =
+    for (user <- User.currentUser ?~ "Not logged in";
+         name <- S.param("name") ?~ "'name' param not supplied";
+         test <- S.param("test") ?~ "'test' param not supplied";
+         action <- S.param("action") ?~ "'action' param not supplied";
+         val a = Action.create.user(user).name(name);
+         a2 <- a.setTest(test);
+         a3 <- a.setAction(action)) yield a3.saveMe.toXml
+
+    ret
+  }
+
+  def getActions(): LiftResponse = {
+    val ret: Can[NodeSeq] =
+    for (user <- User.currentUser ?~ "Not logged in")
+    yield user.performing.flatMap(_.toXml)
+
+    ret
+  }
+
+  def enableAction(): LiftResponse = {
+    val ret: Can[Boolean] =
+    for (action <- findAction;
+         enabled <- S.param("enabled").map(toBoolean) ?~ "enabled param not supplied")
+    yield action.disabled(!enabled).save
+  
+    ret
+  }
+
+  def deleteAction(): LiftResponse = {
+    val ret: Can[Boolean] =
+    for (action <- findAction) 
+    yield action.removed(true).save
+    
+    ret
+  }
+  
+  private def calcUser: Can[User] =
+  S.param("user").flatMap(User.findFromWeb) or
+  User.currentUser
+  
+  def getTracking(): LiftResponse = {
+    val ret: Can[NodeSeq] =
+    for (user <- User.currentUser ?~ "Not logged in")
+    yield Tracking.findAll(By(Tracking.user, user)).flatMap(_.toXml)
+    ret
+  }
+
+  def getConversation(): LiftResponse = {
+    val ret: Can[NodeSeq] =
+    for (user <- User.currentUser ?~ "Not logged in";
+         id <- S.param("conversationid").map(toLong) ?~ "id param missing"
+    ) yield <conversation id={id.toString}>{
+        Message.findAndPrime(By(Message.conversation, id),
+                             OrderBy(Message.id, Ascending)).map(_.toXml)
+      }</conversation>
+
+    ret
+  }
+
+  def removeTracking(): LiftResponse = {
+    val ret: Can[Boolean] =
+    for (user <- User.currentUser ?~ "Not logged in";
+         id <- S.param("trackid") ?~ "id param missing";
+         track <- Tracking.find(By(Tracking.id, id.toLong),
+                                By(Tracking.user, user)) ?~ "Couldn't find tracking item"
+    ) yield track.removed(true).save
+
+    ret
+  }
+
+  def addTracking(): LiftResponse = {
+    val ret: Can[Boolean] =
+    for (user <- User.currentUser ?~ "Not logged in";
+         toTrack <- (S.param("track") ?~ "No track param") if toTrack.trim.length > 0)
+    yield
+    Tracking.create.user(user).regex(toTrack).save
+
+    ret
+  }
+
+  def status(): LiftResponse =
+  {
+    val ret: Can[NodeSeq] = User.currentUser.map(_.toXml)
+    ret
+  }
+
+  def allUsers(): LiftResponse = 
+  for (user <- User.findAll) yield user.toXml
+
+
+  def following(muser: Can[User])(): LiftResponse = {
+    val r: Can[NodeSeq] = for (user <- muser) yield
+    user.following().map(_.toXml)
+    
+    r
+  }
+  
+  def followers(muser: Can[User])(): LiftResponse = {
+    val r: Can[NodeSeq] = for (user <- muser) yield
+    user.followers().map(_.toXml)
+    
+    r
+  }
+  
+  def performFollow(userName: Can[String])(): LiftResponse = {
+    val r: Can[Boolean] =
+    for (user <- User.currentUser;
+         userName <- userName;
+         other <- User.findFromWeb(userName)
+    ) yield user.follow(other)
+    
+    r
+  }
+  
+  def performUnfollow(userName: Can[String])(): LiftResponse = {
+    val r: Can[Boolean] =
+    for (user <- User.currentUser;
+         userName <- userName;
+         other <- User.findFromWeb(userName)
+    ) yield user.unfollow(other)
+    
+    r
+  }
+
+  def login(): LiftResponse = {
+    val res: Can[Boolean] = if (User.loggedIn_?) Empty else
+    for (token <- S.param("token") ?~ "No 'token' param";
+         auth <- AuthToken.find(By(AuthToken.uniqueId, token))
+         ?~ "Token not found";
+         user <- auth.user.obj;
+         session <- S.session
+    ) yield {
+      User.logUserIn(user)
+      val myActor = buildActor(user.id)
+      restActor(Full(myActor))
+      true
+    }
+
+    res
+  }
+
+  def logout(): LiftResponse = {
+    User.logUserOut()
+    true
+  }
+
+  def waitForMsgs(): LiftResponse = {
+    val seq: Long = CometActor.next
+
+    def waitForAnswer: Can[List[(Message, MailboxReason)]] = 
+    receiveWithin(6L * 60L * 1000L) {
+      case (s2, ret: List[(Message, MailboxReason)]) if s2 == seq =>
+        Full(ret)
+      case (s2, _, _) if s2 != seq => waitForAnswer
+      case _ => Empty
+    }
+
+    var r: Can[NodeSeq] = 
+    for (act <- restActor.is ?~ "No REST actor";
+         val ignore = act ! ListenFor(self, 5 minutes, seq);
+         answer <- waitForAnswer ?~ "Didn't get an answer")
+    yield answer.flatMap{ case (msg, reason) => msg.toXml % reason.attr}
+
+    r
+  }
+
+  def sendMsgWithToken(req: Req): Can[LiftResponse] = {
+    for (token <- req.param("token");
+         auth <- AuthToken.find(By(AuthToken.uniqueId, token));
+         userId <- auth.user.can;
+         ret <- sendMsg(Full(userId), req))  yield ret
+  }
+  
+  def sendMsg(theUser: Can[Long], params: HasParams): LiftResponse = {
+    val r: Can[Boolean] =
+    for (user <- theUser ?~ "User not found";
+         msg <- params.param("message") ?~ "Message not included")
+    yield {
+      val from: String = params.param("via") openOr "api"
+
+      val xml: Can[Elem] = params.param("metadata").flatMap(md =>
+        tryo(XML.loadString(md)))
+
+      Distributor !
+      Distributor.UserCreatedMessage(user, msg,
+                                     Tag.split(params.param("tags")
+                                               openOr ""),
+                                     millis,
+                                     xml,
+                                     from,
+                                     params.param("replyto").map(toLong))
+      true
+    }
+    r
+  }
+
+  def getMsgs(): LiftResponse = {
+    val t: Can[NodeSeq] =
+    for (tagName <- S.param("tag");
+         tag <- Tag.find(By(Tag.name, tagName)))
+    yield tag.findMessages.map(_.toXml)
+        
+    val r: Can[NodeSeq] = 
+    t or (for (user <- calcUser ?~ "User not found";
+               val lst = Mailbox.mostRecentMessagesFor(user.id, 40))
+          yield lst.flatMap{ case (msg, why) => msg.toXml % why.attr})
+    
+    r
+  }
+
+  def getTagCloud(params: HasParams): LiftResponse = {
+    // By default, get the normalised word frequencies from the messages
+    val numTags = (params.param("numTags") openOr "20").toInt
+    val numMsgs = 40 //(params.param("numMsgs") openOr "40").toInt
+
+    val r: Can[NodeSeq] = 
+    for (user <- calcUser ?~ "User not found";
+         val lst = Mailbox.mostRecentMessagesFor(user.id, numMsgs).map(_._1))
+    yield
+    <tag_cloud>
+      {
+        for (t <- Tag.centreWeightedTopNTagFreqs(lst, numTags)) yield <tag name={t._1} weight={t._2.toString} />
+      }
+      {
+        for (t <- Message.centreWeightedTopNWordFreqs(lst, numTags)) yield <word name={t._1} weight={t._2.toString} />
+      }
+    </tag_cloud>
+     
+     
+    r
+  }
+
+  def createTag(in: NodeSeq) = <esme_api>{in}</esme_api>
+
+  
+  private def buildActor(userId: Long): RestActor = {
+    val ret = new RestActor
+    ret.start
+    ret ! StartUp(userId)
+    ret
+  }
+
+  object restActor extends SessionVar[Can[RestActor]](Empty) {
+    override def cleanupFunc: Can[() => Unit] = Full(() => this.is.map(_ ! ByeBye))
+  }
+  
+
+  class RestActor extends Actor {
+    private var userId: Long = _
+    private var msgs: List[(Message, MailboxReason)] = Nil
+    private var listener: Can[(Actor, Long)] = Empty
+    
+    def act = loop {
+      react {
+        case StartUp(userId) =>
+          link(ActorWatcher)
+          this.userId = userId
+          Distributor ! Distributor.Listen(userId, this)
+
+        case ByeBye =>
+          unlink(ActorWatcher)
+          Distributor ! Distributor.Unlisten(userId, this)
+          self.exit()
+          
+        case UserActor.MessageReceived(msg, reason) =>
+          msgs = (msg, reason) :: msgs
+          listener.foreach {
+            who =>
+            who._1 ! (who._2, msgs)
+            listener = Empty
+            msgs = Nil
+          }
+        
+        case ReleaseListener =>
+          listener.foreach(l => l._1 ! (l._2, Nil))
+          listener = Empty
+
+        case ListenFor(who, len, seq) =>
+          msgs match {
+            case Nil =>
+              listener.foreach(l => l._1 ! (l._2, Nil))
+              listener = Full((who, seq))
+              ActorPing.schedule(this, ReleaseListener, len)
+             
+            case xs =>
+              who ! (seq, xs)
+              msgs = Nil
+              listener = Empty
+          }
+      }
+    }
+  }
+
+  private case class StartUp(userId: Long)
+  private case object ByeBye
+  private case class ListenFor(who: Actor, howLong: TimeSpan, seq: Long)
+  private case object ReleaseListener
+}

Added: incubator/esme/trunk/server/src/main/scala/us/esme/comet/.keep
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/comet/.keep?rev=726084&view=auto
==============================================================================
    (empty)

Added: incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,87 @@
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package us.esme.comet
+
+import net.liftweb.http._
+import net.liftweb.mapper._
+import net.liftweb.util._
+import net.liftweb.util.Helpers._
+import scala.xml._
+import js._
+import JsCmds._
+import JE._
+
+import us.esme._
+import actor._
+import model._
+import lib._
+
+import java.text._
+
+class PublicTimeline extends CometActor with MsgFormat {
+
+  def defaultPrefix = "timeline"
+
+  private var messages: List[Long] = Nil
+  private var lastRender = millis
+  private var scheduled = false
+
+  override def localSetup() {
+    super.localSetup()
+    Distributor ! Distributor.PublicTimelineListeners(this) 
+    messages = Message.findAll(OrderBy(Message.id, Descending), 
+                               MaxRows(40)).map(_.id.is)
+  }
+  
+  override def localShutdown() {
+    super.localShutdown()
+    Distributor ! Distributor.PublicTimelineUnlisteners(this)
+  }
+  
+  def render = {
+    lastRender = millis
+    scheduled = false
+    val msgMap = Message.findMessages(messages)
+    val toDisplay = messages.flatMap(msgMap.get)
+  
+    <xml:group>
+      {
+        toDisplay.map(m => formatMsg(m, true, true))
+      }
+    </xml:group>
+  }
+  
+  override implicit def xmlToXmlOrJsCmd(in: NodeSeq): RenderOut = new RenderOut(Full(in), fixedRender, Empty, Empty, false)
+
+  override def lowPriority = {
+    case ForceRender =>
+      reRender(false)
+
+    case Distributor.NewMessage(msg) =>
+      messages = (msg.id.is :: messages).take(40)
+
+      if ((millis - lastRender) < 30000L) {
+        if (!scheduled) {
+          scheduled = true    
+          ActorPing.schedule(this, ForceRender, 30000L)
+        }
+      }
+      else reRender(false)
+  }
+}
+
+case object ForceRender

Added: incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,95 @@
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package us.esme.comet
+
+import net.liftweb.http._
+import net.liftweb.util._
+import net.liftweb.util.Helpers._
+import scala.xml._
+import js._
+import JsCmds._
+import JE._
+
+import us.esme._
+import actor._
+import model._
+import lib._
+
+import java.text._
+
+class TagCloud extends CometActor with MsgFormat {
+
+  def defaultPrefix = "tagcloud"
+
+  private var messages: List[Long] = Nil
+  
+  override def localSetup() {
+    super.localSetup()
+    for (user <- User.currentUser) {
+      Distributor ! Distributor.Listen(user.id, this)
+      Distributor !? (2000, Distributor.LatestMessages(user.id, 40)) match {
+        case Some(msg: List[Long]) => messages = msg
+        case x =>
+      }
+    }
+  }
+  
+  override def localShutdown() {
+    super.localShutdown()
+    for (user <- User.currentUser) {
+      Distributor ! Distributor.Unlisten(user.id, this)
+    }
+  }
+
+  private def lookupMessages(): List[Message] = {
+    val mm = Message.findMessages(messages)
+    messages.flatMap(mm.get)
+  }
+
+  def render = {
+    val messages = lookupMessages()
+    //Sort the tags & words to put the most prominent in the middle
+    <div id="tagcloud">
+      <p id="tag-para">Tags</p>
+      <p>
+        {
+          for ((name, weight) <- Tag.centreWeightedTopNTagFreqs(messages, 20))
+          yield <xml:group><a href={"/tag/" + name}
+              style={"font-size: "+(0.5F + weight)+"em; text-decoration: none;"}>{
+                name}</a> </xml:group>
+        }
+      </p>
+      <p/>
+      <p id="word-para">Words</p>
+      <p>
+        {
+          for ((name, weight) <- Message.centreWeightedTopNWordFreqs(messages, 20))
+          yield <xml:group><a href={"/search/" + name}
+              style={"font-size: "+(0.5F + weight)+"em; text-decoration: none;"}>{
+                name}</a> </xml:group>
+        }
+      </p>
+    </div>
+  }
+
+
+  override def lowPriority = {
+    case UserActor.MessageReceived(msg, _) =>
+      messages = (msg.id.is :: messages).take(40)
+      reRender(false)
+  }
+}

Added: incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package us.esme.comet
+
+import net.liftweb.http._
+import net.liftweb.util._
+import net.liftweb.util.Helpers._
+import scala.xml._
+import js._
+import JsCmds._
+import JE._
+
+import us.esme._
+import actor._
+import model._
+import lib._
+
+import java.text._
+
+class Timeline extends CometActor with MsgFormat {
+
+  def defaultPrefix = "timeline"
+
+  private var messages: List[Long] = Nil
+  
+  override def localSetup() {
+    super.localSetup()
+    for (user <- User.currentUser) {
+      Distributor ! Distributor.Listen(user.id, this)
+      Distributor !? (200, Distributor.LatestMessages(user.id, 40)) match {
+        case Some(msg: List[Long]) => messages = msg
+        case x =>
+      }
+    }
+  }
+  
+  override def localShutdown() {
+    super.localShutdown()
+    for (user <- User.currentUser) {
+    Distributor ! Distributor.Unlisten(user.id, this)
+    }
+  }
+  
+  def render = {
+    val msgMap = Message.findMessages(messages)
+    val toDisplay = messages.flatMap(msgMap.get)
+  
+  <xml:group>
+    {
+      toDisplay.map(m => <xml:group>{formatMsg(m, true, true)}</xml:group>)
+    }
+  </xml:group>
+  }
+  
+  override implicit def xmlToXmlOrJsCmd(in: NodeSeq): RenderOut = new RenderOut(Full(in), fixedRender, Empty, Empty, false)
+
+  override def lowPriority = {
+    case UserActor.MessageReceived(msg, _) =>
+      messages = (msg.id.is :: messages).take(40)
+      reRender(false)
+      
+      case Distributor.UserUpdated(_) =>
+        reRender(false)
+  }
+}

Added: incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,56 @@
+package us.esme.external
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+import us.esme.actor.UniqueMessageSource
+import us.esme.actor.Distributor.UserCreatedMessage
+import us.esme.model.User
+
+import net.liftweb._
+import util._
+
+object TwitterFeed {
+  val UserTimelineUrl = "http://twitter.com/statuses/user_timeline/"
+  val Protocol = "xml"
+  val Params = ""
+  val tf = new java.text.SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", java.util.Locale.US)
+  
+}
+
+class TwitterFeed(val user: User, val twitterUser: String) extends UniqueMessageSource {
+  import java.net.{URLConnection, URL}
+  import scala.xml._
+  import TwitterFeed._
+
+  override def apply() = {
+    val url = new URL(UserTimelineUrl + twitterUser + "." + Protocol + Params)
+    val conn = url.openConnection()
+
+    
+    (for (node <- (XML.load(conn.getInputStream) \ "status")) yield UserCreatedMessage(
+      user.id,
+      node \ "text" text,
+      List("twitter"),
+      tf.parse(node \ "created_at" text).getTime,
+      Empty,
+      "twiiter",
+      Empty
+    )).toList
+  }
+  
+}
+

Added: incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,111 @@
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+package us.esme.lib
+
+import us.esme._
+import model._
+
+import scala.xml.{NodeSeq, Node, Text}
+
+import net.liftweb._
+import util._
+import http._
+import Helpers._
+
+import java.text.SimpleDateFormat
+
+object IsIE7 extends SessionVar[Boolean]({
+    // "Firefox/3"
+    // "MSIE 7"
+    def findUserAgent(in: List[(String, String)]): Can[String] =
+    in.filter(_._1.equalsIgnoreCase("User-Agent")).map(_._2).firstOption
+
+  val r: Can[Boolean] =
+  for (session <- S.session;
+       agent <- findUserAgent(session.initialHeaders)) yield
+  agent.indexOf("MSIE 7") >= 0
+
+  r openOr false
+})
+
+trait MsgFormat {
+  
+  def formatMsg(in: Message, showReply: Boolean, showConv: Boolean): NodeSeq =
+  formatMsg(in, showReply, showConv, Empty)
+
+  def formatMsg(in: Message, showReply: Boolean, showConv: Boolean,
+                inside: Can[() => NodeSeq]): NodeSeq =
+  <div class="b-list">
+    <table>
+      <tr>
+        <td class="image">{
+            val r: Can[NodeSeq] =
+            for (user <- in.author.obj;
+                 image <- user.image if !IsIE7.is) yield <img src={image} alt={user.niceName}/>
+
+            r openOr <xml:group>&nbsp;</xml:group>
+          }</td>
+        <td class="message">
+          <div class="outer">
+            <div class="inner clear">
+              <p class="text">{in.digestedXHTML}</p>
+            </div>
+            <p class="date">{in.author.obj.map(u => <a href={"/user/"+urlEncode(u.nickname)}>{u.niceName}</a>).openOr("")}: 
+              { dateFormat(in.when)} {
+                if (showReply) <a href={"javascript:setReplyTo("+in.id+","+
+                                        in.getText.encJs+
+                                        ")"}>reply</a>
+                else Text("")
+
+              }
+              {
+                in.conversation.can.toList.map(cid => <a href={"/conversation/"+cid}>conversation</a>)
+              }
+            </p>
+          </div>
+        </td>
+        <td class="tag">
+          {
+            in.tags.map(tag => <p><a href={"/tag/"+urlEncode(tag)}>{tag}</a></p>)
+          }
+        </td>
+      </tr>
+    </table>
+    {
+      inside.map(_()).openOr(Text(""))
+    }
+  </div>
+
+  private def dateFormat(in: Long): String = {
+    val delta = ((millis - in) / 1000L).toInt
+
+    delta match {
+      case 1 => "1 Second ago"
+      case n if n < 60 => ""+n+" Seconds ago"
+      case n if n >= 60 && n < 120 => "1 Minute ago"
+      case n if n < 3600 => ""+(n / 60)+" Minutes ago"
+      case n =>
+        (n / 3600) match {
+          case 1 => "1 Hour ago"
+          case n if n < 24 => ""+n+" Hours ago"
+          case _ => val df = new SimpleDateFormat("MM/dd HH:mm zzz")
+            dateFormatter.format(new java.util.Date(in))
+        }
+    }
+  }
+}



Mime
View raw message