Added to spatial parser support for parsing distances of miles and kilometers.
Project: http://git-wip-us.apache.org/repos/asf/incubator-blur/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-blur/commit/5e5200bd Tree: http://git-wip-us.apache.org/repos/asf/incubator-blur/tree/5e5200bd Diff: http://git-wip-us.apache.org/repos/asf/incubator-blur/diff/5e5200bd Branch: refs/heads/master Commit: 5e5200bd148c69c333fca43c4ca009e42e1e7304 Parents: 35b2828 Author: Aaron McCurry <[email protected]> Authored: Mon Aug 19 15:39:54 2013 -0400 Committer: Aaron McCurry <[email protected]> Committed: Mon Aug 19 15:39:54 2013 -0400 ---------------------------------------------------------------------- .../spatial/BaseSpatialFieldTypeDefinition.java | 1 - .../analysis/type/spatial/ShapeReadWriter.java | 177 +++++++++++++++++++ .../type/spatial/SpatialArgsParser.java | 1 - ...lPointVectorStrategyFieldTypeDefinition.java | 1 - ...vePrefixTreeStrategyFieldTypeDefinition.java | 1 - ...ryPrefixTreeStrategyFieldTypeDefinition.java | 1 - .../blur/lucene/search/SuperParserTest.java | 32 +++- docs/cluster-setup.html | 50 ++++++ docs/data-model.html | 8 + docs/getting-started.html | 48 +++-- 10 files changed, 304 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/BaseSpatialFieldTypeDefinition.java ---------------------------------------------------------------------- diff --git a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/BaseSpatialFieldTypeDefinition.java b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/BaseSpatialFieldTypeDefinition.java index a36e948..f1455ea 100644 --- a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/BaseSpatialFieldTypeDefinition.java +++ b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/BaseSpatialFieldTypeDefinition.java @@ -33,7 +33,6 @@ import org.apache.lucene.spatial.query.SpatialArgs; import org.apache.lucene.spatial.query.SpatialOperation; import com.spatial4j.core.context.SpatialContext; -import com.spatial4j.core.io.ShapeReadWriter; import com.spatial4j.core.shape.Shape; public abstract class BaseSpatialFieldTypeDefinition extends CustomFieldTypeDefinition { http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/ShapeReadWriter.java ---------------------------------------------------------------------- diff --git a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/ShapeReadWriter.java b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/ShapeReadWriter.java new file mode 100644 index 0000000..68ae050 --- /dev/null +++ b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/ShapeReadWriter.java @@ -0,0 +1,177 @@ +package org.apache.blur.analysis.type.spatial; + +import com.spatial4j.core.context.SpatialContext; +import com.spatial4j.core.distance.DistanceUtils; +import com.spatial4j.core.exception.InvalidShapeException; +import com.spatial4j.core.io.ParseUtils; +import com.spatial4j.core.shape.Circle; +import com.spatial4j.core.shape.Point; +import com.spatial4j.core.shape.Rectangle; +import com.spatial4j.core.shape.Shape; + +import java.text.NumberFormat; +import java.util.Locale; +import java.util.StringTokenizer; + +/** + * Reads and writes {@link Shape}s to strings. + */ +public class ShapeReadWriter<CTX extends SpatialContext> { + protected CTX ctx; + + @SuppressWarnings("unchecked") + public ShapeReadWriter(SpatialContext ctx) { + this.ctx = (CTX) ctx; + } + + /** + * Reads a shape from a given string (ie, X Y, XMin XMax... WKT) + * <ul> + * <li>Point: X Y <br /> + * 1.23 4.56</li> + * <li>BOX: XMin YMin XMax YMax <br /> + * 1.23 4.56 7.87 4.56</li> + * <li><a href="http://en.wikipedia.org/wiki/Well-known_text"> WKT (Well Known + * Text)</a> <br /> + * POLYGON( ... ) <br /> + * <b>Note:</b>Polygons and WKT might not be supported by this spatial + * context; you'll have to use + * {@link com.spatial4j.core.context.jts.JtsSpatialContext}.</li> + * </ul> + * + * @param value + * A string representation of the shape; not null. + * @return A Shape; not null. + * + * @see #writeShape + */ + public Shape readShape(String value) throws InvalidShapeException { + Shape s = readStandardShape(value); + if (s == null) { + throw new InvalidShapeException("Unable to read: " + value); + } + return s; + } + + /** + * Writes a shape to a String, in a format that can be read by + * {@link #readShape(String)}. + * + * @param shape + * Not null. + * @return Not null. + */ + public String writeShape(Shape shape) { + return writeShape(shape, makeNumberFormat(6)); + } + + /** Overloaded to provide a number format. */ + public String writeShape(Shape shape, NumberFormat nf) { + if (shape instanceof Point) { + Point point = (Point) shape; + return nf.format(point.getX()) + " " + nf.format(point.getY()); + } else if (shape instanceof Rectangle) { + Rectangle rect = (Rectangle) shape; + return nf.format(rect.getMinX()) + " " + nf.format(rect.getMinY()) + " " + nf.format(rect.getMaxX()) + " " + + nf.format(rect.getMaxY()); + } else if (shape instanceof Circle) { + Circle c = (Circle) shape; + return "Circle(" + nf.format(c.getCenter().getX()) + " " + nf.format(c.getCenter().getY()) + " " + "d=" + + nf.format(c.getRadius()) + ")"; + } + return shape.toString(); + } + + /** + * A convenience method to create a suitable NumberFormat for writing numbers. + */ + public static NumberFormat makeNumberFormat(int fractionDigits) { + NumberFormat nf = NumberFormat.getInstance(Locale.ROOT);// not thread-safe + nf.setGroupingUsed(false); + nf.setMaximumFractionDigits(fractionDigits); + nf.setMinimumFractionDigits(fractionDigits); + return nf; + } + + protected Shape readStandardShape(String str) { + if (str == null || str.length() == 0) { + throw new InvalidShapeException(str); + } + + if (Character.isLetter(str.charAt(0))) { + if (str.startsWith("Circle(") || str.startsWith("CIRCLE(")) { + int idx = str.lastIndexOf(')'); + if (idx > 0) { + String body = str.substring("Circle(".length(), idx); + StringTokenizer st = new StringTokenizer(body, " "); + String token = st.nextToken(); + Point pt; + if (token.indexOf(',') != -1) { + pt = readLatCommaLonPoint(token); + } else { + double x = Double.parseDouble(token); + double y = Double.parseDouble(st.nextToken()); + pt = ctx.makePoint(x, y); + } + Double d = null; + + String arg = st.nextToken(); + idx = arg.indexOf('='); + if (idx > 0) { + String k = arg.substring(0, idx); + if (k.equals("d") || k.equals("distance")) { + d = parseDistance(arg.substring(idx + 1)); + } else { + throw new InvalidShapeException("unknown arg: " + k + " :: " + str); + } + } else { + d = parseDistance(arg); + } + if (st.hasMoreTokens()) { + throw new InvalidShapeException("Extra arguments: " + st.nextToken() + " :: " + str); + } + if (d == null) { + throw new InvalidShapeException("Missing Distance: " + str); + } + // NOTE: we are assuming the units of 'd' is the same as that of the + // spatial context. + return ctx.makeCircle(pt, d); + } + } + return null; + } + + if (str.indexOf(',') != -1) + return readLatCommaLonPoint(str); + StringTokenizer st = new StringTokenizer(str, " "); + double p0 = Double.parseDouble(st.nextToken()); + double p1 = Double.parseDouble(st.nextToken()); + if (st.hasMoreTokens()) { + double p2 = Double.parseDouble(st.nextToken()); + double p3 = Double.parseDouble(st.nextToken()); + if (st.hasMoreTokens()) + throw new InvalidShapeException("Only 4 numbers supported (rect) but found more: " + str); + return ctx.makeRectangle(p0, p2, p1, p3); + } + return ctx.makePoint(p0, p1); + } + + private static Double parseDistance(String distanceString) { + distanceString = distanceString.toLowerCase(); + if (distanceString.endsWith("km")) { + double distanceInKm = Double.parseDouble(distanceString.substring(0, distanceString.length() - 2)); + return DistanceUtils.dist2Degrees(distanceInKm, DistanceUtils.EARTH_MEAN_RADIUS_KM); + } else if (distanceString.endsWith("m")) { + double distanceInM = Double.parseDouble(distanceString.substring(0, distanceString.length() - 2)); + double distanceInKm = distanceInM * DistanceUtils.MILES_TO_KM; + return DistanceUtils.dist2Degrees(distanceInKm, DistanceUtils.EARTH_MEAN_RADIUS_KM); + } + return Double.parseDouble(distanceString); + } + + /** Reads geospatial latitude then a comma then longitude. */ + private Point readLatCommaLonPoint(String value) throws InvalidShapeException { + double[] latLon = ParseUtils.parseLatitudeLongitude(value); + return ctx.makePoint(latLon[1], latLon[0]); + } +} http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialArgsParser.java ---------------------------------------------------------------------- diff --git a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialArgsParser.java b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialArgsParser.java index 1afcaad..17c7590 100644 --- a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialArgsParser.java +++ b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialArgsParser.java @@ -19,7 +19,6 @@ package org.apache.blur.analysis.type.spatial; import com.spatial4j.core.context.SpatialContext; import com.spatial4j.core.exception.InvalidShapeException; -import com.spatial4j.core.io.ShapeReadWriter; import com.spatial4j.core.shape.Shape; import java.util.HashMap; http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialPointVectorStrategyFieldTypeDefinition.java ---------------------------------------------------------------------- diff --git a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialPointVectorStrategyFieldTypeDefinition.java b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialPointVectorStrategyFieldTypeDefinition.java index 46149ab..093016e 100644 --- a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialPointVectorStrategyFieldTypeDefinition.java +++ b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialPointVectorStrategyFieldTypeDefinition.java @@ -26,7 +26,6 @@ import org.apache.lucene.spatial.query.SpatialOperation; import org.apache.lucene.spatial.vector.PointVectorStrategy; import com.spatial4j.core.context.SpatialContext; -import com.spatial4j.core.io.ShapeReadWriter; import com.spatial4j.core.shape.Point; public class SpatialPointVectorStrategyFieldTypeDefinition extends BaseSpatialFieldTypeDefinition { http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialRecursivePrefixTreeStrategyFieldTypeDefinition.java ---------------------------------------------------------------------- diff --git a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialRecursivePrefixTreeStrategyFieldTypeDefinition.java b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialRecursivePrefixTreeStrategyFieldTypeDefinition.java index 8a82236..b6c7798 100644 --- a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialRecursivePrefixTreeStrategyFieldTypeDefinition.java +++ b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialRecursivePrefixTreeStrategyFieldTypeDefinition.java @@ -23,7 +23,6 @@ import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree; import org.apache.lucene.spatial.query.SpatialOperation; import com.spatial4j.core.context.SpatialContext; -import com.spatial4j.core.io.ShapeReadWriter; import com.spatial4j.core.shape.Shape; public class SpatialRecursivePrefixTreeStrategyFieldTypeDefinition extends BaseSpatialFieldTypeDefinition { http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialTermQueryPrefixTreeStrategyFieldTypeDefinition.java ---------------------------------------------------------------------- diff --git a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialTermQueryPrefixTreeStrategyFieldTypeDefinition.java b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialTermQueryPrefixTreeStrategyFieldTypeDefinition.java index f7af3a2..a97a813 100644 --- a/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialTermQueryPrefixTreeStrategyFieldTypeDefinition.java +++ b/blur-query/src/main/java/org/apache/blur/analysis/type/spatial/SpatialTermQueryPrefixTreeStrategyFieldTypeDefinition.java @@ -23,7 +23,6 @@ import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree; import org.apache.lucene.spatial.query.SpatialOperation; import com.spatial4j.core.context.SpatialContext; -import com.spatial4j.core.io.ShapeReadWriter; import com.spatial4j.core.shape.Point; public class SpatialTermQueryPrefixTreeStrategyFieldTypeDefinition extends BaseSpatialFieldTypeDefinition { http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/blur-query/src/test/java/org/apache/blur/lucene/search/SuperParserTest.java ---------------------------------------------------------------------- diff --git a/blur-query/src/test/java/org/apache/blur/lucene/search/SuperParserTest.java b/blur-query/src/test/java/org/apache/blur/lucene/search/SuperParserTest.java index 52c1051..12f5029 100644 --- a/blur-query/src/test/java/org/apache/blur/lucene/search/SuperParserTest.java +++ b/blur-query/src/test/java/org/apache/blur/lucene/search/SuperParserTest.java @@ -11,6 +11,7 @@ import java.util.List; import org.apache.blur.analysis.BaseFieldManager; import org.apache.blur.analysis.FieldTypeDefinition; import org.apache.blur.analysis.NoStopWordStandardAnalyzer; +import org.apache.blur.analysis.type.spatial.ShapeReadWriter; import org.apache.blur.analysis.type.spatial.SpatialArgsParser; import org.apache.blur.thrift.generated.ScoreType; import org.apache.blur.utils.BlurConstants; @@ -36,7 +37,6 @@ import org.junit.Test; import com.spatial4j.core.context.SpatialContext; import com.spatial4j.core.distance.DistanceUtils; -import com.spatial4j.core.io.ShapeReadWriter; import com.spatial4j.core.shape.Circle; public class SuperParserTest { @@ -340,6 +340,36 @@ public class SuperParserTest { boolean equals = q1.equals(q); assertTrue(equals); } + + @Test + public void test29() throws ParseException { + SpatialContext ctx = SpatialContext.GEO; + int maxLevels = 11; + SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels); + RecursivePrefixTreeStrategy strategy = new RecursivePrefixTreeStrategy(grid, "a.id_gis"); + Circle circle = ctx.makeCircle(-80.0, 33.0, DistanceUtils.dist2Degrees(10, DistanceUtils.EARTH_MEAN_RADIUS_KM)); + SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, circle); + + Query q1 = sq(strategy.makeQuery(args)); + Query q = parseSq("a.id_gis:\"Intersects(Circle(33.000000,-80.000000 d=10.0km))\""); + boolean equals = q1.equals(q); + assertTrue(equals); + } + + @Test + public void test30() throws ParseException { + SpatialContext ctx = SpatialContext.GEO; + int maxLevels = 11; + SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels); + RecursivePrefixTreeStrategy strategy = new RecursivePrefixTreeStrategy(grid, "a.id_gis"); + Circle circle = ctx.makeCircle(-80.0, 33.0, DistanceUtils.dist2Degrees(10, DistanceUtils.EARTH_MEAN_RADIUS_MI)); + SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, circle); + + Query q1 = sq(strategy.makeQuery(args)); + Query q = parseSq("a.id_gis:\"Intersects(Circle(33.000000,-80.000000 d=10.0m))\""); + boolean equals = q1.equals(q); + assertTrue(equals); + } public static BooleanClause bc_m(Query q) { return new BooleanClause(q, Occur.MUST); http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/docs/cluster-setup.html ---------------------------------------------------------------------- diff --git a/docs/cluster-setup.html b/docs/cluster-setup.html index 39854a9..b46b8eb 100644 --- a/docs/cluster-setup.html +++ b/docs/cluster-setup.html @@ -50,6 +50,13 @@ <div class="col-md-3"> <div class="bs-sidebar hidden-print affix" role="complementary"> <ul class="nav bs-sidenav"> + <li> + <a href="#general">General Configuration</a> + <ul class="nav"> + <li><a href="#general-blur-site">blur-site.properties</a></li> + <li><a href="#general-hadoop">Hadoop</a></li> + </ul> + </li> <li> <a href="#controller">Controller Server Configuration</a> <ul class="nav"> @@ -78,6 +85,49 @@ <div class="col-md-9" role="main"> <section> <div class="page-header"> + <h1 id="general">General Configuration</h1> + </div> + <h3 id="general-blur-site">blur-site.properties</h3> + <p> +<pre> +<code class="bash"> +# The ZooKeeper connection string, consider adding a root path to the string it +# can help when upgrading Blur. +# Example: zknode1:2181,zknode2:2181,zknode3:2181/blur-0.2.0 +# +# NOTE: If you provide the root path "/blur-0.2.0", that will have to be manually +# created before Blur will start. + +blur.zookeeper.connection=127.0.0.1 + +# If you are only going to run a single shard cluster then leave this as default. + +blur.cluster.name=default + +# Sets the default table location in hdfs. If left null or omitted the table uri property in +# the table descriptor will be required for all tables. + +blur.cluster.default.table.uri=hdfs://namenode/blur/tables + +</code> +</pre> + </p> + <h3 id="general-hadoop">Hadoop</h3> +<p> +The current version of Blur has Hadoop 1.2.1 embedded in the "apache-blur-*/lib/hadoop-1.2.1" path. However if +you are using a different version of Hadoop or want Blur to use the Hadoop configuration in your installed +version you will need to set the "HADOOP_HOME" environment variable in the +"blur-env.sh" script found in "apache-blur-*/conf/". +<pre> +<code class="bash"> +# Edit the blur-env.sh +export HADOOP_HOME=<path to your Hadoop install directory> +</code> +</pre> +</p> + </section> + <section> + <div class="page-header"> <h1 id="controller">Controller Server Configuration</h1> </div> <h3 id="controller-blur-site">blur-site.properties</h3> http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/docs/data-model.html ---------------------------------------------------------------------- diff --git a/docs/data-model.html b/docs/data-model.html index a07eacf..0a72295 100644 --- a/docs/data-model.html +++ b/docs/data-model.html @@ -258,6 +258,14 @@ shapes per strategy. To run a query to find all the rows that contain a location within 10 km (0.089932 10 km in degrees) of gis coordinate "33.0, -88.0" where the family is "docs" and the column is "location". <pre><code class="json">docs.location:"Intersects(Circle(33.0, -88.0 d=0.089932))"</code></pre> </p> +<p> +To run a query to find all the rows that contain a location within 10 km of gis coordinate "33.0, -88.0" where the family is "docs" and the column is "location". +<pre><code class="json">docs.location:"Intersects(Circle(33.0, -88.0 d=10.0km))"</code></pre> +</p> +<p> +To run a query to find all the rows that contain a location within 10 miles of gis coordinate "33.0, -88.0" where the family is "docs" and the column is "location". +<pre><code class="json">docs.location:"Intersects(Circle(33.0, -88.0 d=10.0m))"</code></pre> +</p> </div> </section> <section> http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/5e5200bd/docs/getting-started.html ---------------------------------------------------------------------- diff --git a/docs/getting-started.html b/docs/getting-started.html index 6a9f2a7..f7bc169 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -57,7 +57,15 @@ <li><a href="#min-config">Minimum Configuration</a></li> <li><a href="#start">Starting Apache Blur</a></li> <li><a href="#shell">Shell</a></li> - <li><a href="#shell-example">Simple Shell Example</a></li> + <li><a href="#shell-example">Simple Shell Example</a> + <ul class="nav"> + <li><a href="#shell-create">Create Table</a></li> + <li><a href="#shell-mutate">Mutate</a></li> + <li><a href="#shell-query">Query</a></li> + <li><a href="#shell-enable-highlighting">Enable Highlighting</a></li> + <li><a href="#shell-query-highlight">Query with Highlights</a></li> + </ul> + </li> </ul> </div> </div> @@ -179,12 +187,22 @@ localhost: Stopping ZooKeeper with pid [6650].</code></pre> <p class="lead"> The below example creates a table and stores the contents of the table in a local directory of /data/testTableName which will only work if you are running blur in a single instance. Normally if you are running a hadoop cluster this will be a hdfs URI for example hdfs://host:port/blur/tables/testTableName. </p> +<h3 id="shell-create">Create Table</h3> +<p> <pre><code class="bash">blur> #Creates a table called testtable in the local directory of /data/testtable with 11 shards blur> create testtable file:///data/testtable 11 -blur> +</code></pre> +</p> +<h3 id="shell-mutate">Mutate</h3> +<p> +<pre><code class="bash"> blur> #Adds a row to testtable -blur> mutate testtable 1 1 fam0 col1 value1 -blur> +blur> mutate testtable rowid1 recordid1 fam0 col1 value1 +</code></pre> +</p> +<h3 id="shell-query">Query</h3> +<p> +<pre><code class="bash"> blur> #Runs a query on testtable blur> query testtable fam0.col1:value1 - Results Summary - @@ -193,19 +211,27 @@ blur> query testtable fam0.col1:value1 ----------------------------------------------------------------------------------------------------- hit : 0 score : 1.4142135381698608 - id : 1 - recordId : 1 + id : rowid1 + recordId : recordid1 family : fam0 col1 : value1 ----------------------------------------------------------------------------------------------------- - Results Summary - total : 1 time : 7.874 ms -blur> +</code></pre> +</p> +<h3 id="shell-enable-highlighting">Enable Highlighting</h3> +<p> +<pre><code class="bash"> blur> #Turns highlighting on blur> highlight highlight of query command is now on -blur> +</code></pre> +</p> +<h3 id="shell-query-highlight">Query with Highlights</h3> +<p> +<pre><code class="bash"> blur> #Runs a query on testtable with highlighting on, notice <<<value1>>> is highlighted blur> query testtable2 fam0.col1:value1 - Results Summary - @@ -214,8 +240,8 @@ blur> query testtable2 fam0.col1:value1 ----------------------------------------------------------------------------------------------------- hit : 0 score : 1.4142135381698608 - id : 1 - recordId : 1 + id : rowid1 + recordId : recordid1 family : fam0 col1 : <<<value1>>> ----------------------------------------------------------------------------------------------------- @@ -227,6 +253,8 @@ blur></code></pre> </div> </div> </div> + +<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="resources/js/jquery-2.0.3.min.js"></script>
