From 42484f064f4708fbe63b7d2ec4ea8b783343b183 Mon Sep 17 00:00:00 2001 From: QJonny Date: Tue, 6 Nov 2012 17:58:41 +0100 Subject: [PATCH] front-end with play --- .gitignore | 7 + README | 4 + app/controllers/Application.scala | 51 + .../generators/LinkGenerator.scala | 0 app/generators/SchedulePdfGenerator.scala | 214 + app/generators/TaskProcessGenerator.scala | 46 + app/paper/Analyze.scala | 64 + app/paper/ComparePaper.scala | 51 + app/paper/ExtendPaper.scala | 105 + app/paper/FileFormat.scala | 72 + app/paper/FileLoader.scala | 112 + app/paper/Graph.scala | 100 + app/paper/InformationExtractors.scala | 180 + app/paper/LoadPaper.scala | 232 + app/paper/ParsePaper.scala | 273 + app/paper/RecognitionClasses.scala | 124 + app/paper/Terms.scala | 106 + app/paper/XMLObjects.scala | 108 + app/paper/XMLObjectsManager.scala | 115 + app/paper/XMLParagraphsConstructor.scala | 180 + app/paper/XMLParser.scala | 79 + app/paper/XMLScheduleParser.scala | 153 + ajax.php => app/views/ajax.php | 4 +- index.html => app/views/index.scala.html | 82 +- schedule.php => app/views/schedule.php | 11 +- cache/1569557585.pdf.parsed | 34 + cache/1569558325.pdf.parsed | 142 + cache/1569566229.pdf.parsed | 158 + cache/1569566239.pdf.parsed | 150 + cache/1569567045.pdf.bad | 0 conf/application.conf | 48 + conf/routes | 17 + lib/d3 | 1 - pdf2xml.dtd | 28 + project/Build.scala | 18 + project/build.properties | 1 + project/plugins.sbt | 8 + enumitem.sty => public/enumitem.sty | 0 {img => public/img}/ajax-loader.gif | Bin {img => public/img}/ajax-loader_dark.gif | Bin {img => public/img}/current.png | Bin .../img}/iconic_icons/ampersand_9x16.png | Bin .../img}/iconic_icons/aperture_16x16.png | Bin .../img}/iconic_icons/aperture_alt_16x16.png | Bin .../img}/iconic_icons/arrow_down_16x16.png | Bin .../iconic_icons/arrow_down_alt1_16x16.png | Bin .../iconic_icons/arrow_down_alt2_16x16.png | Bin .../img}/iconic_icons/arrow_left_16x16.png | Bin .../iconic_icons/arrow_left_alt1_16x16.png | Bin .../iconic_icons/arrow_left_alt2_16x16.png | Bin .../img}/iconic_icons/arrow_right_16x16.png | Bin .../iconic_icons/arrow_right_alt1_16x16.png | Bin .../iconic_icons/arrow_right_alt2_16x16.png | Bin .../img}/iconic_icons/arrow_up_16x16.png | Bin .../img}/iconic_icons/arrow_up_alt1_16x16.png | Bin .../img}/iconic_icons/arrow_up_alt2_16x16.png | Bin .../img}/iconic_icons/article_16x16.png | Bin {img => public/img}/iconic_icons/at_16x16.png | Bin .../img}/iconic_icons/award_fill_8x16.png | Bin .../img}/iconic_icons/award_stroke_8x16.png | Bin .../img}/iconic_icons/bars_16x16.png | Bin .../img}/iconic_icons/bars_alt_14x16.png | Bin .../iconic_icons/battery_charging_16x8.png | Bin .../img}/iconic_icons/battery_empty_16x8.png | Bin .../img}/iconic_icons/battery_full_16x8.png | Bin .../img}/iconic_icons/battery_half_16x8.png | Bin .../img}/iconic_icons/beaker_8x16.png | Bin .../img}/iconic_icons/beaker_alt_8x16.png | Bin .../img}/iconic_icons/bolt_16x16.png | Bin .../img}/iconic_icons/book_14x16.png | Bin .../img}/iconic_icons/book_alt2_16x14.png | Bin .../img}/iconic_icons/book_alt_16x16.png | Bin .../img}/iconic_icons/box_16x16.png | Bin .../img}/iconic_icons/brush_16x16.png | Bin .../img}/iconic_icons/brush_alt_16x16.png | Bin .../img}/iconic_icons/calendar_16x16.png | Bin .../iconic_icons/calendar_alt_fill_16x16.png | Bin .../calendar_alt_stroke_16x16.png | Bin .../img}/iconic_icons/camera_16x16.png | Bin {img => public/img}/iconic_icons/cd_16x16.png | Bin .../img}/iconic_icons/chart_16x16.png | Bin .../img}/iconic_icons/chart_alt_15x16.png | Bin .../img}/iconic_icons/chat_16x16.png | Bin .../img}/iconic_icons/chat_alt_fill_16x16.png | Bin .../iconic_icons/chat_alt_stroke_16x16.png | Bin .../img}/iconic_icons/check_16x13.png | Bin .../img}/iconic_icons/check_alt_16x16.png | Bin .../img}/iconic_icons/clock_16x16.png | Bin .../img}/iconic_icons/cloud_16x10.png | Bin .../iconic_icons/cloud_download_16x16.png | Bin .../img}/iconic_icons/cloud_upload_16x16.png | Bin .../img}/iconic_icons/cog_16x16.png | Bin .../iconic_icons/comment_alt1_fill_16x12.png | Bin .../comment_alt1_stroke_16x12.png | Bin .../iconic_icons/comment_alt2_fill_14x16.png | Bin .../comment_alt2_stroke_14x16.png | Bin .../img}/iconic_icons/comment_fill_16x14.png | Bin .../iconic_icons/comment_stroke_16x14.png | Bin .../img}/iconic_icons/compass_16x16.png | Bin .../img}/iconic_icons/cursor_16x16.png | Bin .../img}/iconic_icons/curved_arrow_16x12.png | Bin .../img}/iconic_icons/denied_16x16.png | Bin .../img}/iconic_icons/dial_16x16.png | Bin .../iconic_icons/document_alt_fill_12x16.png | Bin .../document_alt_stroke_12x16.png | Bin .../img}/iconic_icons/document_fill_16x16.png | Bin .../iconic_icons/document_stroke_16x16.png | Bin .../img}/iconic_icons/download_12x16.png | Bin .../img}/iconic_icons/eject_16x16.png | Bin .../img}/iconic_icons/equalizer_16x16.png | Bin .../img}/iconic_icons/eye_16x12.png | Bin .../img}/iconic_icons/eyedropper_16x16.png | Bin .../img}/iconic_icons/first_16x16.png | Bin .../img}/iconic_icons/folder_fill_16x16.png | Bin .../img}/iconic_icons/folder_stroke_16x16.png | Bin .../img}/iconic_icons/fork_14x16.png | Bin .../img}/iconic_icons/fullscreen_16x16.png | Bin .../iconic_icons/fullscreen_alt_16x16.png | Bin .../iconic_icons/fullscreen_exit_16x16.png | Bin .../fullscreen_exit_alt_16x16.png | Bin .../img}/iconic_icons/hash_14x16.png | Bin .../img}/iconic_icons/headphones_16x14.png | Bin .../img}/iconic_icons/heart_fill_16x14.png | Bin .../img}/iconic_icons/heart_stroke_16x14.png | Bin .../img}/iconic_icons/home_16x16.png | Bin .../img}/iconic_icons/image_16x16.png | Bin .../img}/iconic_icons/info_8x16.png | Bin .../img}/iconic_icons/iphone_12x16.png | Bin .../img}/iconic_icons/key_fill_16x16.png | Bin .../img}/iconic_icons/key_stroke_16x16.png | Bin .../img}/iconic_icons/last_16x16.png | Bin .../img}/iconic_icons/layers_16x14.png | Bin .../img}/iconic_icons/layers_alt_16x16.png | Bin .../img}/iconic_icons/left_quote_16x12.png | Bin .../iconic_icons/left_quote_alt_16x12.png | Bin .../img}/iconic_icons/lightbulb_10x16.png | Bin .../img}/iconic_icons/link_16x16.png | Bin .../img}/iconic_icons/list_16x14.png | Bin .../img}/iconic_icons/list_nested_16x14.png | Bin .../img}/iconic_icons/lock_fill_12x16.png | Bin .../img}/iconic_icons/lock_stroke_12x16.png | Bin .../img}/iconic_icons/loop_16x16.png | Bin .../img}/iconic_icons/loop_alt1_16x12.png | Bin .../img}/iconic_icons/loop_alt2_16x14.png | Bin .../img}/iconic_icons/loop_alt3_16x12.png | Bin .../img}/iconic_icons/loop_alt4_16x12.png | Bin .../iconic_icons/magnifying_glass_16x16.png | Bin .../img}/iconic_icons/mail_16x12.png | Bin .../img}/iconic_icons/map_pin_alt_8x16.png | Bin .../img}/iconic_icons/map_pin_fill_10x16.png | Bin .../iconic_icons/map_pin_stroke_10x16.png | Bin .../img}/iconic_icons/mic_12x16.png | Bin .../img}/iconic_icons/minus_16x4.png | Bin .../img}/iconic_icons/minus_alt_16x16.png | Bin .../img}/iconic_icons/moon_fill_16x16.png | Bin .../img}/iconic_icons/moon_stroke_16x16.png | Bin .../img}/iconic_icons/move_16x16.png | Bin .../img}/iconic_icons/move_alt1_16x16.png | Bin .../img}/iconic_icons/move_alt2_16x16.png | Bin .../iconic_icons/move_horizontal_16x6.png | Bin .../move_horizontal_alt1_16x6.png | Bin .../move_horizontal_alt2_16x16.png | Bin .../img}/iconic_icons/move_vertical_6x16.png | Bin .../iconic_icons/move_vertical_alt1_6x16.png | Bin .../iconic_icons/move_vertical_alt2_16x16.png | Bin .../img}/iconic_icons/movie_16x16.png | Bin .../img}/iconic_icons/new_window_16x16.png | Bin .../img}/iconic_icons/pause_12x16.png | Bin .../img}/iconic_icons/pen_16x16.png | Bin .../img}/iconic_icons/pen_alt2_16x16.png | Bin .../img}/iconic_icons/pen_alt_fill_16x16.png | Bin .../iconic_icons/pen_alt_stroke_16x16.png | Bin .../img}/iconic_icons/pilcrow_12x16.png | Bin .../img}/iconic_icons/pin_16x16.png | Bin .../img}/iconic_icons/play_12x16.png | Bin .../img}/iconic_icons/play_alt_16x16.png | Bin .../img}/iconic_icons/plus_16x16.png | Bin .../img}/iconic_icons/plus_alt_16x16.png | Bin .../img}/iconic_icons/question_mark_8x16.png | Bin .../img}/iconic_icons/rain_16x14.png | Bin .../img}/iconic_icons/read_more_16x16.png | Bin .../img}/iconic_icons/reload_12x14.png | Bin .../img}/iconic_icons/reload_alt_12x14.png | Bin .../img}/iconic_icons/right_quote_16x12.png | Bin .../iconic_icons/right_quote_alt_16x12.png | Bin .../img}/iconic_icons/rss_16x16.png | Bin .../img}/iconic_icons/rss_alt_16x16.png | Bin .../img}/iconic_icons/share_16x16.png | Bin .../img}/iconic_icons/spin_14x16.png | Bin .../img}/iconic_icons/spin_alt_16x16.png | Bin .../img}/iconic_icons/star_16x16.png | Bin .../iconic_icons/steering_wheel_16x16.png | Bin .../img}/iconic_icons/stop_16x16.png | Bin .../img}/iconic_icons/sun_fill_16x16.png | Bin .../img}/iconic_icons/sun_stroke_16x16.png | Bin .../img}/iconic_icons/tag_fill_16x16.png | Bin .../img}/iconic_icons/tag_stroke_16x16.png | Bin .../img}/iconic_icons/target_16x16.png | Bin .../img}/iconic_icons/transfer_16x12.png | Bin .../img}/iconic_icons/trash_fill_16x16.png | Bin .../img}/iconic_icons/trash_stroke_16x16.png | Bin .../img}/iconic_icons/umbrella_16x16.png | Bin .../img}/iconic_icons/undo_16x16.png | Bin .../img}/iconic_icons/unlock_fill_12x16.png | Bin .../img}/iconic_icons/unlock_stroke_12x16.png | Bin .../img}/iconic_icons/upload_12x16.png | Bin .../img}/iconic_icons/user_12x16.png | Bin .../img}/iconic_icons/volume_16x12.png | Bin .../img}/iconic_icons/volume_mute_16x12.png | Bin .../img}/iconic_icons/wrench_16x16.png | Bin {img => public/img}/iconic_icons/x_14x14.png | Bin .../img}/iconic_icons/x_alt_16x16.png | Bin {img => public/img}/icons/authors.png | Bin {img => public/img}/icons/calendar.png | Bin {img => public/img}/icons/calendar_light.png | Bin {img => public/img}/icons/contract.png | Bin {img => public/img}/icons/create.png | Bin {img => public/img}/icons/download.png | Bin {img => public/img}/icons/download_light.png | Bin {img => public/img}/icons/expand.png | Bin {img => public/img}/icons/info.png | Bin {img => public/img}/icons/info_light.png | Bin {img => public/img}/icons/move.png | Bin {img => public/img}/icons/paper.png | Bin {img => public/img}/icons/remove.png | Bin {img => public/img}/icons/schedule.png | Bin {img => public/img}/icons/search.png | Bin {img => public/img}/icons/talk.png | Bin {img => public/img}/icons/time.png | Bin {img => public/img}/icons/title.png | Bin {img => public/img}/icons/title2.png | Bin {img => public/img}/icons/title3.png | Bin {img => public/img}/icons/zoom.png | Bin {img => public/img}/icons1/expand.png | Bin {img => public/img}/icons1/paper.png | Bin {img => public/img}/icons1/remove.png | Bin {img => public/img}/icons1/search.png | Bin {img => public/img}/icons2/expand.png | Bin {img => public/img}/icons2/paper.png | Bin {img => public/img}/icons2/remove.png | Bin {img => public/img}/icons2/search.png | Bin {img => public/img}/icons4/expand.png | Bin {img => public/img}/icons4/paper.png | Bin {img => public/img}/icons4/remove.png | Bin {img => public/img}/icons4/search.png | Bin {img => public/img}/logo/logo.png | Bin {img => public/img}/logo/logo.svg | 0 {img => public/img}/node.png | Bin {img => public/img}/pointer1.png | Bin {img => public/img}/pointer2.png | Bin {img => public/img}/pointer3.png | Bin {img => public/img}/pointer4.png | Bin {img => public/img}/pointer5.png | Bin {img => public/img}/pointer6.png | Bin {img => public/img}/searchresult.png | Bin {img => public/img}/selected.png | Bin {js => public/js}/cookie.js | 0 {js => public/js}/data.json | 1270 +-- {js => public/js}/data_test.json~ | 0 {js => public/js}/graph.js | 0 {js => public/js}/ui.js | 2 +- {js => public/js}/util.js | 0 public/lib/d3/.gitignore | 3 + public/lib/d3/.gitmodules | 0 public/lib/d3/.npmignore | 4 + public/lib/d3/LICENSE | 26 + public/lib/d3/Makefile | 268 + public/lib/d3/README.md | 51 + public/lib/d3/d3.chart.js | 984 +++ public/lib/d3/d3.chart.min.js | 1 + public/lib/d3/d3.csv.js | 92 + public/lib/d3/d3.csv.min.js | 1 + public/lib/d3/d3.geo.js | 938 +++ public/lib/d3/d3.geo.min.js | 1 + public/lib/d3/d3.geom.js | 835 ++ public/lib/d3/d3.geom.min.js | 1 + public/lib/d3/d3.js | 4695 +++++++++++ public/lib/d3/d3.layout.js | 1889 +++++ public/lib/d3/d3.layout.min.js | 1 + public/lib/d3/d3.min.js | 2 + public/lib/d3/d3.time.js | 687 ++ public/lib/d3/d3.time.min.js | 1 + public/lib/d3/examples/albers/albers.html | 168 + public/lib/d3/examples/area/area-radial.html | 48 + public/lib/d3/examples/area/area.html | 113 + .../d3/examples/axis/axis-alternating.html | 50 + public/lib/d3/examples/axis/axis-ggplot2.html | 68 + .../lib/d3/examples/axis/axis-multiples.html | 117 + .../d3/examples/axis/axis-orientations.html | 63 + .../lib/d3/examples/axis/axis-transition.html | 153 + .../lib/d3/examples/azimuthal/azimuthal.css | 21 + .../lib/d3/examples/azimuthal/azimuthal.html | 99 + public/lib/d3/examples/azimuthal/azimuthal.js | 29 + public/lib/d3/examples/bar/bar-hierarchy.html | 223 + public/lib/d3/examples/bar/bar.html | 101 + public/lib/d3/examples/bar/sample-data.csv | 53 + public/lib/d3/examples/bonne/bonne.html | 159 + public/lib/d3/examples/box/box.css | 4 + public/lib/d3/examples/box/box.html | 19 + public/lib/d3/examples/box/box.js | 68 + .../lib/d3/examples/brush/brush-ordinal.html | 92 + public/lib/d3/examples/brush/brush-x.html | 92 + public/lib/d3/examples/brush/brush-y.html | 91 + public/lib/d3/examples/brush/brush.html | 98 + public/lib/d3/examples/bubble/bubble.css | 8 + public/lib/d3/examples/bubble/bubble.html | 14 + public/lib/d3/examples/bubble/bubble.js | 46 + public/lib/d3/examples/bullet/bullet.css | 10 + public/lib/d3/examples/bullet/bullet.html | 18 + public/lib/d3/examples/bullet/bullet.js | 53 + public/lib/d3/examples/bullet/bullets.json | 7 + .../lib/d3/examples/bundle/bundle-radial.css | 9 + .../lib/d3/examples/bundle/bundle-radial.html | 15 + .../lib/d3/examples/bundle/bundle-radial.js | 50 + .../lib/d3/examples/bundle/bundle-treemap.css | 14 + .../d3/examples/bundle/bundle-treemap.html | 16 + .../lib/d3/examples/bundle/bundle-treemap.js | 53 + public/lib/d3/examples/bundle/packages.js | 49 + public/lib/d3/examples/button.css | 35 + public/lib/d3/examples/calendar/calendar.css | 15 + public/lib/d3/examples/calendar/dji-area.html | 120 + public/lib/d3/examples/calendar/dji.csv | 5233 +++++++++++++ public/lib/d3/examples/calendar/dji.html | 15 + public/lib/d3/examples/calendar/dji.js | 69 + public/lib/d3/examples/calendar/vix.csv | 5231 +++++++++++++ public/lib/d3/examples/calendar/vix.html | 15 + public/lib/d3/examples/calendar/vix.js | 69 + .../lib/d3/examples/cartogram/cartogram.css | 20 + .../lib/d3/examples/cartogram/cartogram.html | 15 + public/lib/d3/examples/cartogram/cartogram.js | 51 + public/lib/d3/examples/cartogram/demers.css | 9 + public/lib/d3/examples/cartogram/demers.html | 16 + public/lib/d3/examples/cartogram/demers.js | 79 + public/lib/d3/examples/cartogram/dorling.css | 9 + public/lib/d3/examples/cartogram/dorling.html | 16 + public/lib/d3/examples/cartogram/dorling.js | 80 + public/lib/d3/examples/chord/chord-flare.html | 109 + public/lib/d3/examples/chord/chord.css | 9 + public/lib/d3/examples/chord/chord.html | 14 + public/lib/d3/examples/chord/chord.js | 98 + .../examples/choropleth/choropleth-area.html | 51 + .../choropleth/choropleth-bounds.html | 46 + .../lib/d3/examples/choropleth/choropleth.css | 16 + .../d3/examples/choropleth/choropleth.html | 15 + .../lib/d3/examples/choropleth/choropleth.js | 38 + .../d3/examples/choropleth/unemployment.json | 1 + public/lib/d3/examples/clock/clock.css | 23 + public/lib/d3/examples/clock/clock.html | 17 + public/lib/d3/examples/clock/clock.js | 87 + .../d3/examples/cluster/cluster-radial.html | 14 + .../lib/d3/examples/cluster/cluster-radial.js | 39 + public/lib/d3/examples/cluster/cluster.css | 15 + public/lib/d3/examples/cluster/cluster.html | 14 + public/lib/d3/examples/cluster/cluster.js | 39 + public/lib/d3/examples/contour/contour.html | 108 + .../examples/crimea/crimea-stacked-area.html | 109 + .../examples/crimea/crimea-stacked-bar.html | 98 + public/lib/d3/examples/crimea/crimea.csv | 24 + public/lib/d3/examples/custom/custom.html | 83 + public/lib/d3/examples/data/README.md | 13 + public/lib/d3/examples/data/faithful.json | 8 + .../lib/d3/examples/data/flare-imports.json | 222 + public/lib/d3/examples/data/flare.json | 380 + public/lib/d3/examples/data/morley.csv | 101 + public/lib/d3/examples/data/sample.csv | 2 + public/lib/d3/examples/data/sample.html | 5 + public/lib/d3/examples/data/sample.json | 1 + public/lib/d3/examples/data/sample.txt | 1 + public/lib/d3/examples/data/sample.xml | 4 + public/lib/d3/examples/data/stocks.csv | 807 ++ public/lib/d3/examples/data/unemployment.csv | 1709 ++++ public/lib/d3/examples/data/us-borders.json | 1 + public/lib/d3/examples/data/us-counties.json | 3216 ++++++++ .../d3/examples/data/us-state-centroids.json | 54 + public/lib/d3/examples/data/us-states.json | 54 + .../lib/d3/examples/data/world-countries.json | 179 + public/lib/d3/examples/delaunay/delaunay.html | 44 + public/lib/d3/examples/donut/donut.html | 124 + public/lib/d3/examples/dot/dot.html | 103 + public/lib/d3/examples/drag/drag.html | 44 + public/lib/d3/examples/force/README | 10 + .../lib/d3/examples/force/force-bounds.html | 70 + .../lib/d3/examples/force/force-cluster.html | 249 + .../d3/examples/force/force-collapsible.html | 144 + .../lib/d3/examples/force/force-dynamic.html | 118 + public/lib/d3/examples/force/force-map.html | 104 + .../d3/examples/force/force-multi-foci.html | 68 + public/lib/d3/examples/force/force.css | 9 + public/lib/d3/examples/force/force.html | 14 + public/lib/d3/examples/force/force.js | 50 + public/lib/d3/examples/force/miserables.json | 18 + .../lib/d3/examples/great-arc/great-arc.html | 78 + .../examples/hello-world/hello-data-key.html | 60 + .../hello-world/hello-data-nested-key.html | 75 + .../hello-world/hello-data-nested.html | 77 + .../d3/examples/hello-world/hello-data.html | 46 + .../d3/examples/hello-world/hello-event.html | 53 + .../examples/hello-world/hello-node-key.html | 25 + .../d3/examples/hello-world/hello-order.html | 25 + .../d3/examples/hello-world/hello-sort.html | 75 + .../examples/hello-world/hello-transform.html | 41 + .../hello-transition-undefined.html | 43 + .../hello-world/hello-transition.html | 47 + .../hello-world/hello-webkit-transition.html | 64 + .../hello-world/select-enter-add.html | 29 + .../hello-world/selectAll-enter-add.html | 20 + .../lib/d3/examples/histogram/histogram.html | 80 + public/lib/d3/examples/horizon/horizon.css | 9 + public/lib/d3/examples/horizon/horizon.html | 25 + public/lib/d3/examples/horizon/horizon.js | 43 + .../lib/d3/examples/horizon/unemployment.json | 1 + public/lib/d3/examples/hull/hull.html | 75 + public/lib/d3/examples/kde/kde.css | 9 + public/lib/d3/examples/kde/kde.html | 14 + public/lib/d3/examples/kde/kde.js | 40 + public/lib/d3/examples/line/line.css | 22 + public/lib/d3/examples/line/line.html | 11 + public/lib/d3/examples/line/line.js | 63 + .../lib/d3/examples/marimekko/marimekko.html | 116 + .../lib/d3/examples/marimekko/marimekko.json | 18 + public/lib/d3/examples/marker/marker.html | 169 + public/lib/d3/examples/mercator/mercator.html | 133 + public/lib/d3/examples/moire/moire.html | 53 + .../d3/examples/node-canvas/us-counties.js | 70 + public/lib/d3/examples/pack/pack.css | 15 + public/lib/d3/examples/pack/pack.html | 14 + public/lib/d3/examples/pack/pack.js | 33 + public/lib/d3/examples/parallel/cars.csv | 407 + public/lib/d3/examples/parallel/parallel.html | 134 + .../partition/partition-icicle-zoom.html | 59 + .../examples/partition/partition-icicle.html | 45 + .../partition/partition-sunburst-zoom.html | 72 + .../partition/partition-sunburst.html | 21 + .../examples/partition/partition-sunburst.js | 72 + .../lib/d3/examples/pie/pie-transition.html | 69 + public/lib/d3/examples/pie/pie.html | 51 + .../lib/d3/examples/population/population.css | 28 + .../lib/d3/examples/population/population.csv | 571 ++ .../d3/examples/population/population.html | 13 + .../lib/d3/examples/population/population.js | 126 + public/lib/d3/examples/qq/qq.css | 18 + public/lib/d3/examples/qq/qq.html | 21 + public/lib/d3/examples/qq/qq.js | 66 + public/lib/d3/examples/qq/stats.js | 28 + public/lib/d3/examples/qq/turkers.json | 1 + public/lib/d3/examples/quadtree/quadtree.html | 114 + public/lib/d3/examples/showreel/showreel.html | 661 ++ public/lib/d3/examples/sizzle/sizzle.html | 27 + public/lib/d3/examples/sort/sort.css | 4 + public/lib/d3/examples/sort/sort.html | 12 + public/lib/d3/examples/sort/sort.js | 112 + public/lib/d3/examples/spline/spline.css | 30 + public/lib/d3/examples/spline/spline.html | 14 + public/lib/d3/examples/spline/spline.js | 110 + public/lib/d3/examples/splom/flowers.json | 1 + public/lib/d3/examples/splom/splom.css | 49 + public/lib/d3/examples/splom/splom.html | 13 + public/lib/d3/examples/splom/splom.js | 119 + public/lib/d3/examples/stream/stack.css | 7 + public/lib/d3/examples/stream/stack.html | 22 + public/lib/d3/examples/stream/stack.js | 119 + public/lib/d3/examples/stream/stream.css | 3 + public/lib/d3/examples/stream/stream.html | 19 + public/lib/d3/examples/stream/stream.js | 42 + .../lib/d3/examples/stream/stream_layers.js | 33 + public/lib/d3/examples/superformula/dot.html | 104 + .../d3/examples/superformula/explorer.html | 120 + .../examples/superformula/superformula.html | 70 + .../d3/examples/superformula/superformula.js | 98 + .../d3/examples/symbol-map/symbol-map.html | 67 + public/lib/d3/examples/touch/touch.html | 65 + public/lib/d3/examples/transform/test.html | 85 + .../lib/d3/examples/transform/transform.html | 60 + public/lib/d3/examples/tree/tree-dynamic.html | 111 + .../d3/examples/tree/tree-interactive.html | 172 + public/lib/d3/examples/tree/tree-radial.html | 14 + public/lib/d3/examples/tree/tree-radial.js | 40 + public/lib/d3/examples/tree/tree.css | 15 + public/lib/d3/examples/tree/tree.html | 14 + public/lib/d3/examples/tree/tree.js | 39 + .../lib/d3/examples/treemap/treemap-svg.html | 22 + public/lib/d3/examples/treemap/treemap-svg.js | 34 + public/lib/d3/examples/treemap/treemap.css | 8 + public/lib/d3/examples/treemap/treemap.html | 22 + public/lib/d3/examples/treemap/treemap.js | 53 + public/lib/d3/examples/voroboids/boid.js | 235 + .../lib/d3/examples/voroboids/voroboids.css | 15 + .../lib/d3/examples/voroboids/voroboids.html | 14 + public/lib/d3/examples/voroboids/voroboids.js | 65 + public/lib/d3/examples/voronoi/voronoi.css | 16 + public/lib/d3/examples/voronoi/voronoi.html | 15 + public/lib/d3/examples/voronoi/voronoi.js | 34 + .../examples/zoom-pan/zoom-pan-transform.html | 96 + public/lib/d3/examples/zoom-pan/zoom-pan.html | 120 + public/lib/d3/examples/zoom/dji.csv | 5233 +++++++++++++ public/lib/d3/examples/zoom/zoom.html | 162 + public/lib/d3/lib/colorbrewer/LICENSE | 38 + public/lib/d3/lib/colorbrewer/colorbrewer.css | 1327 ++++ public/lib/d3/lib/colorbrewer/colorbrewer.js | 32 + public/lib/d3/lib/jit/LICENSE | 27 + public/lib/d3/lib/jquery-ui/LICENSE | 25 + .../ui-bg_diagonals-thick_18_b81900_40x40.png | Bin .../ui-bg_diagonals-thick_20_666666_40x40.png | Bin .../images/ui-bg_flat_10_000000_40x100.png | Bin .../images/ui-bg_glass_100_f6f6f6_1x400.png | Bin .../images/ui-bg_glass_100_fdf5ce_1x400.png | Bin .../images/ui-bg_glass_65_ffffff_1x400.png | Bin .../ui-bg_gloss-wave_35_f6a828_500x100.png | Bin .../ui-bg_highlight-soft_100_eeeeee_1x100.png | Bin .../ui-bg_highlight-soft_75_ffe45c_1x100.png | Bin .../images/ui-icons_222222_256x240.png | Bin .../images/ui-icons_228ef1_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ef8c08_256x240.png | Bin .../images/ui-icons_ffd27a_256x240.png | Bin .../images/ui-icons_ffffff_256x240.png | Bin public/lib/d3/lib/jquery-ui/jquery-ui.css | 318 + public/lib/d3/lib/jquery-ui/jquery-ui.min.js | 83 + public/lib/d3/lib/jquery/LICENSE | 20 + public/lib/d3/lib/jquery/jquery.js | 6883 +++++++++++++++++ public/lib/d3/lib/jquery/jquery.min.js | 166 + public/lib/d3/lib/polymaps/LICENSE | 28 + public/lib/d3/lib/protovis/LICENSE | 27 + public/lib/d3/lib/science/LICENSE | 26 + public/lib/d3/lib/science/science.js | 225 + public/lib/d3/lib/science/science.lin.js | 27 + public/lib/d3/lib/science/science.lin.min.js | 1 + public/lib/d3/lib/science/science.min.js | 1 + public/lib/d3/lib/science/science.stats.js | 720 ++ .../lib/d3/lib/science/science.stats.min.js | 1 + public/lib/d3/lib/sizzle/LICENSE | 24 + public/lib/d3/lib/sizzle/sizzle.js | 1376 ++++ public/lib/d3/lib/sizzle/sizzle.min.js | 28 + public/lib/d3/package.json | 33 + public/lib/d3/src/behavior/behavior.js | 1 + public/lib/d3/src/behavior/drag.js | 125 + public/lib/d3/src/behavior/zoom.js | 242 + public/lib/d3/src/chart/box.js | 297 + public/lib/d3/src/chart/bullet.js | 237 + public/lib/d3/src/chart/chart.js | 1 + public/lib/d3/src/chart/horizon.js | 203 + public/lib/d3/src/chart/qq.js | 245 + public/lib/d3/src/compat/date.js | 3 + public/lib/d3/src/compat/style.js | 9 + public/lib/d3/src/core/array.js | 29 + public/lib/d3/src/core/ascending.js | 3 + public/lib/d3/src/core/bisect.js | 38 + public/lib/d3/src/core/collapse.js | 3 + public/lib/d3/src/core/core.js | 1 + public/lib/d3/src/core/descending.js | 3 + public/lib/d3/src/core/dispatch.js | 60 + public/lib/d3/src/core/ease.js | 128 + public/lib/d3/src/core/entries.js | 5 + public/lib/d3/src/core/event.js | 6 + public/lib/d3/src/core/extent.js | 21 + public/lib/d3/src/core/first.js | 13 + public/lib/d3/src/core/format.js | 100 + public/lib/d3/src/core/formatPrefix.js | 20 + public/lib/d3/src/core/functor.js | 3 + public/lib/d3/src/core/hsl.js | 63 + public/lib/d3/src/core/html.js | 10 + public/lib/d3/src/core/interpolate.js | 183 + public/lib/d3/src/core/json.js | 5 + public/lib/d3/src/core/keys.js | 5 + public/lib/d3/src/core/last.js | 13 + public/lib/d3/src/core/max.js | 14 + public/lib/d3/src/core/mean.js | 13 + public/lib/d3/src/core/median.js | 5 + public/lib/d3/src/core/merge.js | 3 + public/lib/d3/src/core/min.js | 14 + public/lib/d3/src/core/nest.js | 87 + public/lib/d3/src/core/noop.js | 1 + public/lib/d3/src/core/ns.js | 17 + public/lib/d3/src/core/number.js | 3 + public/lib/d3/src/core/permute.js | 7 + public/lib/d3/src/core/quantile.js | 8 + public/lib/d3/src/core/random.js | 15 + public/lib/d3/src/core/range.js | 21 + public/lib/d3/src/core/rebind.js | 16 + public/lib/d3/src/core/requote.js | 5 + public/lib/d3/src/core/rgb.js | 287 + public/lib/d3/src/core/round.js | 5 + public/lib/d3/src/core/selection-append.js | 15 + public/lib/d3/src/core/selection-attr.js | 44 + public/lib/d3/src/core/selection-call.js | 13 + public/lib/d3/src/core/selection-classed.js | 61 + public/lib/d3/src/core/selection-data.js | 110 + public/lib/d3/src/core/selection-each.js | 9 + public/lib/d3/src/core/selection-empty.js | 3 + .../lib/d3/src/core/selection-enter-select.js | 24 + public/lib/d3/src/core/selection-enter.js | 11 + public/lib/d3/src/core/selection-filter.js | 26 + public/lib/d3/src/core/selection-html.js | 7 + public/lib/d3/src/core/selection-insert.js | 20 + public/lib/d3/src/core/selection-map.js | 5 + public/lib/d3/src/core/selection-node.js | 9 + public/lib/d3/src/core/selection-on.js | 34 + public/lib/d3/src/core/selection-order.js | 11 + public/lib/d3/src/core/selection-property.js | 23 + public/lib/d3/src/core/selection-remove.js | 9 + public/lib/d3/src/core/selection-root.js | 18 + public/lib/d3/src/core/selection-select.js | 30 + public/lib/d3/src/core/selection-selectAll.js | 24 + public/lib/d3/src/core/selection-sort.js | 12 + public/lib/d3/src/core/selection-style.js | 26 + public/lib/d3/src/core/selection-text.js | 7 + .../lib/d3/src/core/selection-transition.js | 14 + public/lib/d3/src/core/selection.js | 25 + public/lib/d3/src/core/split.js | 21 + public/lib/d3/src/core/sum.js | 14 + public/lib/d3/src/core/text.js | 10 + public/lib/d3/src/core/this.js | 3 + public/lib/d3/src/core/timer.js | 104 + public/lib/d3/src/core/transform.js | 60 + public/lib/d3/src/core/transition-attr.js | 23 + public/lib/d3/src/core/transition-delay.js | 6 + public/lib/d3/src/core/transition-duration.js | 6 + public/lib/d3/src/core/transition-each.js | 9 + public/lib/d3/src/core/transition-remove.js | 6 + public/lib/d3/src/core/transition-select.js | 22 + .../lib/d3/src/core/transition-selectAll.js | 22 + public/lib/d3/src/core/transition-style.js | 14 + public/lib/d3/src/core/transition-text.js | 7 + .../lib/d3/src/core/transition-transition.js | 3 + public/lib/d3/src/core/transition.js | 125 + public/lib/d3/src/core/transpose.js | 3 + public/lib/d3/src/core/uninterpolate.js | 9 + public/lib/d3/src/core/values.js | 5 + public/lib/d3/src/core/xhr.js | 11 + public/lib/d3/src/core/xml.js | 10 + public/lib/d3/src/core/zip.js | 13 + public/lib/d3/src/csv/csv.js | 5 + public/lib/d3/src/csv/format.js | 13 + public/lib/d3/src/csv/parse.js | 73 + public/lib/d3/src/end.js | 1 + public/lib/d3/src/externs.js | 6 + public/lib/d3/src/geo/albers.js | 126 + public/lib/d3/src/geo/azimuthal.js | 80 + public/lib/d3/src/geo/bonne.js | 70 + public/lib/d3/src/geo/bounds.js | 83 + public/lib/d3/src/geo/circle.js | 146 + public/lib/d3/src/geo/equirectangular.js | 36 + public/lib/d3/src/geo/geo.js | 3 + public/lib/d3/src/geo/greatArc.js | 80 + public/lib/d3/src/geo/greatCircle.js | 1 + public/lib/d3/src/geo/mercator.js | 36 + public/lib/d3/src/geo/path.js | 271 + public/lib/d3/src/geo/type.js | 5 + public/lib/d3/src/geom/contour.js | 78 + public/lib/d3/src/geom/delaunay.js | 31 + public/lib/d3/src/geom/geom.js | 1 + public/lib/d3/src/geom/hull.js | 98 + public/lib/d3/src/geom/polygon.js | 88 + public/lib/d3/src/geom/quadtree.js | 129 + public/lib/d3/src/geom/voronoi.js | 409 + public/lib/d3/src/layout/bundle.js | 57 + public/lib/d3/src/layout/chord.js | 153 + public/lib/d3/src/layout/cluster.js | 78 + public/lib/d3/src/layout/force.js | 342 + public/lib/d3/src/layout/hierarchy.js | 120 + public/lib/d3/src/layout/histogram.js | 102 + public/lib/d3/src/layout/layout.js | 1 + public/lib/d3/src/layout/pack.js | 203 + public/lib/d3/src/layout/partition.js | 48 + public/lib/d3/src/layout/pie.js | 93 + public/lib/d3/src/layout/stack.js | 237 + public/lib/d3/src/layout/tree.js | 237 + public/lib/d3/src/layout/treemap.js | 217 + public/lib/d3/src/package.js | 21 + public/lib/d3/src/scale/bilinear.js | 7 + public/lib/d3/src/scale/category.js | 54 + public/lib/d3/src/scale/linear.js | 111 + public/lib/d3/src/scale/log.js | 85 + public/lib/d3/src/scale/nice.js | 24 + public/lib/d3/src/scale/ordinal.js | 81 + public/lib/d3/src/scale/polylinear.js | 16 + public/lib/d3/src/scale/pow.js | 54 + public/lib/d3/src/scale/quantile.js | 43 + public/lib/d3/src/scale/quantize.js | 36 + public/lib/d3/src/scale/scale.js | 10 + public/lib/d3/src/scale/sqrt.js | 3 + public/lib/d3/src/start.js | 1 + public/lib/d3/src/svg/arc.js | 95 + public/lib/d3/src/svg/area-radial.js | 10 + public/lib/d3/src/svg/area.js | 89 + public/lib/d3/src/svg/axis.js | 200 + public/lib/d3/src/svg/brush.js | 334 + public/lib/d3/src/svg/chord.js | 99 + public/lib/d3/src/svg/diagonal-radial.js | 22 + public/lib/d3/src/svg/diagonal.js | 38 + public/lib/d3/src/svg/line-radial.js | 22 + public/lib/d3/src/svg/line.js | 415 + public/lib/d3/src/svg/mouse.js | 29 + public/lib/d3/src/svg/svg.js | 1 + public/lib/d3/src/svg/symbol.js | 98 + public/lib/d3/src/svg/touches.js | 9 + public/lib/d3/src/time/day.js | 7 + public/lib/d3/src/time/days.js | 11 + public/lib/d3/src/time/format-iso.js | 13 + public/lib/d3/src/time/format-utc.js | 53 + public/lib/d3/src/time/format.js | 327 + public/lib/d3/src/time/hour.js | 8 + public/lib/d3/src/time/hours.js | 11 + public/lib/d3/src/time/minute.js | 5 + public/lib/d3/src/time/minutes.js | 11 + public/lib/d3/src/time/month.js | 7 + public/lib/d3/src/time/months.js | 11 + public/lib/d3/src/time/range.js | 16 + public/lib/d3/src/time/scale-utc.js | 36 + public/lib/d3/src/time/scale.js | 118 + public/lib/d3/src/time/second.js | 5 + public/lib/d3/src/time/seconds.js | 7 + public/lib/d3/src/time/time.js | 3 + public/lib/d3/src/time/week.js | 9 + public/lib/d3/src/time/weeks.js | 11 + public/lib/d3/src/time/year.js | 7 + public/lib/d3/src/time/years.js | 11 + public/lib/d3/test/core/ascending-test.js | 47 + public/lib/d3/test/core/bisect-test.js | 103 + public/lib/d3/test/core/descending-test.js | 47 + public/lib/d3/test/core/dispatch-test.js | 129 + public/lib/d3/test/core/ease-test.js | 129 + public/lib/d3/test/core/entries-test.js | 43 + public/lib/d3/test/core/extent-test.js | 51 + public/lib/d3/test/core/first-test.js | 42 + public/lib/d3/test/core/format-test.js | 239 + public/lib/d3/test/core/formatPrefix-test.js | 108 + public/lib/d3/test/core/functor-test.js | 29 + public/lib/d3/test/core/hsl-test.js | 82 + public/lib/d3/test/core/html-test.js | 37 + public/lib/d3/test/core/interpolate-test.js | 209 + public/lib/d3/test/core/json-test.js | 37 + public/lib/d3/test/core/keys-test.js | 31 + public/lib/d3/test/core/last-test.js | 42 + public/lib/d3/test/core/max-test.js | 51 + public/lib/d3/test/core/mean-test.js | 43 + public/lib/d3/test/core/median-test.js | 43 + public/lib/d3/test/core/merge-test.js | 27 + public/lib/d3/test/core/min-test.js | 50 + public/lib/d3/test/core/nest-test.js | 236 + public/lib/d3/test/core/ns-test.js | 58 + public/lib/d3/test/core/permute-test.js | 53 + public/lib/d3/test/core/quantile-test.js | 50 + public/lib/d3/test/core/range-test.js | 93 + public/lib/d3/test/core/rebind-test.js | 52 + public/lib/d3/test/core/requote-test.js | 53 + public/lib/d3/test/core/rgb-test.js | 89 + public/lib/d3/test/core/round-test.js | 70 + public/lib/d3/test/core/select-test.js | 42 + public/lib/d3/test/core/selectAll-test.js | 46 + .../lib/d3/test/core/selection-append-test.js | 123 + .../lib/d3/test/core/selection-attr-test.js | 153 + .../lib/d3/test/core/selection-call-test.js | 71 + .../d3/test/core/selection-classed-test.js | 219 + .../lib/d3/test/core/selection-data-test.js | 168 + .../lib/d3/test/core/selection-each-test.js | 83 + .../lib/d3/test/core/selection-empty-test.js | 51 + .../lib/d3/test/core/selection-filter-test.js | 70 + .../lib/d3/test/core/selection-html-test.js | 133 + .../lib/d3/test/core/selection-insert-test.js | 136 + public/lib/d3/test/core/selection-map-test.js | 47 + .../lib/d3/test/core/selection-node-test.js | 50 + public/lib/d3/test/core/selection-on-test.js | 95 + .../lib/d3/test/core/selection-order-test.js | 32 + .../d3/test/core/selection-property-test.js | 91 + .../lib/d3/test/core/selection-remove-test.js | 39 + .../lib/d3/test/core/selection-select-test.js | 125 + .../d3/test/core/selection-selectAll-test.js | 128 + .../lib/d3/test/core/selection-sort-test.js | 59 + .../lib/d3/test/core/selection-style-test.js | 100 + public/lib/d3/test/core/selection-test.js | 35 + .../lib/d3/test/core/selection-text-test.js | 116 + public/lib/d3/test/core/split-test.js | 34 + public/lib/d3/test/core/sum-test.js | 47 + public/lib/d3/test/core/text-test.js | 48 + public/lib/d3/test/core/timer-test.js | 62 + .../lib/d3/test/core/transition-test-attr.js | 54 + .../d3/test/core/transition-test-attrTween.js | 67 + .../lib/d3/test/core/transition-test-call.js | 33 + .../lib/d3/test/core/transition-test-delay.js | 41 + .../d3/test/core/transition-test-duration.js | 41 + .../lib/d3/test/core/transition-test-each.js | 166 + public/lib/d3/test/core/transition-test-id.js | 20 + .../d3/test/core/transition-test-remove.js | 46 + .../d3/test/core/transition-test-select.js | 63 + .../d3/test/core/transition-test-selectAll.js | 59 + .../lib/d3/test/core/transition-test-style.js | 49 + .../test/core/transition-test-styleTween.js | 73 + .../lib/d3/test/core/transition-test-text.js | 30 + .../lib/d3/test/core/transition-test-time.js | 36 + .../test/core/transition-test-transition.js | 60 + .../lib/d3/test/core/transition-test-tween.js | 71 + public/lib/d3/test/core/transition-test.js | 66 + public/lib/d3/test/core/transpose-test.js | 32 + public/lib/d3/test/core/values-test.js | 35 + public/lib/d3/test/core/version-test.js | 18 + public/lib/d3/test/core/xhr-test.js | 56 + public/lib/d3/test/core/xml-test.js | 48 + public/lib/d3/test/core/zip-test.js | 32 + public/lib/d3/test/csv/csv-test.js | 38 + public/lib/d3/test/csv/format-test.js | 39 + public/lib/d3/test/csv/parse-test.js | 101 + public/lib/d3/test/env-assert.js | 96 + public/lib/d3/test/env-fragment.js | 8 + public/lib/d3/test/env-xhr.js | 55 + public/lib/d3/test/env.js | 13 + public/lib/d3/test/geo/albers-test.js | 57 + public/lib/d3/test/geo/azimuthal-test.js | 261 + public/lib/d3/test/geo/bonne-test.js | 116 + .../lib/d3/test/geo/equirectangular-test.js | 50 + public/lib/d3/test/geo/greatArc-test.js | 41 + public/lib/d3/test/geo/mercator-test.js | 57 + public/lib/d3/test/geo/path-test.js | 25 + public/lib/d3/test/geom/polygon-test.js | 57 + public/lib/d3/test/layout/cluster-test.js | 44 + public/lib/d3/test/layout/hierarchy-test.js | 30 + public/lib/d3/test/layout/histogram-test.js | 91 + public/lib/d3/test/layout/pack-test.js | 67 + public/lib/d3/test/layout/partition-test.js | 50 + public/lib/d3/test/layout/pie-test.js | 26 + public/lib/d3/test/layout/tree-test.js | 46 + public/lib/d3/test/layout/treemap-test.js | 190 + public/lib/d3/test/scale/category-test.js | 74 + public/lib/d3/test/scale/linear-test.js | 243 + public/lib/d3/test/scale/log-test.js | 266 + public/lib/d3/test/scale/ordinal-test.js | 209 + public/lib/d3/test/scale/pow-test.js | 263 + public/lib/d3/test/scale/quantile-test.js | 64 + public/lib/d3/test/scale/quantize-test.js | 69 + public/lib/d3/test/scale/sqrt-test.js | 256 + public/lib/d3/test/svg/arc-test.js | 147 + public/lib/d3/test/svg/area-radial-test.js | 200 + public/lib/d3/test/svg/area-test.js | 192 + public/lib/d3/test/svg/axis-test.js | 359 + public/lib/d3/test/svg/line-radial-test.js | 125 + public/lib/d3/test/svg/line-test.js | 189 + public/lib/d3/test/svg/symbol-test.js | 96 + public/lib/d3/test/time/day-test.js | 65 + public/lib/d3/test/time/days-test.js | 105 + public/lib/d3/test/time/format-test.js | 467 ++ public/lib/d3/test/time/hour-test.js | 103 + public/lib/d3/test/time/hours-test.js | 135 + public/lib/d3/test/time/minute-test.js | 43 + public/lib/d3/test/time/minutes-test.js | 101 + public/lib/d3/test/time/month-test.js | 53 + public/lib/d3/test/time/months-test.js | 105 + public/lib/d3/test/time/scale-test.js | 525 ++ public/lib/d3/test/time/second-test.js | 41 + public/lib/d3/test/time/seconds-test.js | 101 + public/lib/d3/test/time/week-test.js | 59 + public/lib/d3/test/time/weeks-test.js | 105 + public/lib/d3/test/time/year-test.js | 41 + public/lib/d3/test/time/years-test.js | 73 + .../lib}/jquery/jquery-svgpan.min.js | 0 {lib => public/lib}/jquery/jquery-ui.js | 0 .../lib}/jquery/jquery.asmselect.css | 0 .../lib}/jquery/jquery.asmselect.js | 0 {lib => public/lib}/jquery/jquery.js | 0 public/lib/jquery/jquery.js~ | 0 .../ui-bg_diagonals-thick_18_b81900_40x40.png | Bin .../ui-bg_diagonals-thick_20_666666_40x40.png | Bin .../images/ui-bg_flat_10_000000_40x100.png | Bin .../images/ui-bg_glass_100_f6f6f6_1x400.png | Bin .../images/ui-bg_glass_100_fdf5ce_1x400.png | Bin .../images/ui-bg_glass_65_ffffff_1x400.png | Bin .../ui-bg_gloss-wave_35_f6a828_500x100.png | Bin .../ui-bg_highlight-soft_100_eeeeee_1x100.png | Bin .../ui-bg_highlight-soft_75_ffe45c_1x100.png | Bin .../images/ui-icons_222222_256x240.png | Bin .../images/ui-icons_228ef1_256x240.png | Bin .../images/ui-icons_ef8c08_256x240.png | Bin .../images/ui-icons_ffd27a_256x240.png | Bin .../images/ui-icons_ffffff_256x240.png | Bin .../ui-lightness/jquery-ui-1.8.18.custom.css | 0 .../ui-bg_diagonals-thick_18_b81900_40x40.png | Bin 0 -> 260 bytes .../ui-bg_diagonals-thick_20_666666_40x40.png | Bin 0 -> 251 bytes .../images/ui-bg_flat_10_000000_40x100.png | Bin 0 -> 178 bytes .../images/ui-bg_glass_100_f6f6f6_1x400.png | Bin 0 -> 104 bytes .../images/ui-bg_glass_100_fdf5ce_1x400.png | Bin 0 -> 125 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../ui-bg_gloss-wave_35_f6a828_500x100.png | Bin 0 -> 3762 bytes .../ui-bg_highlight-soft_100_eeeeee_1x100.png | Bin 0 -> 90 bytes .../ui-bg_highlight-soft_75_ffe45c_1x100.png | Bin 0 -> 129 bytes .../images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_228ef1_256x240.png | Bin .../images/ui-icons_ef8c08_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ffd27a_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ffffff_256x240.png | Bin 0 -> 4369 bytes .../ui-lightness/jquery-ui-1.8.18.custom.css | 0 {lib => public/lib}/jquery/ui/index.html | 570 +- .../lib}/jquery/ui/js/jquery-1.7.1.min.js | 0 .../ui/js/jquery-ui-1.8.18.custom.min.js | 0 graph.css => public/stylesheets/graph.css | 24 +- reset.css => public/stylesheets/reset.css | 0 {tex => public/tex}/enumitem.sty | 0 {tex => public/tex}/footer.tex | 0 {tex => public/tex}/header.tex | 0 {tex => public/tex}/ieee.pdf | Bin {tex => public/tex}/isit-bw.pdf | Bin {tex => public/tex}/logo.png | Bin {tex => public/tex}/schedule.tex | 166 +- {tex => public/tex}/test.aux | 0 tools/windows/pdfTotxtConverter.exe | Bin 0 -> 860160 bytes tools/windows/pdfToxmlConverter.exe | Bin 0 -> 581632 bytes 903 files changed, 83202 insertions(+), 1054 deletions(-) create mode 100644 .gitignore create mode 100644 README create mode 100644 app/controllers/Application.scala rename lib/jquery/jquery.js~ => app/generators/LinkGenerator.scala (100%) mode change 100755 => 100644 create mode 100644 app/generators/SchedulePdfGenerator.scala create mode 100644 app/generators/TaskProcessGenerator.scala create mode 100644 app/paper/Analyze.scala create mode 100644 app/paper/ComparePaper.scala create mode 100644 app/paper/ExtendPaper.scala create mode 100644 app/paper/FileFormat.scala create mode 100644 app/paper/FileLoader.scala create mode 100644 app/paper/Graph.scala create mode 100644 app/paper/InformationExtractors.scala create mode 100644 app/paper/LoadPaper.scala create mode 100644 app/paper/ParsePaper.scala create mode 100644 app/paper/RecognitionClasses.scala create mode 100644 app/paper/Terms.scala create mode 100644 app/paper/XMLObjects.scala create mode 100644 app/paper/XMLObjectsManager.scala create mode 100644 app/paper/XMLParagraphsConstructor.scala create mode 100644 app/paper/XMLParser.scala create mode 100644 app/paper/XMLScheduleParser.scala rename ajax.php => app/views/ajax.php (95%) rename index.html => app/views/index.scala.html (65%) mode change 100755 => 100644 rename schedule.php => app/views/schedule.php (95%) mode change 100755 => 100644 create mode 100644 cache/1569557585.pdf.parsed create mode 100644 cache/1569558325.pdf.parsed create mode 100644 cache/1569566229.pdf.parsed create mode 100644 cache/1569566239.pdf.parsed create mode 100644 cache/1569567045.pdf.bad create mode 100644 conf/application.conf create mode 100644 conf/routes delete mode 160000 lib/d3 create mode 100644 pdf2xml.dtd create mode 100644 project/Build.scala create mode 100644 project/build.properties create mode 100644 project/plugins.sbt rename enumitem.sty => public/enumitem.sty (100%) rename {img => public/img}/ajax-loader.gif (100%) rename {img => public/img}/ajax-loader_dark.gif (100%) rename {img => public/img}/current.png (100%) rename {img => public/img}/iconic_icons/ampersand_9x16.png (100%) rename {img => public/img}/iconic_icons/aperture_16x16.png (100%) rename {img => public/img}/iconic_icons/aperture_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_down_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_down_alt1_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_down_alt2_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_left_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_left_alt1_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_left_alt2_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_right_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_right_alt1_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_right_alt2_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_up_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_up_alt1_16x16.png (100%) rename {img => public/img}/iconic_icons/arrow_up_alt2_16x16.png (100%) rename {img => public/img}/iconic_icons/article_16x16.png (100%) rename {img => public/img}/iconic_icons/at_16x16.png (100%) rename {img => public/img}/iconic_icons/award_fill_8x16.png (100%) rename {img => public/img}/iconic_icons/award_stroke_8x16.png (100%) rename {img => public/img}/iconic_icons/bars_16x16.png (100%) rename {img => public/img}/iconic_icons/bars_alt_14x16.png (100%) rename {img => public/img}/iconic_icons/battery_charging_16x8.png (100%) rename {img => public/img}/iconic_icons/battery_empty_16x8.png (100%) rename {img => public/img}/iconic_icons/battery_full_16x8.png (100%) rename {img => public/img}/iconic_icons/battery_half_16x8.png (100%) rename {img => public/img}/iconic_icons/beaker_8x16.png (100%) rename {img => public/img}/iconic_icons/beaker_alt_8x16.png (100%) rename {img => public/img}/iconic_icons/bolt_16x16.png (100%) rename {img => public/img}/iconic_icons/book_14x16.png (100%) rename {img => public/img}/iconic_icons/book_alt2_16x14.png (100%) rename {img => public/img}/iconic_icons/book_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/box_16x16.png (100%) rename {img => public/img}/iconic_icons/brush_16x16.png (100%) rename {img => public/img}/iconic_icons/brush_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/calendar_16x16.png (100%) rename {img => public/img}/iconic_icons/calendar_alt_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/calendar_alt_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/camera_16x16.png (100%) rename {img => public/img}/iconic_icons/cd_16x16.png (100%) rename {img => public/img}/iconic_icons/chart_16x16.png (100%) rename {img => public/img}/iconic_icons/chart_alt_15x16.png (100%) rename {img => public/img}/iconic_icons/chat_16x16.png (100%) rename {img => public/img}/iconic_icons/chat_alt_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/chat_alt_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/check_16x13.png (100%) rename {img => public/img}/iconic_icons/check_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/clock_16x16.png (100%) rename {img => public/img}/iconic_icons/cloud_16x10.png (100%) rename {img => public/img}/iconic_icons/cloud_download_16x16.png (100%) rename {img => public/img}/iconic_icons/cloud_upload_16x16.png (100%) rename {img => public/img}/iconic_icons/cog_16x16.png (100%) rename {img => public/img}/iconic_icons/comment_alt1_fill_16x12.png (100%) rename {img => public/img}/iconic_icons/comment_alt1_stroke_16x12.png (100%) rename {img => public/img}/iconic_icons/comment_alt2_fill_14x16.png (100%) rename {img => public/img}/iconic_icons/comment_alt2_stroke_14x16.png (100%) rename {img => public/img}/iconic_icons/comment_fill_16x14.png (100%) rename {img => public/img}/iconic_icons/comment_stroke_16x14.png (100%) rename {img => public/img}/iconic_icons/compass_16x16.png (100%) rename {img => public/img}/iconic_icons/cursor_16x16.png (100%) rename {img => public/img}/iconic_icons/curved_arrow_16x12.png (100%) rename {img => public/img}/iconic_icons/denied_16x16.png (100%) rename {img => public/img}/iconic_icons/dial_16x16.png (100%) rename {img => public/img}/iconic_icons/document_alt_fill_12x16.png (100%) rename {img => public/img}/iconic_icons/document_alt_stroke_12x16.png (100%) rename {img => public/img}/iconic_icons/document_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/document_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/download_12x16.png (100%) rename {img => public/img}/iconic_icons/eject_16x16.png (100%) rename {img => public/img}/iconic_icons/equalizer_16x16.png (100%) rename {img => public/img}/iconic_icons/eye_16x12.png (100%) rename {img => public/img}/iconic_icons/eyedropper_16x16.png (100%) rename {img => public/img}/iconic_icons/first_16x16.png (100%) rename {img => public/img}/iconic_icons/folder_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/folder_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/fork_14x16.png (100%) rename {img => public/img}/iconic_icons/fullscreen_16x16.png (100%) rename {img => public/img}/iconic_icons/fullscreen_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/fullscreen_exit_16x16.png (100%) rename {img => public/img}/iconic_icons/fullscreen_exit_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/hash_14x16.png (100%) rename {img => public/img}/iconic_icons/headphones_16x14.png (100%) rename {img => public/img}/iconic_icons/heart_fill_16x14.png (100%) rename {img => public/img}/iconic_icons/heart_stroke_16x14.png (100%) rename {img => public/img}/iconic_icons/home_16x16.png (100%) rename {img => public/img}/iconic_icons/image_16x16.png (100%) rename {img => public/img}/iconic_icons/info_8x16.png (100%) rename {img => public/img}/iconic_icons/iphone_12x16.png (100%) rename {img => public/img}/iconic_icons/key_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/key_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/last_16x16.png (100%) rename {img => public/img}/iconic_icons/layers_16x14.png (100%) rename {img => public/img}/iconic_icons/layers_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/left_quote_16x12.png (100%) rename {img => public/img}/iconic_icons/left_quote_alt_16x12.png (100%) rename {img => public/img}/iconic_icons/lightbulb_10x16.png (100%) rename {img => public/img}/iconic_icons/link_16x16.png (100%) rename {img => public/img}/iconic_icons/list_16x14.png (100%) rename {img => public/img}/iconic_icons/list_nested_16x14.png (100%) rename {img => public/img}/iconic_icons/lock_fill_12x16.png (100%) rename {img => public/img}/iconic_icons/lock_stroke_12x16.png (100%) rename {img => public/img}/iconic_icons/loop_16x16.png (100%) rename {img => public/img}/iconic_icons/loop_alt1_16x12.png (100%) rename {img => public/img}/iconic_icons/loop_alt2_16x14.png (100%) rename {img => public/img}/iconic_icons/loop_alt3_16x12.png (100%) rename {img => public/img}/iconic_icons/loop_alt4_16x12.png (100%) rename {img => public/img}/iconic_icons/magnifying_glass_16x16.png (100%) rename {img => public/img}/iconic_icons/mail_16x12.png (100%) rename {img => public/img}/iconic_icons/map_pin_alt_8x16.png (100%) rename {img => public/img}/iconic_icons/map_pin_fill_10x16.png (100%) rename {img => public/img}/iconic_icons/map_pin_stroke_10x16.png (100%) rename {img => public/img}/iconic_icons/mic_12x16.png (100%) rename {img => public/img}/iconic_icons/minus_16x4.png (100%) rename {img => public/img}/iconic_icons/minus_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/moon_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/moon_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/move_16x16.png (100%) rename {img => public/img}/iconic_icons/move_alt1_16x16.png (100%) rename {img => public/img}/iconic_icons/move_alt2_16x16.png (100%) rename {img => public/img}/iconic_icons/move_horizontal_16x6.png (100%) rename {img => public/img}/iconic_icons/move_horizontal_alt1_16x6.png (100%) rename {img => public/img}/iconic_icons/move_horizontal_alt2_16x16.png (100%) rename {img => public/img}/iconic_icons/move_vertical_6x16.png (100%) rename {img => public/img}/iconic_icons/move_vertical_alt1_6x16.png (100%) rename {img => public/img}/iconic_icons/move_vertical_alt2_16x16.png (100%) rename {img => public/img}/iconic_icons/movie_16x16.png (100%) rename {img => public/img}/iconic_icons/new_window_16x16.png (100%) rename {img => public/img}/iconic_icons/pause_12x16.png (100%) rename {img => public/img}/iconic_icons/pen_16x16.png (100%) rename {img => public/img}/iconic_icons/pen_alt2_16x16.png (100%) rename {img => public/img}/iconic_icons/pen_alt_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/pen_alt_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/pilcrow_12x16.png (100%) rename {img => public/img}/iconic_icons/pin_16x16.png (100%) rename {img => public/img}/iconic_icons/play_12x16.png (100%) rename {img => public/img}/iconic_icons/play_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/plus_16x16.png (100%) rename {img => public/img}/iconic_icons/plus_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/question_mark_8x16.png (100%) rename {img => public/img}/iconic_icons/rain_16x14.png (100%) rename {img => public/img}/iconic_icons/read_more_16x16.png (100%) rename {img => public/img}/iconic_icons/reload_12x14.png (100%) rename {img => public/img}/iconic_icons/reload_alt_12x14.png (100%) rename {img => public/img}/iconic_icons/right_quote_16x12.png (100%) rename {img => public/img}/iconic_icons/right_quote_alt_16x12.png (100%) rename {img => public/img}/iconic_icons/rss_16x16.png (100%) rename {img => public/img}/iconic_icons/rss_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/share_16x16.png (100%) rename {img => public/img}/iconic_icons/spin_14x16.png (100%) rename {img => public/img}/iconic_icons/spin_alt_16x16.png (100%) rename {img => public/img}/iconic_icons/star_16x16.png (100%) rename {img => public/img}/iconic_icons/steering_wheel_16x16.png (100%) rename {img => public/img}/iconic_icons/stop_16x16.png (100%) rename {img => public/img}/iconic_icons/sun_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/sun_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/tag_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/tag_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/target_16x16.png (100%) rename {img => public/img}/iconic_icons/transfer_16x12.png (100%) rename {img => public/img}/iconic_icons/trash_fill_16x16.png (100%) rename {img => public/img}/iconic_icons/trash_stroke_16x16.png (100%) rename {img => public/img}/iconic_icons/umbrella_16x16.png (100%) rename {img => public/img}/iconic_icons/undo_16x16.png (100%) rename {img => public/img}/iconic_icons/unlock_fill_12x16.png (100%) rename {img => public/img}/iconic_icons/unlock_stroke_12x16.png (100%) rename {img => public/img}/iconic_icons/upload_12x16.png (100%) rename {img => public/img}/iconic_icons/user_12x16.png (100%) rename {img => public/img}/iconic_icons/volume_16x12.png (100%) rename {img => public/img}/iconic_icons/volume_mute_16x12.png (100%) rename {img => public/img}/iconic_icons/wrench_16x16.png (100%) rename {img => public/img}/iconic_icons/x_14x14.png (100%) rename {img => public/img}/iconic_icons/x_alt_16x16.png (100%) rename {img => public/img}/icons/authors.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/calendar.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/calendar_light.png (100%) rename {img => public/img}/icons/contract.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/create.png (100%) rename {img => public/img}/icons/download.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/download_light.png (100%) rename {img => public/img}/icons/expand.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/info.png (100%) rename {img => public/img}/icons/info_light.png (100%) rename {img => public/img}/icons/move.png (100%) rename {img => public/img}/icons/paper.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/remove.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/schedule.png (100%) rename {img => public/img}/icons/search.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/talk.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/time.png (100%) rename {img => public/img}/icons/title.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/title2.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/title3.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons/zoom.png (100%) rename {img => public/img}/icons1/expand.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons1/paper.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons1/remove.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons1/search.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons2/expand.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons2/paper.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons2/remove.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons2/search.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons4/expand.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons4/paper.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons4/remove.png (100%) mode change 100755 => 100644 rename {img => public/img}/icons4/search.png (100%) mode change 100755 => 100644 rename {img => public/img}/logo/logo.png (100%) mode change 100755 => 100644 rename {img => public/img}/logo/logo.svg (100%) mode change 100755 => 100644 rename {img => public/img}/node.png (100%) rename {img => public/img}/pointer1.png (100%) rename {img => public/img}/pointer2.png (100%) rename {img => public/img}/pointer3.png (100%) rename {img => public/img}/pointer4.png (100%) rename {img => public/img}/pointer5.png (100%) rename {img => public/img}/pointer6.png (100%) rename {img => public/img}/searchresult.png (100%) rename {img => public/img}/selected.png (100%) rename {js => public/js}/cookie.js (100%) mode change 100755 => 100644 rename {js => public/js}/data.json (90%) rename {js => public/js}/data_test.json~ (100%) mode change 100755 => 100644 rename {js => public/js}/graph.js (100%) mode change 100755 => 100644 rename {js => public/js}/ui.js (99%) mode change 100755 => 100644 rename {js => public/js}/util.js (100%) mode change 100755 => 100644 create mode 100644 public/lib/d3/.gitignore create mode 100644 public/lib/d3/.gitmodules create mode 100644 public/lib/d3/.npmignore create mode 100644 public/lib/d3/LICENSE create mode 100644 public/lib/d3/Makefile create mode 100644 public/lib/d3/README.md create mode 100644 public/lib/d3/d3.chart.js create mode 100644 public/lib/d3/d3.chart.min.js create mode 100644 public/lib/d3/d3.csv.js create mode 100644 public/lib/d3/d3.csv.min.js create mode 100644 public/lib/d3/d3.geo.js create mode 100644 public/lib/d3/d3.geo.min.js create mode 100644 public/lib/d3/d3.geom.js create mode 100644 public/lib/d3/d3.geom.min.js create mode 100644 public/lib/d3/d3.js create mode 100644 public/lib/d3/d3.layout.js create mode 100644 public/lib/d3/d3.layout.min.js create mode 100644 public/lib/d3/d3.min.js create mode 100644 public/lib/d3/d3.time.js create mode 100644 public/lib/d3/d3.time.min.js create mode 100644 public/lib/d3/examples/albers/albers.html create mode 100644 public/lib/d3/examples/area/area-radial.html create mode 100644 public/lib/d3/examples/area/area.html create mode 100644 public/lib/d3/examples/axis/axis-alternating.html create mode 100644 public/lib/d3/examples/axis/axis-ggplot2.html create mode 100644 public/lib/d3/examples/axis/axis-multiples.html create mode 100644 public/lib/d3/examples/axis/axis-orientations.html create mode 100644 public/lib/d3/examples/axis/axis-transition.html create mode 100644 public/lib/d3/examples/azimuthal/azimuthal.css create mode 100644 public/lib/d3/examples/azimuthal/azimuthal.html create mode 100644 public/lib/d3/examples/azimuthal/azimuthal.js create mode 100644 public/lib/d3/examples/bar/bar-hierarchy.html create mode 100644 public/lib/d3/examples/bar/bar.html create mode 100644 public/lib/d3/examples/bar/sample-data.csv create mode 100644 public/lib/d3/examples/bonne/bonne.html create mode 100644 public/lib/d3/examples/box/box.css create mode 100644 public/lib/d3/examples/box/box.html create mode 100644 public/lib/d3/examples/box/box.js create mode 100644 public/lib/d3/examples/brush/brush-ordinal.html create mode 100644 public/lib/d3/examples/brush/brush-x.html create mode 100644 public/lib/d3/examples/brush/brush-y.html create mode 100644 public/lib/d3/examples/brush/brush.html create mode 100644 public/lib/d3/examples/bubble/bubble.css create mode 100644 public/lib/d3/examples/bubble/bubble.html create mode 100644 public/lib/d3/examples/bubble/bubble.js create mode 100644 public/lib/d3/examples/bullet/bullet.css create mode 100644 public/lib/d3/examples/bullet/bullet.html create mode 100644 public/lib/d3/examples/bullet/bullet.js create mode 100644 public/lib/d3/examples/bullet/bullets.json create mode 100644 public/lib/d3/examples/bundle/bundle-radial.css create mode 100644 public/lib/d3/examples/bundle/bundle-radial.html create mode 100644 public/lib/d3/examples/bundle/bundle-radial.js create mode 100644 public/lib/d3/examples/bundle/bundle-treemap.css create mode 100644 public/lib/d3/examples/bundle/bundle-treemap.html create mode 100644 public/lib/d3/examples/bundle/bundle-treemap.js create mode 100644 public/lib/d3/examples/bundle/packages.js create mode 100644 public/lib/d3/examples/button.css create mode 100644 public/lib/d3/examples/calendar/calendar.css create mode 100644 public/lib/d3/examples/calendar/dji-area.html create mode 100644 public/lib/d3/examples/calendar/dji.csv create mode 100644 public/lib/d3/examples/calendar/dji.html create mode 100644 public/lib/d3/examples/calendar/dji.js create mode 100644 public/lib/d3/examples/calendar/vix.csv create mode 100644 public/lib/d3/examples/calendar/vix.html create mode 100644 public/lib/d3/examples/calendar/vix.js create mode 100644 public/lib/d3/examples/cartogram/cartogram.css create mode 100644 public/lib/d3/examples/cartogram/cartogram.html create mode 100644 public/lib/d3/examples/cartogram/cartogram.js create mode 100644 public/lib/d3/examples/cartogram/demers.css create mode 100644 public/lib/d3/examples/cartogram/demers.html create mode 100644 public/lib/d3/examples/cartogram/demers.js create mode 100644 public/lib/d3/examples/cartogram/dorling.css create mode 100644 public/lib/d3/examples/cartogram/dorling.html create mode 100644 public/lib/d3/examples/cartogram/dorling.js create mode 100644 public/lib/d3/examples/chord/chord-flare.html create mode 100644 public/lib/d3/examples/chord/chord.css create mode 100644 public/lib/d3/examples/chord/chord.html create mode 100644 public/lib/d3/examples/chord/chord.js create mode 100644 public/lib/d3/examples/choropleth/choropleth-area.html create mode 100644 public/lib/d3/examples/choropleth/choropleth-bounds.html create mode 100644 public/lib/d3/examples/choropleth/choropleth.css create mode 100644 public/lib/d3/examples/choropleth/choropleth.html create mode 100644 public/lib/d3/examples/choropleth/choropleth.js create mode 100644 public/lib/d3/examples/choropleth/unemployment.json create mode 100644 public/lib/d3/examples/clock/clock.css create mode 100644 public/lib/d3/examples/clock/clock.html create mode 100644 public/lib/d3/examples/clock/clock.js create mode 100644 public/lib/d3/examples/cluster/cluster-radial.html create mode 100644 public/lib/d3/examples/cluster/cluster-radial.js create mode 100644 public/lib/d3/examples/cluster/cluster.css create mode 100644 public/lib/d3/examples/cluster/cluster.html create mode 100644 public/lib/d3/examples/cluster/cluster.js create mode 100644 public/lib/d3/examples/contour/contour.html create mode 100644 public/lib/d3/examples/crimea/crimea-stacked-area.html create mode 100644 public/lib/d3/examples/crimea/crimea-stacked-bar.html create mode 100644 public/lib/d3/examples/crimea/crimea.csv create mode 100644 public/lib/d3/examples/custom/custom.html create mode 100644 public/lib/d3/examples/data/README.md create mode 100644 public/lib/d3/examples/data/faithful.json create mode 100644 public/lib/d3/examples/data/flare-imports.json create mode 100644 public/lib/d3/examples/data/flare.json create mode 100644 public/lib/d3/examples/data/morley.csv create mode 100644 public/lib/d3/examples/data/sample.csv create mode 100644 public/lib/d3/examples/data/sample.html create mode 100644 public/lib/d3/examples/data/sample.json create mode 100644 public/lib/d3/examples/data/sample.txt create mode 100644 public/lib/d3/examples/data/sample.xml create mode 100644 public/lib/d3/examples/data/stocks.csv create mode 100644 public/lib/d3/examples/data/unemployment.csv create mode 100644 public/lib/d3/examples/data/us-borders.json create mode 100644 public/lib/d3/examples/data/us-counties.json create mode 100644 public/lib/d3/examples/data/us-state-centroids.json create mode 100644 public/lib/d3/examples/data/us-states.json create mode 100644 public/lib/d3/examples/data/world-countries.json create mode 100644 public/lib/d3/examples/delaunay/delaunay.html create mode 100644 public/lib/d3/examples/donut/donut.html create mode 100644 public/lib/d3/examples/dot/dot.html create mode 100644 public/lib/d3/examples/drag/drag.html create mode 100644 public/lib/d3/examples/force/README create mode 100644 public/lib/d3/examples/force/force-bounds.html create mode 100644 public/lib/d3/examples/force/force-cluster.html create mode 100644 public/lib/d3/examples/force/force-collapsible.html create mode 100644 public/lib/d3/examples/force/force-dynamic.html create mode 100644 public/lib/d3/examples/force/force-map.html create mode 100644 public/lib/d3/examples/force/force-multi-foci.html create mode 100644 public/lib/d3/examples/force/force.css create mode 100644 public/lib/d3/examples/force/force.html create mode 100644 public/lib/d3/examples/force/force.js create mode 100644 public/lib/d3/examples/force/miserables.json create mode 100644 public/lib/d3/examples/great-arc/great-arc.html create mode 100644 public/lib/d3/examples/hello-world/hello-data-key.html create mode 100644 public/lib/d3/examples/hello-world/hello-data-nested-key.html create mode 100644 public/lib/d3/examples/hello-world/hello-data-nested.html create mode 100644 public/lib/d3/examples/hello-world/hello-data.html create mode 100644 public/lib/d3/examples/hello-world/hello-event.html create mode 100644 public/lib/d3/examples/hello-world/hello-node-key.html create mode 100644 public/lib/d3/examples/hello-world/hello-order.html create mode 100644 public/lib/d3/examples/hello-world/hello-sort.html create mode 100644 public/lib/d3/examples/hello-world/hello-transform.html create mode 100644 public/lib/d3/examples/hello-world/hello-transition-undefined.html create mode 100644 public/lib/d3/examples/hello-world/hello-transition.html create mode 100644 public/lib/d3/examples/hello-world/hello-webkit-transition.html create mode 100644 public/lib/d3/examples/hello-world/select-enter-add.html create mode 100644 public/lib/d3/examples/hello-world/selectAll-enter-add.html create mode 100644 public/lib/d3/examples/histogram/histogram.html create mode 100644 public/lib/d3/examples/horizon/horizon.css create mode 100644 public/lib/d3/examples/horizon/horizon.html create mode 100644 public/lib/d3/examples/horizon/horizon.js create mode 100644 public/lib/d3/examples/horizon/unemployment.json create mode 100644 public/lib/d3/examples/hull/hull.html create mode 100644 public/lib/d3/examples/kde/kde.css create mode 100644 public/lib/d3/examples/kde/kde.html create mode 100644 public/lib/d3/examples/kde/kde.js create mode 100644 public/lib/d3/examples/line/line.css create mode 100644 public/lib/d3/examples/line/line.html create mode 100644 public/lib/d3/examples/line/line.js create mode 100644 public/lib/d3/examples/marimekko/marimekko.html create mode 100644 public/lib/d3/examples/marimekko/marimekko.json create mode 100644 public/lib/d3/examples/marker/marker.html create mode 100644 public/lib/d3/examples/mercator/mercator.html create mode 100644 public/lib/d3/examples/moire/moire.html create mode 100644 public/lib/d3/examples/node-canvas/us-counties.js create mode 100644 public/lib/d3/examples/pack/pack.css create mode 100644 public/lib/d3/examples/pack/pack.html create mode 100644 public/lib/d3/examples/pack/pack.js create mode 100644 public/lib/d3/examples/parallel/cars.csv create mode 100644 public/lib/d3/examples/parallel/parallel.html create mode 100644 public/lib/d3/examples/partition/partition-icicle-zoom.html create mode 100644 public/lib/d3/examples/partition/partition-icicle.html create mode 100644 public/lib/d3/examples/partition/partition-sunburst-zoom.html create mode 100644 public/lib/d3/examples/partition/partition-sunburst.html create mode 100644 public/lib/d3/examples/partition/partition-sunburst.js create mode 100644 public/lib/d3/examples/pie/pie-transition.html create mode 100644 public/lib/d3/examples/pie/pie.html create mode 100644 public/lib/d3/examples/population/population.css create mode 100644 public/lib/d3/examples/population/population.csv create mode 100644 public/lib/d3/examples/population/population.html create mode 100644 public/lib/d3/examples/population/population.js create mode 100644 public/lib/d3/examples/qq/qq.css create mode 100644 public/lib/d3/examples/qq/qq.html create mode 100644 public/lib/d3/examples/qq/qq.js create mode 100644 public/lib/d3/examples/qq/stats.js create mode 100644 public/lib/d3/examples/qq/turkers.json create mode 100644 public/lib/d3/examples/quadtree/quadtree.html create mode 100644 public/lib/d3/examples/showreel/showreel.html create mode 100644 public/lib/d3/examples/sizzle/sizzle.html create mode 100644 public/lib/d3/examples/sort/sort.css create mode 100644 public/lib/d3/examples/sort/sort.html create mode 100644 public/lib/d3/examples/sort/sort.js create mode 100644 public/lib/d3/examples/spline/spline.css create mode 100644 public/lib/d3/examples/spline/spline.html create mode 100644 public/lib/d3/examples/spline/spline.js create mode 100644 public/lib/d3/examples/splom/flowers.json create mode 100644 public/lib/d3/examples/splom/splom.css create mode 100644 public/lib/d3/examples/splom/splom.html create mode 100644 public/lib/d3/examples/splom/splom.js create mode 100644 public/lib/d3/examples/stream/stack.css create mode 100644 public/lib/d3/examples/stream/stack.html create mode 100644 public/lib/d3/examples/stream/stack.js create mode 100644 public/lib/d3/examples/stream/stream.css create mode 100644 public/lib/d3/examples/stream/stream.html create mode 100644 public/lib/d3/examples/stream/stream.js create mode 100644 public/lib/d3/examples/stream/stream_layers.js create mode 100644 public/lib/d3/examples/superformula/dot.html create mode 100644 public/lib/d3/examples/superformula/explorer.html create mode 100644 public/lib/d3/examples/superformula/superformula.html create mode 100644 public/lib/d3/examples/superformula/superformula.js create mode 100644 public/lib/d3/examples/symbol-map/symbol-map.html create mode 100644 public/lib/d3/examples/touch/touch.html create mode 100644 public/lib/d3/examples/transform/test.html create mode 100644 public/lib/d3/examples/transform/transform.html create mode 100644 public/lib/d3/examples/tree/tree-dynamic.html create mode 100644 public/lib/d3/examples/tree/tree-interactive.html create mode 100644 public/lib/d3/examples/tree/tree-radial.html create mode 100644 public/lib/d3/examples/tree/tree-radial.js create mode 100644 public/lib/d3/examples/tree/tree.css create mode 100644 public/lib/d3/examples/tree/tree.html create mode 100644 public/lib/d3/examples/tree/tree.js create mode 100644 public/lib/d3/examples/treemap/treemap-svg.html create mode 100644 public/lib/d3/examples/treemap/treemap-svg.js create mode 100644 public/lib/d3/examples/treemap/treemap.css create mode 100644 public/lib/d3/examples/treemap/treemap.html create mode 100644 public/lib/d3/examples/treemap/treemap.js create mode 100644 public/lib/d3/examples/voroboids/boid.js create mode 100644 public/lib/d3/examples/voroboids/voroboids.css create mode 100644 public/lib/d3/examples/voroboids/voroboids.html create mode 100644 public/lib/d3/examples/voroboids/voroboids.js create mode 100644 public/lib/d3/examples/voronoi/voronoi.css create mode 100644 public/lib/d3/examples/voronoi/voronoi.html create mode 100644 public/lib/d3/examples/voronoi/voronoi.js create mode 100644 public/lib/d3/examples/zoom-pan/zoom-pan-transform.html create mode 100644 public/lib/d3/examples/zoom-pan/zoom-pan.html create mode 100644 public/lib/d3/examples/zoom/dji.csv create mode 100644 public/lib/d3/examples/zoom/zoom.html create mode 100644 public/lib/d3/lib/colorbrewer/LICENSE create mode 100644 public/lib/d3/lib/colorbrewer/colorbrewer.css create mode 100644 public/lib/d3/lib/colorbrewer/colorbrewer.js create mode 100644 public/lib/d3/lib/jit/LICENSE create mode 100644 public/lib/d3/lib/jquery-ui/LICENSE rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_diagonals-thick_18_b81900_40x40.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_diagonals-thick_20_666666_40x40.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_flat_10_000000_40x100.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_glass_100_f6f6f6_1x400.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_glass_100_fdf5ce_1x400.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_glass_65_ffffff_1x400.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_gloss-wave_35_f6a828_500x100.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_highlight-soft_100_eeeeee_1x100.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-bg_highlight-soft_75_ffe45c_1x100.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-icons_222222_256x240.png (100%) mode change 100755 => 100644 create mode 100644 public/lib/d3/lib/jquery-ui/images/ui-icons_228ef1_256x240.png rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-icons_ef8c08_256x240.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-icons_ffd27a_256x240.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui-lightness => public/lib/d3/lib/jquery-ui}/images/ui-icons_ffffff_256x240.png (100%) mode change 100755 => 100644 create mode 100644 public/lib/d3/lib/jquery-ui/jquery-ui.css create mode 100644 public/lib/d3/lib/jquery-ui/jquery-ui.min.js create mode 100644 public/lib/d3/lib/jquery/LICENSE create mode 100644 public/lib/d3/lib/jquery/jquery.js create mode 100644 public/lib/d3/lib/jquery/jquery.min.js create mode 100644 public/lib/d3/lib/polymaps/LICENSE create mode 100644 public/lib/d3/lib/protovis/LICENSE create mode 100644 public/lib/d3/lib/science/LICENSE create mode 100644 public/lib/d3/lib/science/science.js create mode 100644 public/lib/d3/lib/science/science.lin.js create mode 100644 public/lib/d3/lib/science/science.lin.min.js create mode 100644 public/lib/d3/lib/science/science.min.js create mode 100644 public/lib/d3/lib/science/science.stats.js create mode 100644 public/lib/d3/lib/science/science.stats.min.js create mode 100644 public/lib/d3/lib/sizzle/LICENSE create mode 100644 public/lib/d3/lib/sizzle/sizzle.js create mode 100644 public/lib/d3/lib/sizzle/sizzle.min.js create mode 100644 public/lib/d3/package.json create mode 100644 public/lib/d3/src/behavior/behavior.js create mode 100644 public/lib/d3/src/behavior/drag.js create mode 100644 public/lib/d3/src/behavior/zoom.js create mode 100644 public/lib/d3/src/chart/box.js create mode 100644 public/lib/d3/src/chart/bullet.js create mode 100644 public/lib/d3/src/chart/chart.js create mode 100644 public/lib/d3/src/chart/horizon.js create mode 100644 public/lib/d3/src/chart/qq.js create mode 100644 public/lib/d3/src/compat/date.js create mode 100644 public/lib/d3/src/compat/style.js create mode 100644 public/lib/d3/src/core/array.js create mode 100644 public/lib/d3/src/core/ascending.js create mode 100644 public/lib/d3/src/core/bisect.js create mode 100644 public/lib/d3/src/core/collapse.js create mode 100644 public/lib/d3/src/core/core.js create mode 100644 public/lib/d3/src/core/descending.js create mode 100644 public/lib/d3/src/core/dispatch.js create mode 100644 public/lib/d3/src/core/ease.js create mode 100644 public/lib/d3/src/core/entries.js create mode 100644 public/lib/d3/src/core/event.js create mode 100644 public/lib/d3/src/core/extent.js create mode 100644 public/lib/d3/src/core/first.js create mode 100644 public/lib/d3/src/core/format.js create mode 100644 public/lib/d3/src/core/formatPrefix.js create mode 100644 public/lib/d3/src/core/functor.js create mode 100644 public/lib/d3/src/core/hsl.js create mode 100644 public/lib/d3/src/core/html.js create mode 100644 public/lib/d3/src/core/interpolate.js create mode 100644 public/lib/d3/src/core/json.js create mode 100644 public/lib/d3/src/core/keys.js create mode 100644 public/lib/d3/src/core/last.js create mode 100644 public/lib/d3/src/core/max.js create mode 100644 public/lib/d3/src/core/mean.js create mode 100644 public/lib/d3/src/core/median.js create mode 100644 public/lib/d3/src/core/merge.js create mode 100644 public/lib/d3/src/core/min.js create mode 100644 public/lib/d3/src/core/nest.js create mode 100644 public/lib/d3/src/core/noop.js create mode 100644 public/lib/d3/src/core/ns.js create mode 100644 public/lib/d3/src/core/number.js create mode 100644 public/lib/d3/src/core/permute.js create mode 100644 public/lib/d3/src/core/quantile.js create mode 100644 public/lib/d3/src/core/random.js create mode 100644 public/lib/d3/src/core/range.js create mode 100644 public/lib/d3/src/core/rebind.js create mode 100644 public/lib/d3/src/core/requote.js create mode 100644 public/lib/d3/src/core/rgb.js create mode 100644 public/lib/d3/src/core/round.js create mode 100644 public/lib/d3/src/core/selection-append.js create mode 100644 public/lib/d3/src/core/selection-attr.js create mode 100644 public/lib/d3/src/core/selection-call.js create mode 100644 public/lib/d3/src/core/selection-classed.js create mode 100644 public/lib/d3/src/core/selection-data.js create mode 100644 public/lib/d3/src/core/selection-each.js create mode 100644 public/lib/d3/src/core/selection-empty.js create mode 100644 public/lib/d3/src/core/selection-enter-select.js create mode 100644 public/lib/d3/src/core/selection-enter.js create mode 100644 public/lib/d3/src/core/selection-filter.js create mode 100644 public/lib/d3/src/core/selection-html.js create mode 100644 public/lib/d3/src/core/selection-insert.js create mode 100644 public/lib/d3/src/core/selection-map.js create mode 100644 public/lib/d3/src/core/selection-node.js create mode 100644 public/lib/d3/src/core/selection-on.js create mode 100644 public/lib/d3/src/core/selection-order.js create mode 100644 public/lib/d3/src/core/selection-property.js create mode 100644 public/lib/d3/src/core/selection-remove.js create mode 100644 public/lib/d3/src/core/selection-root.js create mode 100644 public/lib/d3/src/core/selection-select.js create mode 100644 public/lib/d3/src/core/selection-selectAll.js create mode 100644 public/lib/d3/src/core/selection-sort.js create mode 100644 public/lib/d3/src/core/selection-style.js create mode 100644 public/lib/d3/src/core/selection-text.js create mode 100644 public/lib/d3/src/core/selection-transition.js create mode 100644 public/lib/d3/src/core/selection.js create mode 100644 public/lib/d3/src/core/split.js create mode 100644 public/lib/d3/src/core/sum.js create mode 100644 public/lib/d3/src/core/text.js create mode 100644 public/lib/d3/src/core/this.js create mode 100644 public/lib/d3/src/core/timer.js create mode 100644 public/lib/d3/src/core/transform.js create mode 100644 public/lib/d3/src/core/transition-attr.js create mode 100644 public/lib/d3/src/core/transition-delay.js create mode 100644 public/lib/d3/src/core/transition-duration.js create mode 100644 public/lib/d3/src/core/transition-each.js create mode 100644 public/lib/d3/src/core/transition-remove.js create mode 100644 public/lib/d3/src/core/transition-select.js create mode 100644 public/lib/d3/src/core/transition-selectAll.js create mode 100644 public/lib/d3/src/core/transition-style.js create mode 100644 public/lib/d3/src/core/transition-text.js create mode 100644 public/lib/d3/src/core/transition-transition.js create mode 100644 public/lib/d3/src/core/transition.js create mode 100644 public/lib/d3/src/core/transpose.js create mode 100644 public/lib/d3/src/core/uninterpolate.js create mode 100644 public/lib/d3/src/core/values.js create mode 100644 public/lib/d3/src/core/xhr.js create mode 100644 public/lib/d3/src/core/xml.js create mode 100644 public/lib/d3/src/core/zip.js create mode 100644 public/lib/d3/src/csv/csv.js create mode 100644 public/lib/d3/src/csv/format.js create mode 100644 public/lib/d3/src/csv/parse.js create mode 100644 public/lib/d3/src/end.js create mode 100644 public/lib/d3/src/externs.js create mode 100644 public/lib/d3/src/geo/albers.js create mode 100644 public/lib/d3/src/geo/azimuthal.js create mode 100644 public/lib/d3/src/geo/bonne.js create mode 100644 public/lib/d3/src/geo/bounds.js create mode 100644 public/lib/d3/src/geo/circle.js create mode 100644 public/lib/d3/src/geo/equirectangular.js create mode 100644 public/lib/d3/src/geo/geo.js create mode 100644 public/lib/d3/src/geo/greatArc.js create mode 100644 public/lib/d3/src/geo/greatCircle.js create mode 100644 public/lib/d3/src/geo/mercator.js create mode 100644 public/lib/d3/src/geo/path.js create mode 100644 public/lib/d3/src/geo/type.js create mode 100644 public/lib/d3/src/geom/contour.js create mode 100644 public/lib/d3/src/geom/delaunay.js create mode 100644 public/lib/d3/src/geom/geom.js create mode 100644 public/lib/d3/src/geom/hull.js create mode 100644 public/lib/d3/src/geom/polygon.js create mode 100644 public/lib/d3/src/geom/quadtree.js create mode 100644 public/lib/d3/src/geom/voronoi.js create mode 100644 public/lib/d3/src/layout/bundle.js create mode 100644 public/lib/d3/src/layout/chord.js create mode 100644 public/lib/d3/src/layout/cluster.js create mode 100644 public/lib/d3/src/layout/force.js create mode 100644 public/lib/d3/src/layout/hierarchy.js create mode 100644 public/lib/d3/src/layout/histogram.js create mode 100644 public/lib/d3/src/layout/layout.js create mode 100644 public/lib/d3/src/layout/pack.js create mode 100644 public/lib/d3/src/layout/partition.js create mode 100644 public/lib/d3/src/layout/pie.js create mode 100644 public/lib/d3/src/layout/stack.js create mode 100644 public/lib/d3/src/layout/tree.js create mode 100644 public/lib/d3/src/layout/treemap.js create mode 100644 public/lib/d3/src/package.js create mode 100644 public/lib/d3/src/scale/bilinear.js create mode 100644 public/lib/d3/src/scale/category.js create mode 100644 public/lib/d3/src/scale/linear.js create mode 100644 public/lib/d3/src/scale/log.js create mode 100644 public/lib/d3/src/scale/nice.js create mode 100644 public/lib/d3/src/scale/ordinal.js create mode 100644 public/lib/d3/src/scale/polylinear.js create mode 100644 public/lib/d3/src/scale/pow.js create mode 100644 public/lib/d3/src/scale/quantile.js create mode 100644 public/lib/d3/src/scale/quantize.js create mode 100644 public/lib/d3/src/scale/scale.js create mode 100644 public/lib/d3/src/scale/sqrt.js create mode 100644 public/lib/d3/src/start.js create mode 100644 public/lib/d3/src/svg/arc.js create mode 100644 public/lib/d3/src/svg/area-radial.js create mode 100644 public/lib/d3/src/svg/area.js create mode 100644 public/lib/d3/src/svg/axis.js create mode 100644 public/lib/d3/src/svg/brush.js create mode 100644 public/lib/d3/src/svg/chord.js create mode 100644 public/lib/d3/src/svg/diagonal-radial.js create mode 100644 public/lib/d3/src/svg/diagonal.js create mode 100644 public/lib/d3/src/svg/line-radial.js create mode 100644 public/lib/d3/src/svg/line.js create mode 100644 public/lib/d3/src/svg/mouse.js create mode 100644 public/lib/d3/src/svg/svg.js create mode 100644 public/lib/d3/src/svg/symbol.js create mode 100644 public/lib/d3/src/svg/touches.js create mode 100644 public/lib/d3/src/time/day.js create mode 100644 public/lib/d3/src/time/days.js create mode 100644 public/lib/d3/src/time/format-iso.js create mode 100644 public/lib/d3/src/time/format-utc.js create mode 100644 public/lib/d3/src/time/format.js create mode 100644 public/lib/d3/src/time/hour.js create mode 100644 public/lib/d3/src/time/hours.js create mode 100644 public/lib/d3/src/time/minute.js create mode 100644 public/lib/d3/src/time/minutes.js create mode 100644 public/lib/d3/src/time/month.js create mode 100644 public/lib/d3/src/time/months.js create mode 100644 public/lib/d3/src/time/range.js create mode 100644 public/lib/d3/src/time/scale-utc.js create mode 100644 public/lib/d3/src/time/scale.js create mode 100644 public/lib/d3/src/time/second.js create mode 100644 public/lib/d3/src/time/seconds.js create mode 100644 public/lib/d3/src/time/time.js create mode 100644 public/lib/d3/src/time/week.js create mode 100644 public/lib/d3/src/time/weeks.js create mode 100644 public/lib/d3/src/time/year.js create mode 100644 public/lib/d3/src/time/years.js create mode 100644 public/lib/d3/test/core/ascending-test.js create mode 100644 public/lib/d3/test/core/bisect-test.js create mode 100644 public/lib/d3/test/core/descending-test.js create mode 100644 public/lib/d3/test/core/dispatch-test.js create mode 100644 public/lib/d3/test/core/ease-test.js create mode 100644 public/lib/d3/test/core/entries-test.js create mode 100644 public/lib/d3/test/core/extent-test.js create mode 100644 public/lib/d3/test/core/first-test.js create mode 100644 public/lib/d3/test/core/format-test.js create mode 100644 public/lib/d3/test/core/formatPrefix-test.js create mode 100644 public/lib/d3/test/core/functor-test.js create mode 100644 public/lib/d3/test/core/hsl-test.js create mode 100644 public/lib/d3/test/core/html-test.js create mode 100644 public/lib/d3/test/core/interpolate-test.js create mode 100644 public/lib/d3/test/core/json-test.js create mode 100644 public/lib/d3/test/core/keys-test.js create mode 100644 public/lib/d3/test/core/last-test.js create mode 100644 public/lib/d3/test/core/max-test.js create mode 100644 public/lib/d3/test/core/mean-test.js create mode 100644 public/lib/d3/test/core/median-test.js create mode 100644 public/lib/d3/test/core/merge-test.js create mode 100644 public/lib/d3/test/core/min-test.js create mode 100644 public/lib/d3/test/core/nest-test.js create mode 100644 public/lib/d3/test/core/ns-test.js create mode 100644 public/lib/d3/test/core/permute-test.js create mode 100644 public/lib/d3/test/core/quantile-test.js create mode 100644 public/lib/d3/test/core/range-test.js create mode 100644 public/lib/d3/test/core/rebind-test.js create mode 100644 public/lib/d3/test/core/requote-test.js create mode 100644 public/lib/d3/test/core/rgb-test.js create mode 100644 public/lib/d3/test/core/round-test.js create mode 100644 public/lib/d3/test/core/select-test.js create mode 100644 public/lib/d3/test/core/selectAll-test.js create mode 100644 public/lib/d3/test/core/selection-append-test.js create mode 100644 public/lib/d3/test/core/selection-attr-test.js create mode 100644 public/lib/d3/test/core/selection-call-test.js create mode 100644 public/lib/d3/test/core/selection-classed-test.js create mode 100644 public/lib/d3/test/core/selection-data-test.js create mode 100644 public/lib/d3/test/core/selection-each-test.js create mode 100644 public/lib/d3/test/core/selection-empty-test.js create mode 100644 public/lib/d3/test/core/selection-filter-test.js create mode 100644 public/lib/d3/test/core/selection-html-test.js create mode 100644 public/lib/d3/test/core/selection-insert-test.js create mode 100644 public/lib/d3/test/core/selection-map-test.js create mode 100644 public/lib/d3/test/core/selection-node-test.js create mode 100644 public/lib/d3/test/core/selection-on-test.js create mode 100644 public/lib/d3/test/core/selection-order-test.js create mode 100644 public/lib/d3/test/core/selection-property-test.js create mode 100644 public/lib/d3/test/core/selection-remove-test.js create mode 100644 public/lib/d3/test/core/selection-select-test.js create mode 100644 public/lib/d3/test/core/selection-selectAll-test.js create mode 100644 public/lib/d3/test/core/selection-sort-test.js create mode 100644 public/lib/d3/test/core/selection-style-test.js create mode 100644 public/lib/d3/test/core/selection-test.js create mode 100644 public/lib/d3/test/core/selection-text-test.js create mode 100644 public/lib/d3/test/core/split-test.js create mode 100644 public/lib/d3/test/core/sum-test.js create mode 100644 public/lib/d3/test/core/text-test.js create mode 100644 public/lib/d3/test/core/timer-test.js create mode 100644 public/lib/d3/test/core/transition-test-attr.js create mode 100644 public/lib/d3/test/core/transition-test-attrTween.js create mode 100644 public/lib/d3/test/core/transition-test-call.js create mode 100644 public/lib/d3/test/core/transition-test-delay.js create mode 100644 public/lib/d3/test/core/transition-test-duration.js create mode 100644 public/lib/d3/test/core/transition-test-each.js create mode 100644 public/lib/d3/test/core/transition-test-id.js create mode 100644 public/lib/d3/test/core/transition-test-remove.js create mode 100644 public/lib/d3/test/core/transition-test-select.js create mode 100644 public/lib/d3/test/core/transition-test-selectAll.js create mode 100644 public/lib/d3/test/core/transition-test-style.js create mode 100644 public/lib/d3/test/core/transition-test-styleTween.js create mode 100644 public/lib/d3/test/core/transition-test-text.js create mode 100644 public/lib/d3/test/core/transition-test-time.js create mode 100644 public/lib/d3/test/core/transition-test-transition.js create mode 100644 public/lib/d3/test/core/transition-test-tween.js create mode 100644 public/lib/d3/test/core/transition-test.js create mode 100644 public/lib/d3/test/core/transpose-test.js create mode 100644 public/lib/d3/test/core/values-test.js create mode 100644 public/lib/d3/test/core/version-test.js create mode 100644 public/lib/d3/test/core/xhr-test.js create mode 100644 public/lib/d3/test/core/xml-test.js create mode 100644 public/lib/d3/test/core/zip-test.js create mode 100644 public/lib/d3/test/csv/csv-test.js create mode 100644 public/lib/d3/test/csv/format-test.js create mode 100644 public/lib/d3/test/csv/parse-test.js create mode 100644 public/lib/d3/test/env-assert.js create mode 100644 public/lib/d3/test/env-fragment.js create mode 100644 public/lib/d3/test/env-xhr.js create mode 100644 public/lib/d3/test/env.js create mode 100644 public/lib/d3/test/geo/albers-test.js create mode 100644 public/lib/d3/test/geo/azimuthal-test.js create mode 100644 public/lib/d3/test/geo/bonne-test.js create mode 100644 public/lib/d3/test/geo/equirectangular-test.js create mode 100644 public/lib/d3/test/geo/greatArc-test.js create mode 100644 public/lib/d3/test/geo/mercator-test.js create mode 100644 public/lib/d3/test/geo/path-test.js create mode 100644 public/lib/d3/test/geom/polygon-test.js create mode 100644 public/lib/d3/test/layout/cluster-test.js create mode 100644 public/lib/d3/test/layout/hierarchy-test.js create mode 100644 public/lib/d3/test/layout/histogram-test.js create mode 100644 public/lib/d3/test/layout/pack-test.js create mode 100644 public/lib/d3/test/layout/partition-test.js create mode 100644 public/lib/d3/test/layout/pie-test.js create mode 100644 public/lib/d3/test/layout/tree-test.js create mode 100644 public/lib/d3/test/layout/treemap-test.js create mode 100644 public/lib/d3/test/scale/category-test.js create mode 100644 public/lib/d3/test/scale/linear-test.js create mode 100644 public/lib/d3/test/scale/log-test.js create mode 100644 public/lib/d3/test/scale/ordinal-test.js create mode 100644 public/lib/d3/test/scale/pow-test.js create mode 100644 public/lib/d3/test/scale/quantile-test.js create mode 100644 public/lib/d3/test/scale/quantize-test.js create mode 100644 public/lib/d3/test/scale/sqrt-test.js create mode 100644 public/lib/d3/test/svg/arc-test.js create mode 100644 public/lib/d3/test/svg/area-radial-test.js create mode 100644 public/lib/d3/test/svg/area-test.js create mode 100644 public/lib/d3/test/svg/axis-test.js create mode 100644 public/lib/d3/test/svg/line-radial-test.js create mode 100644 public/lib/d3/test/svg/line-test.js create mode 100644 public/lib/d3/test/svg/symbol-test.js create mode 100644 public/lib/d3/test/time/day-test.js create mode 100644 public/lib/d3/test/time/days-test.js create mode 100644 public/lib/d3/test/time/format-test.js create mode 100644 public/lib/d3/test/time/hour-test.js create mode 100644 public/lib/d3/test/time/hours-test.js create mode 100644 public/lib/d3/test/time/minute-test.js create mode 100644 public/lib/d3/test/time/minutes-test.js create mode 100644 public/lib/d3/test/time/month-test.js create mode 100644 public/lib/d3/test/time/months-test.js create mode 100644 public/lib/d3/test/time/scale-test.js create mode 100644 public/lib/d3/test/time/second-test.js create mode 100644 public/lib/d3/test/time/seconds-test.js create mode 100644 public/lib/d3/test/time/week-test.js create mode 100644 public/lib/d3/test/time/weeks-test.js create mode 100644 public/lib/d3/test/time/year-test.js create mode 100644 public/lib/d3/test/time/years-test.js rename {lib => public/lib}/jquery/jquery-svgpan.min.js (100%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/jquery-ui.js (100%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/jquery.asmselect.css (100%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/jquery.asmselect.js (100%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/jquery.js (100%) mode change 100755 => 100644 create mode 100644 public/lib/jquery/jquery.js~ rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_flat_10_000000_40x100.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-icons_222222_256x240.png (100%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/ui-lightness/images/ui-icons_228ef1_256x240.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-icons_ef8c08_256x240.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-icons_ffd27a_256x240.png (100%) mode change 100755 => 100644 rename {lib/jquery/ui/css => public/lib/jquery}/ui-lightness/images/ui-icons_ffffff_256x240.png (100%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/ui-lightness/jquery-ui-1.8.18.custom.css (100%) mode change 100755 => 100644 create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-icons_222222_256x240.png rename {lib => public/lib}/jquery/ui/css/ui-lightness/images/ui-icons_228ef1_256x240.png (100%) mode change 100755 => 100644 create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-icons_ef8c08_256x240.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-icons_ffd27a_256x240.png create mode 100644 public/lib/jquery/ui/css/ui-lightness/images/ui-icons_ffffff_256x240.png rename {lib => public/lib}/jquery/ui/css/ui-lightness/jquery-ui-1.8.18.custom.css (100%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/ui/index.html (98%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/ui/js/jquery-1.7.1.min.js (100%) mode change 100755 => 100644 rename {lib => public/lib}/jquery/ui/js/jquery-ui-1.8.18.custom.min.js (100%) mode change 100755 => 100644 rename graph.css => public/stylesheets/graph.css (91%) mode change 100755 => 100644 rename reset.css => public/stylesheets/reset.css (100%) mode change 100755 => 100644 rename {tex => public/tex}/enumitem.sty (100%) rename {tex => public/tex}/footer.tex (100%) mode change 100755 => 100644 rename {tex => public/tex}/header.tex (100%) mode change 100755 => 100644 rename {tex => public/tex}/ieee.pdf (100%) mode change 100755 => 100644 rename {tex => public/tex}/isit-bw.pdf (100%) mode change 100755 => 100644 rename {tex => public/tex}/logo.png (100%) mode change 100755 => 100644 rename {tex => public/tex}/schedule.tex (98%) rename {tex => public/tex}/test.aux (100%) mode change 100755 => 100644 create mode 100644 tools/windows/pdfTotxtConverter.exe create mode 100644 tools/windows/pdfToxmlConverter.exe diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6ca7ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +logs +project/project +project/target +target +tmp +.history +dist \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..6373f4a --- /dev/null +++ b/README @@ -0,0 +1,4 @@ +This is your new Play 2.0 application +===================================== + +This file will be packaged with your application, when using `play dist`. diff --git a/app/controllers/Application.scala b/app/controllers/Application.scala new file mode 100644 index 0000000..1416387 --- /dev/null +++ b/app/controllers/Application.scala @@ -0,0 +1,51 @@ +package controllers + +import play.api._ +import play.api.mvc._ +import java.io.File +import paper.Analyze +import generators._ + +object Application extends Controller { + + def index = Action { + Ok(views.html.index("")) + } + + def generateSchedulePdf = Action { request => + val body = request.body.asFormUrlEncoded + if(body != None) { + val papers = body.get("papers[]").toList + val abstractGet = body.get("abstract") + + val abstractVal = if(abstractGet.length == 1) abstractGet.toList.head.toInt else 0 + + Ok(SchedulePdfGenerator.apply(papers, abstractVal)) + } else Ok("Something went wrong") + } + + def generateTaskProcess(task: String, path: String) = Action { + Ok(TaskProcessGenerator.apply(task, utf8URLDecode(path))) + } + + def generatePersonalGraph(link: String) = Action { + Ok(views.html.index(link)) + } + + def generateLink = Action { request => + val body = request.body.asFormUrlEncoded + if(body != None) { + val email = body.get("useremail").toList + } + // TODO + Redirect(routes.Application.index) + } + + def getGraphData(link: String) = Action { + Ok("") // TODO + } + + private def utf8URLDecode(url: String): String = { + return """/%u([0-9a-f]{3,4})/i""".r.replaceAllIn(java.net.URLDecoder.decode(url.replace("\\00", "%u00"), "UTF-8"), "&#x\\1;") + } +} \ No newline at end of file diff --git a/lib/jquery/jquery.js~ b/app/generators/LinkGenerator.scala old mode 100755 new mode 100644 similarity index 100% rename from lib/jquery/jquery.js~ rename to app/generators/LinkGenerator.scala diff --git a/app/generators/SchedulePdfGenerator.scala b/app/generators/SchedulePdfGenerator.scala new file mode 100644 index 0000000..6f1bd17 --- /dev/null +++ b/app/generators/SchedulePdfGenerator.scala @@ -0,0 +1,214 @@ +package generators + +import play.api._ +import play.api.mvc._ +import play.i18n.Lang +import play.api.libs.json._ +import scala.io.Source +import java.io.File +import java.security.MessageDigest + + +case class Paper(id: String, title: String, authors: String, pdf: String, date: String, room: String) { + def getId: String = this.id + def getTitle: String = this.title + def getAuthors: String = this.authors + def getPdf: String = this.pdf + def getDate: String = this.date + def getRoom: String = this.room + + def setId(newId: String): Paper = Paper(newId, title, authors, pdf, date, room) + def setTitle(newTitle: String): Paper = Paper(id, newTitle, authors, pdf, date, room) + def setAuthors(newAuthors: String): Paper = Paper(id, title, newAuthors, pdf, date, room) + def setPdf(newPdf: String): Paper = Paper(id, title, authors, newPdf, date, room) + def setDate(newDate: String): Paper = Paper(id, title, authors, pdf, newDate, room) + def setRoom(newRoom: String): Paper = Paper(id, title, authors, pdf, date, newRoom) +} + +object PaperCreator { + def createPaper(json: JsValue): Paper = { + Paper((json \ "id").toString, (json \ "title").toString.drop(1).dropRight(1), (json \ "authors").toString.drop(1).dropRight(1), (json \ "pdf").toString.drop(1).dropRight(1), (json \ "date").toString.drop(1).dropRight(1), (json \ "room").toString.drop(1).dropRight(1)) + } +} + +object SchedulePdfGenerator { + def apply(selectedPapers: List[String], abstractVal: Int): String = { + val json: JsValue = Json.parse(Source.fromFile("public/js/data.json").mkString) + val nodes = (json \\ "nodes").head + + // Dividing to get seconds in place of milliseconds + //date_default_timezone_set ( "UTC" ); + val papers = changeDate(getPapers(nodes, selectedPapers)) + + + // Get Temporary directory + val postfix = md5(Math.random.toInt.toString).substring(0,7) + val directory = "public/tex/temp/" + postfix + (new File(directory)).mkdir + + val tempContent = createSchedule(abstractVal, papers, directory) + val tempOutput = directory + "/isit_schedule" + + // Create system call for generating pdf + val call = "cat public/tex/header.tex " + tempContent + " public/tex/footer.tex | pdflatex --jobname " + tempOutput + + /* + // Make system call + $ret = exec($call); + + // Create temporary page "your download should appear in a moment. If not click here" + echo page_output($temp_output); + + // Redirect to schedule + header( 'Location: '.$temp_output.'.pdf' ) ; +*/ "" + } + + private def md5(s: String): String = { + var algorithm = MessageDigest.getInstance("MD5") + algorithm.update(s.getBytes) + algorithm.digest.toString + } + + private def changeDate(papers: List[Paper]): List[Paper] = { + def changeDate0(papers: List[Paper], accu: List[Paper]): List[Paper] = papers match { + case List() => accu + case x::xs => changeDate0(xs, x.setDate(x.getDate.dropRight(3)) :: accu) + } + + changeDate0(papers, List()).reverse + } + + /** + * Creates the content part of the schedule file + */ + private def createSchedule(abstractVal: Int, papers: List[Paper], directory: String): String = { + + // Sorts papers by date + //uasort($papers, "sort_by_date"); + + // Schedule and date + var schedule = "" + var date = "" + var time = "" + var first = true + + // Now for each paper, write it out + papers.foreach (p => { + // Check if the date is the same as before + val newDate = ""//date('l \t\h\e jS \of F Y', p.getDate) + val newTime = ""//date('h:i A', p.getDate) + + // Add day + if (!newDate.equals(date)) { + if (!first) schedule = schedule + endList + + schedule = schedule + addScheduleDay(newDate) + startList + first = false + } + + // Add schedule point + schedule = if (newTime.equals(time)) schedule + addSchedulePoint(abstractVal, p, "") + else schedule + addSchedulePoint(abstractVal, p, newTime) + + // Add schedule point and update date + date = newDate + time = newTime + } + ) + + // Save schedule to file + val file = directory + "/content.tex" + val fileObj = new File(file) + fileObj.createNewFile + val p = new java.io.PrintWriter(fileObj) + + p.print(schedule) + p.close + + file + } + + /** + * Constructs the latex code for a single paper in the schedule + */ + private def addSchedulePoint(abstractVal:Int, p: Paper, time: String): String = { + + // Get abstract + var abstr = "" + if (abstractVal == 1) { + abstr = TaskProcessGenerator.apply("abstract", p.getPdf) + abstr = latexSpecialChars(abstr) + abstr = "{\\small " + abstr + "} \n" + } + + // Get title + val title = "{\\it " + latexSpecialChars( p.getTitle/*, "\\'\"&\n\r{}[]"*/ ) + "} \\\\ \n"; + + // Get time and place + val point = if (time.equals("")) "\\item[{\\hfill " + p.getRoom + "}]\n" + else "\\item[{\\hfill \bf " + time + "} \\\\ {\\hfill " + p.getRoom + "}]\n" + + // Get authors + val authors = "{" + p.getAuthors + "} \\\\ \n" + + point + title + authors + abstr + "\n" + } + + private def startList: String = { + "%\n%\n\\begin{enumerate}[leftmargin=5cm, labelsep=0.3cm, rightmargin=2cm, align=right, itemsep=1cm, style=multiline]\n%\n" + } + + private def endList: String = { + "\\end{enumerate}\n%\n" + } + + /** + * Constructs the latex code for a page dedicated to a certain day + */ + private def addScheduleDay(date: String) { + "\\clearpage\\period{" + date + "}\\hfil\\break \\\\ \n" + } + + /** + * Sorts two items based on their date + */ + private def sortByDate(a: Paper, b: Paper): Int = { + return if(a.getDate < b.getDate) -1 else 1 + } + + + /** + * Displays a field for downloading the schedule + */ + private def pageOutput(tempOutput: String): String = { + "TrailHead

If your download didn't start automatically, click here

" + } + + private def latexSpecialChars( str: String ): String = { + val map = Map( + "#"->"\\#", + "$"->"\\$", + "%"->"\\%", + "&"->"\\&", + "~"->"\\~{}", + "_"->"\\_", + "^"->"\\^{}", + "\\"->"\\textbackslash", + "{"->"\\{", + "}"->"\\}" + ) + return """([\^\%~\\\\#\$%&_\{\}])""".r.replaceAllIn(str, m => map(m.group(1))) + } + + private def getPapers(array: JsValue, selectedPapers: List[String]): List[Paper] = { + var output: List[Paper] = List[Paper]() + + selectedPapers.foreach((id: String) => { + val paper = PaperCreator.createPaper(array.apply(id.toInt)) + output = paper.setId(id) :: output + }) + + output.reverse + } +} \ No newline at end of file diff --git a/app/generators/TaskProcessGenerator.scala b/app/generators/TaskProcessGenerator.scala new file mode 100644 index 0000000..1ff4ef2 --- /dev/null +++ b/app/generators/TaskProcessGenerator.scala @@ -0,0 +1,46 @@ +package generators + +import play.api._ +import play.api.mvc._ +import play.i18n.Lang +import scala.io.Source +import java.io.File +import paper._ + +object TaskProcessGenerator { + def apply(task: String, path: String): String = { + return if(task.equals("abstract")) getAbstract(path) else "Task not recognized" + } + + private def getAbstract(pdf: String): String = { + val array = List[(String, String)](("û", "fi"), (""d", "≤"), ("ï¬", "fi"), ("≤", "≤"), ("º", "κ"), + ("´", "δ"), (""¥", "⊥"), (""H", "≈"), (""", "♣"), ("³", "γ"), ("Á", "ρ"), + ("Ä", "τ"), ("»", "λ")) + + + val files = Analyze.main(Array[String]("public/" + pdf, "-p")) + + if(files.isEmpty) return "Can't load the abstract" + else return replaceWithList(files.head.getAbstract.getText, array) + } + + private def replaceWithList(str: String, array: List[(String, String)]): String = { + var output = str + + array.foreach((l: (String, String)) => output = output.replace(l._1, l._2)) + + output + } + + private def repeatStr(str: String, nb: Int): String = { + var output = "" + var i = 0 + + while(i < nb) { + output = output + str + i = i + 1 + } + + output + } +} \ No newline at end of file diff --git a/app/paper/Analyze.scala b/app/paper/Analyze.scala new file mode 100644 index 0000000..2f63c8c --- /dev/null +++ b/app/paper/Analyze.scala @@ -0,0 +1,64 @@ +package paper + +object Analyze { + def main(args : Array[String]): List[Paper] = { + // create analyzer + val A : Analyzer = new Analyzer() + + // Check that a directory is supplied (there is an argument) + if (args.length == 0 || args.length > 2) {println("You should provide at leath a path and at most a path and an option. Type -h for help.");List()} + + else if(args.contains("-h")) { println("How to call: Analyze [path] [parameter]?\nPARAMETERS:\n\t-p : parsing\n\t-s : looks for xml scheduler\n\t-c : compare\n\t-e : extend\n\t-g : create graph\n\t-h : shows this help page\n\tnothing : do everything"); List()} + // Then go ahead + else A.analyze(args(0), args.toList.tail) + } +} + +class Analyzer extends Object with LoadPaper + with ParsePaper + with ExtendPaper + with ComparePaper + with XMLScheduleParser + with Graphs { + + // Set a limit in percent for when papers get an edge between them + val limit : Int = 1 + + // Get cached papers in this order + val cache : List[String] = List(Cache.linked, Cache.extended, Cache.scheduled, Cache.parsed) + + // Set sources we want to extend with + //val sources : List[PaperSource] = List(TalkDates, TalkRooms, PdfLink) + val sources : List[PaperSource] = List(PdfLink) + + // Analyze a paper + def analyze(paperPos: String, options: List[String]): List[Paper] = { + // Get a list of parsed papers + val papers : Option[List[Paper]] = if(options.isEmpty || options.contains("-p")) Some(loadAndParse(paperPos, cache, XMLParser, XMLConverterLoader)) else None + + // Mix in the schedule XML data + val xmlPapers : Option[List[Paper]] = if(options.isEmpty || options.contains("-s")) Some(getXMLSchedule(paperPos, papers)) else None + + // Extend papers with tertiary data + val extendedPapers : Option[List[Paper]] = if(options.isEmpty || options.contains("-e")) Some(extend(paperPos, xmlPapers, sources)) else None + + // Compare the papers individually + val comparedPapers : Option[List[Paper]] = if(options.isEmpty || options.contains("-c")) Some(compare(paperPos, extendedPapers, limit)) else None + + + if(options.isEmpty || options.contains("-g")){ + // Create graph + val graph : Graph = getGraph(paperPos, comparedPapers) + + // Print graph to file 'data.json' + graph.save + } + + if(options.contains("-p")) return papers.get + else if(options.contains("-s")) return xmlPapers.get + else if(options.contains("-e")) return extendedPapers.get + else if(options.isEmpty || options.contains("-c")) return comparedPapers.get + + List() + } +} diff --git a/app/paper/ComparePaper.scala b/app/paper/ComparePaper.scala new file mode 100644 index 0000000..c822db4 --- /dev/null +++ b/app/paper/ComparePaper.scala @@ -0,0 +1,51 @@ +package paper +import java.io._ +import scala.io.Source + +trait ComparePaper { + + def compare(paperPos:String, papers : Option[List[Paper]], limit : Int) : List[Paper] = { + println("BEGIN OF PAPERS COMPARISION") + val loadedPapers = if(papers == None) CacheLoader.load(paperPos, Cache.extended) else papers.get + + val finalPapers = loadedPapers.map(p => { + // Check that paper isn't already linked + if (p.meta.get("linked") == None) { + // Get list of papers that aren't current paper + val otherPapers = loadedPapers.filter(p != _) + + // Compare to every other paper + val weights : List[Int] = for (other <- otherPapers) yield getWeight(p, other) + + // Make links + //val links = for ((p,w) <- otherPapers.zip(weights) if w >= limit) yield Link(p.id,w) + val links = for ((p,w) <- otherPapers.zip(weights) if w >= 1) yield Link(p.index,w) + + // Add links to paper, and set it as linked + val result = p.setLinks(links).setMeta("linked", "yes") + + // Save result + Cache.save(result, Cache.linked) + + result + } + else p + }) + println("END OF PAPERS COMPARISION") + finalPapers + } + + def getWeight(p : Paper, o : Paper) : Int = { + // Get names + val pNames = p.getDistinctNames + val oNames = o.getDistinctNames + + // For each auther in p, check if he/she exists in other + var matches = (for (name <- pNames if oNames.contains(name)) yield 1).sum + + // return result + return (100 * matches.toDouble / pNames.length.toDouble).toInt + + } + +} diff --git a/app/paper/ExtendPaper.scala b/app/paper/ExtendPaper.scala new file mode 100644 index 0000000..989592f --- /dev/null +++ b/app/paper/ExtendPaper.scala @@ -0,0 +1,105 @@ +package paper + +abstract class PaperSource { + def getInfo(p : Paper) : String + def getLabel : String +} + +object TalkDates extends PaperSource { + + import scala.util.Random + import java.util.Date + import java.sql.Timestamp + import java.util.Calendar + + // TODO: This is just a temporary implementation + def getInfo(p : Paper) : String = { + + // Get Calendar and Random + var c = Calendar.getInstance + var r = new Random + + // Set starting point as tomorrow at 8 + c.add(Calendar.DAY_OF_MONTH, 1) + c.set(Calendar.HOUR_OF_DAY,8) + c.set(Calendar.MINUTE,0) + c.set(Calendar.SECOND,0) + c.set(Calendar.MILLISECOND,0) + + // Now add between zero and 6 hours + c.add(Calendar.HOUR, (r.nextDouble * 7).toInt) + // Add between 0 and 5 days + c.add(Calendar.DAY_OF_MONTH, (r.nextDouble * 6).toInt) + + // Get a timeStamp + var t = new Timestamp(c.getTime.getTime).getTime.toString + + //var n = new Timestamp(new Date().getTime).getTime + //var r = (n + (new Random().nextDouble * (60*60*24*4*1000)).toLong).toString + + return t + } + + def getLabel : String = "date" +} + + +// Adds the link of the pdf to the paper +object PdfLink extends PaperSource { + import scala.util.Random + + def getInfo(p : Paper) : String = { + + var f : String = p.meta("file") + var pdf : String = f.takeWhile(_!='.').concat(".pdf") + return pdf; + } + + def getLabel : String = "pdf" +} + + +object TalkRooms extends PaperSource { + import scala.util.Random + + // TODO: This is also just a temporary thing + def getInfo(p : Paper) : String = { + + // Return a random room between 1 and 10 + return (new Random().nextDouble * 10).toInt.toString + } + + def getLabel : String = "room" +} + + +/** Extend paper loops through a list of sources. Each source implements the + * interface paperSource and provides two methods: getLabel and getInfo. + * Get label returns the map label, while getInfo returns the particular information + */ +trait ExtendPaper { + + def extend(paperPos: String, papers : Option[List[Paper]], sources : List[PaperSource]) : List[Paper] = { + println("BEGIN OF PAPERS EXTENSION") + val loadedPapers = if(papers == None) CacheLoader.load(paperPos, Cache.scheduled) else papers.get + val finalPapers = loadedPapers.map(p => { + + var result : Paper = p + + // For each source, check if it's already added, and if not, add it + for (s <- sources if !p.hasMeta(s.getLabel)) { + result = result.setMeta(s.getLabel, s.getInfo(p)) + } + + // Save result + Cache.save(result, Cache.extended) + + // return result + result + }) + + println("END OF PAPERS EXTENSION") + finalPapers + } + +} diff --git a/app/paper/FileFormat.scala b/app/paper/FileFormat.scala new file mode 100644 index 0000000..b8e9604 --- /dev/null +++ b/app/paper/FileFormat.scala @@ -0,0 +1,72 @@ +package paper +import java.io.File + +object Paths { + private val toolsDirStr = "tools" + private val linuxDirStr = "linux" + private val windowsDirStr = "windows" + private val windowsSepStr = "\\" + private val linuxSepStr = "/" + private val windowsExtStr = ".exe" + private val linuxExtStr = "" + + + private def getOSDir: String = { if(SystemHelper.isWindows) windowsSepStr + windowsDirStr + windowsSepStr + else if(SystemHelper.isLinux) linuxSepStr + linuxDirStr + linuxSepStr + else "" } + + // Returns the tools directory according to the current operating system + def toolsDir = toolsDirStr + getOSDir + + // Returns the file extension according to the current operating system + def ext = if(SystemHelper.isWindows) windowsExtStr else if(SystemHelper.isLinux) linuxExtStr else "" + + // Returns the path separator according to the current operating system + def sep = if(SystemHelper.isWindows) windowsSepStr else if(SystemHelper.isLinux) linuxSepStr else "" +} + +// This class transforms a File object into another File object, according to the extension of the file +abstract class FileFormat { + def convertTo(format: String, params: List[String]): File = this match{ + case TXTFormat(file) => file + case PDFFormat(file) => { + val command = CommandDetector.detect(Paths.toolsDir + "pdfTo" + format + "Converter" + Paths.ext, format) + + val process: Process = sys.runtime.exec((List(command) ::: params ::: List(file.getAbsolutePath())).toArray[String]) + + // Waiting until the end of the command execution + if(process.waitFor() != 0) { println("Can't convert pdf file. Program will exit"); exit } + + new File(file.getParent() + Paths.sep + SystemHelper.name(file.getName) + "." + format) + } + } + + // Performs final procedures before the end of the file processing (mostly deleting intermediate files) + def releaseFile(newFile: File) = this match { + case TXTFormat(file) => + case PDFFormat(file) => newFile.delete() + } +} + +case class TXTFormat (file: File) extends FileFormat +case class PDFFormat (file: File) extends FileFormat + + +object FileFormatDispatcher { + // Determines which FileFormat should be used according to the extension of the file + def getFileFormat(file: File): FileFormat = { + SystemHelper.ext(file.getName()) match { + case "txt" => new TXTFormat(file) + case "pdf" => new PDFFormat(file) + } + } +} + +// This object handles special tool cases +object CommandDetector { + def detect(toolPath: String, format: String): String = { + if(format.equals("xml") && SystemHelper.isLinux) return "pdftohtml" + + toolPath + } +} \ No newline at end of file diff --git a/app/paper/FileLoader.scala b/app/paper/FileLoader.scala new file mode 100644 index 0000000..adaf8e3 --- /dev/null +++ b/app/paper/FileLoader.scala @@ -0,0 +1,112 @@ +package paper +import java.io.File +import scala.io.Source +import scala.io.BufferedSource + +// This object provides helpful methods for file and system managing +object SystemHelper { + private val supportedFormats = """pdf""" + private val os = sys.props.get("os.name") + + def ext(file: String) = """^.+?\.""".r.findFirstIn(file.reverse).get.dropRight(1).reverse + def name(file: String) = """^.+?\.""".r.replaceAllIn(file.reverse, "").reverse + def isSupported(format: String): Boolean = ("^" + supportedFormats + "$").r.findFirstIn(format).isDefined + + // Returns the files from a directory + def getFilesFromDirectory(orig: File): List[File] = { + if(orig.isDirectory()) orig.listFiles.filter(f => (""".+\.(""" + supportedFormats + """)$""").r.findFirstIn(f.getName).isDefined).toList + else Nil + } + + // The apps is on Windows + def isWindows: Boolean = os match { + case Some(s) => """.*Windows.*""".r.findFirstIn(s.toString()).isDefined + case None => false + } + + // The apps is on Linux + def isLinux: Boolean = os match { + case Some(s) => """.*Linux.*""".r.findFirstIn(s.toString()).isDefined + case None => false + } +} + +trait FileLoader { + def loadFromFile(file : File, p : Parsers) : Option[Paper] + + // This function sets the id and metadata before final returning + def setLastModifications(file: File, paper: Option[Paper]): Option[Paper] = { + if (paper != None) { + // Get index + try { + var id = (SystemHelper.name(file.getName())).toInt + + // Set filename and id + val finalPaper : Paper = paper.get.setMeta("file" -> file.getPath).setId(id) + + return Some(finalPaper) + }catch { + case _ => { println("The paper's name must contain only numerical values. Not parsed"); return None } + } + } + return None + } +} + +// This loader doesn't care about the format, it just passes the file to the parser +object SimpleLoader extends FileLoader { + def loadFromFile(file : File, p : Parsers) : Option[Paper] = { + println("parsing " + file.getPath + " using simple loader") + + val text = Source.fromFile(file) + + // actual parsing of the file content + val maybePaper : Option[Paper] = p.parse(text) + + // If paper exists and parsed, save it in cache + setLastModifications(file, maybePaper) + } +} + +// This class uses external tools in order to convert a particular format file into another before it is passed to the parser +abstract class ExternalLoader extends FileLoader { + // Converts a particular format file into another using an external tool + def loadFromFile(file : File, p : Parsers, format : String, params : List[String]) : Option[Paper] = { + // getFileFormat looks for other file formats (like pdf), then using external tools it extracts the content of the file and + // converts it to another format file + val fileFormat = FileFormatDispatcher.getFileFormat(file) + val newFile = fileFormat.convertTo(format, params) + val text = Source.fromFile(newFile) + + // actual parsing of the file content + val maybePaper : Option[Paper] = p.parse(text) + + // this method deletes temporary files that could have been previously created + fileFormat.releaseFile(newFile) + + // If paper exists and parsed, save it in cache + setLastModifications(file, maybePaper) + } +} + +// This object tries to convert the input file into txt before parsing +object TXTConverterLoader extends ExternalLoader { + override def loadFromFile(file : File, p : Parsers) : Option[Paper] = { + println("parsing " + file.getPath + " using txt loader") + // looking for the format and setting the correct parameters + loadFromFile(file, p, "txt", List("-enc", "UTF-8")) + } +} + +// This object converts a file into an xml one before parsing. Must use a parser that parses XML +object XMLConverterLoader extends ExternalLoader { + def loadFromFile(file : File, p : Parsers) : Option[Paper] = { + println("parsing " + file.getPath + " using xml loader") + + // looking for the format and setting the correct parameters + SystemHelper.ext(file.getName()) match { + case "txt" => loadFromFile(file, p, "txt", List("-enc", "UTF-8")) + case "pdf" => loadFromFile(file, p, "xml", List("-xml", "-q", "-enc", "UTF-8")) + } + } +} \ No newline at end of file diff --git a/app/paper/Graph.scala b/app/paper/Graph.scala new file mode 100644 index 0000000..0ce495e --- /dev/null +++ b/app/paper/Graph.scala @@ -0,0 +1,100 @@ +package paper + +trait Graphs { + + def getGraph(paperPos:String, papers : Option[List[Paper]]) : Graph = { + println("BEGIN OF GRAPH CREATION") + val loadedPapers = if(papers == None) CacheLoader.load(paperPos, Cache.linked) else papers.get + // Add all papers as nodes + val nodes : List[Node] = for (p <- loadedPapers) yield makeNode(p) + + // Then create all edges + val edges : List[Edge] = for (p <- loadedPapers; e <- makeEdges(p, nodes)) yield e + + println("END OF GRAPH CREATION") + return new Graph(nodes, edges) + } + + // MODIFICATION + def makeNode(paper : Paper) : Node = { + println("Making node for " + paper.id) + Node(paper.id, paper.meta("xmlpapertitle"), paper.meta("xmlauthors"), paper.meta("pdf"), paper.meta("xmldate"), paper.meta("xmlroom")) + } + + def makeEdges(paper : Paper, nodes : List[Node]) : List[Edge] = { + // make edge + val edges = for (link <- paper.links) yield (makeEdge(paper.index, link)) + // Sort edges by weight and pick the n biggest + val l = math.min(4, edges.length) + return edges.sortWith(_.weight > _.weight).take(l) + } + + def makeEdge(index : Int, link : Link) : Edge = Edge(index, link.index, link.weight) + +} + +class Graph(nodes : List[Node], edges : List[Edge]) { + + def save : Unit = { + val f = new java.io.File("data.json") + val p = new java.io.PrintWriter(f) + p.println(toString) + p.close + } + + override def toString : String = { + var ret : String = "{\n" + + // add nodes + ret += "\"nodes\":" + nodes.mkString("[\n ",",\n ","\n],") + "\n" + + // add edges + ret += "\"links\":" + edges.mkString("[\n ",",\n ","\n]") + "\n\n" + + // End + ret += "}" + + return ret + } +} + +case class Node(id : Int, title : String, authors : String, pdf : String, date : String, room : String) { + override def toString : String = { + var ret : String = "{" + ret += "\"id\":" + id + ",\n " + ret += "\"title\":\"" + Escape(title) + "\",\n " + ret += "\"authors\":\"" + Escape(authors) + "\",\n " + ret += "\"pdf\":\"" + Escape(pdf) + "\",\n " + ret += "\"date\":\"" + Escape(date) + "\",\n " + ret += "\"room\":\"" + Escape(room) + "\"" + ret += "}" + return ret + } +} + +case class Edge(from : Int, to : Int, weight : Int) { + override def toString : String = "{\"source\":" + from + ",\"target\":" + to + ",\"value\":" + weight + "}" +} + +/** Escapes a raw string for use in HTML.*/ +object Escape +{ + def apply(s: String) = + { + val out = new StringBuilder + for(i <- 0 until s.length) + { + s.charAt(i) match + { + case '>' => out.append(">") + case '&' => out.append("&") + case '<' => out.append("<") + case '"' => out.append(""") + case '\n' => out.append(" ") + case '\\' => out.append("\\\\") + case c => out.append(c) + } + } + out.toString + } +} diff --git a/app/paper/InformationExtractors.scala b/app/paper/InformationExtractors.scala new file mode 100644 index 0000000..03c356e --- /dev/null +++ b/app/paper/InformationExtractors.scala @@ -0,0 +1,180 @@ +package paper + +trait InformationExtractor { + // This method finds the first element in a list matching a particular condition and returns it with the rest of the list + protected def findFirstOf(list: List[XMLParagraph], condition: (XMLParagraph) => Boolean): List[XMLParagraph] = list match{ + case List() => Nil + case x::xs => if(condition(x)) x::xs else findFirstOf(xs, condition) + } + + // This method find the first element matching a condition and returns the previous ones (not matching) + protected def untilFirstOf(list: List[XMLParagraph], condition: (XMLParagraph) => Boolean): List[XMLParagraph] = { + def untilFirstOf0(l: List[XMLParagraph], accu: List[XMLParagraph]): List[XMLParagraph] = l match{ + case List() => accu.reverse + case x::xs => if(condition(x)) accu.reverse else untilFirstOf0(xs, x::accu) + } + + untilFirstOf0(list, List()) + } + + // This method filters the first elements matching a condition which are adjacent + protected def filterAdjacents(list: List[XMLParagraph], condition: (XMLParagraph) => Boolean): List[XMLParagraph] = { + def filterAdjacents0(l: List[XMLParagraph], accu: List[XMLParagraph]): List[XMLParagraph] = l match { + case List() => accu + case x::xs => if(condition(x)) filterAdjacents0(xs, x::accu) + else if(accu.length == 0) filterAdjacents0(xs, accu) else accu + } + + filterAdjacents0(list, List()).reverse + } + + // This method finds the first elements matching a condition which are adjacent and returns the list of the remaining ones (after these) + protected def discardAdjacents(list: List[XMLParagraph], condition: (XMLParagraph) => Boolean): List[XMLParagraph] = { + def discardAdjacents0(l: List[XMLParagraph], accu: Int): List[XMLParagraph] = l match { + case List() => Nil + case x::xs => if(condition(x)) discardAdjacents0(xs, accu + 1) + else if(accu == 0) discardAdjacents0(xs, accu) else x::xs + } + + discardAdjacents0(list, 0) + } + + // This method takes a list of strings and returns a string containing the concatenation of all the other strings + protected def concatText(list: List[String]): String = { + def concatText0(l: List[String], accu: String): String = l match { + case List() => if(accu.length() > 0) accu.dropRight(1) else accu // Last \n replacement + case x::xs => concatText0(xs, accu + x + "\n") + } + + concatText0(list, "") + } +} + + + + +trait AuthorsExtractor1 extends InformationExtractor{ + // This method extracts the authors of the article. + // It uses the following rules: + // - They are located in the first page between title and abstract + // - Every author paragraph contains the name at the top of it, i.e. the names are located at the first line of these paragraphs + def extractAuthors(paper: Paper, xml: XMLDocument, paragraphs: List[XMLParagraph]): (List[XMLParagraph], Paper) = { + val list = untilFirstOf(paragraphs, (p: XMLParagraph) => p.hasOption(XMLParagraphOptions.JUSTIFY) && p.getPosition.getWidth >= xml.getPage(1).getPosition.getWidth / 3) + val remainingList = paragraphs.drop(list.length) + + // Finding of the most at the top paragraphs + if(list.length == 0) return (paragraphs, paper) + val minTop = list.map((p:XMLParagraph) => p.getPosition.getY).min + val unprocessedAuthorsList = list.filter((p:XMLParagraph) => p.getPosition.getY == minTop) + + // Applying the extraction processing + val authors = unprocessedAuthorsList.flatMap((p:XMLParagraph) => ("""(.+?""" + ExtractionRegexes.authorsSeparator + """)|(.+?$)""").r.findAllIn(""" [0-9]+""".r.replaceAllIn(p.getLines.head.getText, ""))) + val authorsList = authors.map((s: String) => new Author(ExtractionRegexes.authorsSeparator.r.replaceAllIn(s, ""))) + + + if(authorsList.length != 0) (remainingList, paper.setAuthors(authorsList)) + else (paragraphs, paper) + + } +} + +trait AbstractExtractor1 extends InformationExtractor{ + // This method extracts the abstract of the article. + // It uses the following rules: + // - It is the first justified paragraph + // - It is entirely contained in the first page + def extractAbstract(paper: Paper, xml: XMLDocument, paragraphs: List[XMLParagraph]): (List[XMLParagraph], Paper) = { + val list = findFirstOf(paragraphs, (p: XMLParagraph) => p.hasOption(XMLParagraphOptions.JUSTIFY) && p.getPosition.getWidth >= xml.getPage(1).getPosition.getWidth / 3) + + if(list.length == 0) return (paragraphs, paper) + val xmlFont = xml.getFontsContainer.getXMLFont(list.head.getFontID) + val abstractList = filterAdjacents(list, (p: XMLParagraph) => xmlFont.get.checkID(p.getFontID) && p.hasOption(XMLParagraphOptions.JUSTIFY)).map((p: XMLParagraph) => p.getText.replaceAll("\n", " ")) + val remainingList = discardAdjacents(list, (p: XMLParagraph) => xmlFont.get.checkID(p.getFontID) && p.hasOption(XMLParagraphOptions.JUSTIFY)) + + if(abstractList.length != 0) (remainingList, paper.setAbstract(new Abstract(concatText(abstractList)))) + else (paragraphs, paper) + } +} + +trait TitleExtractor1 extends InformationExtractor { + // This method extracts the title of the article. + // It uses the following rules: + // - The title is contained in the first page + // - It has the biggest font size + def extractTitle(paper: Paper, xml: XMLDocument, paragraphs: List[XMLParagraph]): (List[XMLParagraph], Paper) = { + // This method finds the font id having the maximum size + def findMaxSizeID(paragraphs: List[XMLParagraph]): String = { + def findMaxSizeID0(paragraphs: List[XMLParagraph], max: Int, id: String): String = paragraphs match{ + case List() => id + case x::xs => + val newSize = xml.getFontsContainer.getXMLFont(x.getFontID).get.getSize.toInt + + if(newSize > max) findMaxSizeID0(xs, newSize, xml.getFontsContainer.getXMLFont(x.getFontID).get.getID) + else findMaxSizeID0(xs, max, id) + } + + findMaxSizeID0(paragraphs, 0, "") + } + + val maxSizeIDFont = xml.getFontsContainer.getXMLFont(findMaxSizeID(paragraphs.take(10))) + val title = findFirstOf(paragraphs, p => maxSizeIDFont.get.checkID(p.getFontID) || p.hasOption(XMLParagraphOptions.PAGE_CENTERED)) + + if(title.length != 0) (title.tail, paper.setTitle(new Title(title.head.getText.replace("\n", " ")))) + else (paragraphs, paper) + } +} + + +trait BodyExtractor1 extends InformationExtractor { + // This method extracts the body of the article. + // It uses the following rules: + // - It begins with the first justified paragraph after the abstract + // - It is justified and belongs to one column + def extractBody(paper: Paper, xml: XMLDocument, paragraphs: List[XMLParagraph]): (List[XMLParagraph], Paper) = { + val firstBodyList = findFirstOf(paragraphs, (p: XMLParagraph) => p.hasOption(XMLParagraphOptions.JUSTIFY) && !p.hasOption(XMLParagraphOptions.NO_COLUMN)) + if(firstBodyList.length == 0) return (paragraphs, paper) + val bodyXmlFont = xml.getFontsContainer.getXMLFont(firstBodyList.head.getFontID) + + // Filter (applying the rules) + val bodyListWithReturn = firstBodyList.filter((p: XMLParagraph) => bodyXmlFont.get.checkID(p.getFontID) && p.hasOption(XMLParagraphOptions.JUSTIFY) && !p.hasOption(XMLParagraphOptions.NO_COLUMN)) + + // Calculating the remaining list + val lastBodyParagraph = bodyListWithReturn.last + val bodyList = bodyListWithReturn.map((p: XMLParagraph) => p.getText.replaceAll("\n", " ")) + val remainingList = findFirstOf(paragraphs, (p:XMLParagraph) => p.getText.equals(lastBodyParagraph.getText)).tail + + if(bodyList.length != 0) (remainingList, paper.setBody(new Body(concatText(bodyList)))) + else (paragraphs, paper) + } +} + +trait ReferencesExtractor1 extends InformationExtractor { + // This method extracts the references of the article. + // It uses the following rules: + // - They begin with a paragraph containing a reference title + // - Each following paragraph is a reference. + // - The method recognizes the reference format and applies a suitable extraction strategy + def extractReferences(paper: Paper, xml: XMLDocument, paragraphs: List[XMLParagraph]): (List[XMLParagraph], Paper) = { + val refParagraphs = findFirstOf(paragraphs, (p: XMLParagraph) => ("""^""" + ExtractionRegexes.referencesName + """$""").r.findFirstIn(p.getText).isDefined) + val referencesStringList = if(!refParagraphs.isEmpty) refParagraphs.tail else List() + + // This method takes a list of reference paragraphs and process them + def makeReferences(refs: List[XMLParagraph], accu: List[Reference]): List[Reference] = refs match { + case List() => accu + case x::xs => { + // Using of the good reference processor after a structure recognition + val refExtr = ReferenceProcessorExecuter.extract(x.getText.replaceAll("\n", " ")) + val title = refExtr._1 + val authors = refExtr._2 + + if(title == None || authors == None) makeReferences(xs, accu) + else makeReferences(xs, (new Reference(authors.get, title.get)::accu)) + } + } + + val refList = makeReferences(referencesStringList, List()).reverse + + if(refList.length != 0) (List(), paper.setReferences(refList)) + else (paragraphs, paper) + } +} \ No newline at end of file diff --git a/app/paper/LoadPaper.scala b/app/paper/LoadPaper.scala new file mode 100644 index 0000000..b6828ab --- /dev/null +++ b/app/paper/LoadPaper.scala @@ -0,0 +1,232 @@ +package paper + +import scala.util.parsing.input._ +import scala.collection.immutable.Stream +import scala.io.Source +import java.io._ + + +object Cache { + + // Constants + val dir = "cache" + Paths.sep + val parsed = "parsed" + val extended = "extended" + val linked = "linked" + val scheduled = "scheduled" + val bad = "bad" + + import scala.io.Source + + def bad(file : File) : Unit = { + val f = new File(dir + file.getName + "." + bad) + // Make sure file exists + if(!f.exists) f.createNewFile + } + + def save(p : Paper, postfix : String) : Unit = { + val orig = new File(p.meta("file")) + val f = new File(dir + orig.getName + "." + postfix) + // Make sure file exists + if(!f.exists) f.createNewFile + val w = new PrintWriter(f) + + // Print paper + w.println("[[[ ID ]]]" + "\n" + p.id) + w.println("[[[ INDEX ]]]" + "\n" + p.index) + w.println("[[[ TITLE ]]]" + "\n" + p.title) + w.println("[[[ AUTHORS ]]]" + "\n" + p.authors.mkString("\n")) + w.println("[[[ ABSTR ]]]" + "\n" + p.abstr.text) + w.println("[[[ BODY ]]]" + "\n" + p.body.text) + w.println("[[[ REFS ]]]" + "\n" + p.refs.mkString("\n----\n")) + w.println("[[[ META ]]]" + "\n" + p.meta.mkString("\n")) + w.println("[[[ LINKS ]]]" + "\n" + p.links.mkString("\n----\n")) + w.close + } + + def load(file : File) : Paper = { + + // Printout + println("Loading file " + file.getName + " from cache") + + // Get file and read in lines + val lines : Iterator[String] = Source.fromFile(file).getLines + + // Variables + var vars : Map[String, List[String]] = Map.empty.withDefaultValue(Nil) + var current = "unknown"; + + // Order the information + for (l <- lines) l match { + case "[[[ ID ]]]" => current = "id" + case "[[[ INDEX ]]]" => current = "index" + case "[[[ TITLE ]]]" => current = "title" + case "[[[ AUTHORS ]]]" => current = "authors" + case "[[[ ABSTR ]]]" => current = "abstr" + case "[[[ BODY ]]]" => current = "body" + case "[[[ REFS ]]]" => current = "refs" + case "[[[ META ]]]" => current = "meta" + case "[[[ LINKS ]]]" => current = "links" + case line => vars = vars + (current -> (vars(current) ::: List(line))) + } + + return Paper(vars("id").head.toInt, + vars("index").head.toInt, + Title(vars("title").head), + stringToAuthors(vars("authors")), + Abstract(vars("abstr").mkString("\n")), + Body(vars("body").mkString("\n")), + stringToRefs(vars("refs")), + setMeta(vars("meta")), + stringToLinks(vars("links"))) + + } + + def setMeta(s : List[String]) : Map[String, String] = { + var m : Map[String, String] = Map.empty + // Looping through all the maps + for (e <- s) { + m = m + Pair((e.split(" -> "))(0), (e.split(" -> "))(1)) + } + return m + } + + def stringToLinks(s : List[String]) : List[Link] = { + return s.filter(l => l.split(" ").length == 2).map(l => Link(l.split(" ").head.toInt, l.split(" ").last.toInt)) + } + + def stringToAuthors(s : List[String]) : List[Author] = { + return s.map(l => Author(l)) + } + + def stringToRefs(s : List[String]) : List[Reference] = { + // Variables + var map : Map[String, List[String]] = Map.empty.withDefaultValue(Nil) + var index : Int = 0 + var current = "authors" + index + + // Make sure we have any references + if (s.head == "") return Nil + + // Order the information + for (l <- s) l match { + case "--" => current = "title" + index + case "----" => index += 1; current = "authors" + index + case line => map = map + (current -> (line :: map(current))) + } + + // Now gather it + val refs = for (i <- 0 to index) yield Reference(stringToAuthors(map("authors" + i)), Title(map("title" + i).head)) + return refs.toList + } +} + +trait LoadPaper { + + def loadAndParse(name : String, postfix : List[String], parser : Parsers, loader : FileLoader) : List[Paper] = { + println("BEGIN OF PARSING") + + // Get file handle of original file or directory + val orig = new File(name) + + // Check that directory or file exists + if (!orig.exists) println("Something is wrong with the file or directory in the argument : " + name) + + // If exists, set name and file + // In case it's a directory, let the file array contain all the files of the directory (regex utilization) + val files : List[File] = if(orig.isDirectory) SystemHelper.getFilesFromDirectory(orig) else List(orig) + val fnames : List[String] = if(orig.isDirectory) files.map(f => name ++ f.getName) else List(name) + + + // If postfix exists, try loading from cache + val somePapers : List[Option[Paper]] = if (postfix != Nil) files.map(f => loadFromCache(f, postfix)) else Nil + + // All papers that weren't loaded by cache are loaded by file + val finalPapers = somePapers.zip(files).map(p => if (p._1 == None) loadFromFile(p._2, parser, loader) else p._1) + + // Filter papers for None's and set index + val papers : List[Paper] = finalPapers.filter(p => p != None).zipWithIndex.map({case Pair(p,i) => p.get.setIndex(i) }).toList + + println("END OF PARSING") + + return papers + } + + + // Loads a paper from a text file and parses it. It has been modified in order to make loading and parsing flexible + def loadFromFile(file : File, p : Parsers, loader: FileLoader) : Option[Paper] = { + + // Check if file is bad or contains non numerical values (in the name) + if (checkIfBad(file) || """[^0-9]+""".r.findFirstIn(SystemHelper.name(file.getName())).isDefined) return None + + val result = loader.loadFromFile(file, p) + + // If paper doesn't exist and didn't parse, let's not parse it again + if(result == None) return isBadFile(file) + else Cache.save(result.get.clean, Cache.parsed) // Save and return + + return result + } + + + def isBadFile(file: File): Option[Paper] = { + println("Couldn't parse " + file.getName()) + Cache.bad(file) + return None + } + + def checkIfBad(file : File) : Boolean = { + + // Get file + val cached = new File(Cache.dir + file.getName + "." + Cache.bad) + + // Check that file exists + return (cached.exists) + } + + // Loads a paper from cache + def loadFromCache(file : File, postfix : List[String]) : Option[Paper] = { + // Helper function to load file + def getCache(postfix : String) : Option[Paper] = { + // Get file + val cached = new File(Cache.dir + file.getName + "." + postfix) + + // Check that file exists + if (!cached.exists) return None + + // Else, load away + return Some(Cache.load(cached)) + } + + postfix match { + // No postfix? - Return None + case Nil => None + // a postfix, well, let's try it + case p::ps => { + val ret = getCache(p) + // If we didn't find anything in cache, recurse + if (ret == None) loadFromCache(file, ps) + // Else return result + else return ret + } + } + } +} + + +object CacheLoader extends LoadPaper{ + def load(paperPos:String, postfix : String): List[Paper] = { + // Get file handle of original file or directory + val orig = new File(paperPos) + + // Check that directory or file exists + if (!orig.exists) sys.error("Problem with file path") + + val files : List[File] = if(orig.isDirectory()) orig.listFiles.toList else List(orig) + + // If postfix exists, try loading from cache + val papers : List[Option[Paper]] = files.map(f => loadFromCache(f, List(postfix))) + + return papers.filter((p:Option[Paper]) => p != None).map((p:Option[Paper]) => p.get) + } + } \ No newline at end of file diff --git a/app/paper/ParsePaper.scala b/app/paper/ParsePaper.scala new file mode 100644 index 0000000..536f361 --- /dev/null +++ b/app/paper/ParsePaper.scala @@ -0,0 +1,273 @@ +package paper + +import scala.collection.immutable.Stream +import scala.collection.immutable.StringOps +import scala.util.parsing.input._ +import scala.io.Source +import java.io.File + +abstract class Parsers { + def parse(file : Source) : Option[Paper] +} + +trait ParsePaper { + + def getText(in: Source): Stream[Char] = in.hasNext match { + case false => in.close(); Stream.Empty + case true => in.next #:: getText(in) + } + + + object Isit extends Parsers { + + def paper : Parser[Paper] = ( + //title ~ authors ~ dropLinesUntil("R EFERENCES") ~ references + dropLinesUntil("R EFERENCES") ~ references + ^^ { case b~r => Paper(0,0,Title(""),Nil,Abstract("Not saved"),Body("Not saved"),r,Map.empty,List()) } + | dropLinesUntil("References") ~ references + ^^ { case b~r => Paper(0,0,Title(""),Nil,Abstract("Not saved"),Body("Not saved"),r,Map.empty,List()) }) + + + def title : Parser[Title] = ( + line && ("Title:" ~> rest) + ^^ trim ^^ (s => Title(s.init.mkString))) + + def authors : Parser[List[Author]] = ( + line && "Author: " ~> split(", ") + ^^ (as => { + if (as.length == 0) Nil + else { + var names = as.init.map(a => a.mkString) ::: List(as.last.mkString.init) + names.map(a => Author(formatAuthor(a.mkString))) + } + })) + + def abstr : Parser[Abstract] = ( + dropLinesUntil("Abstract") ~> takeLinesUntil("I. ") + ^^ (t => Abstract(t.mkString))) + + def body : Parser[Body] = ( + takeLinesUntil("R EFERENCES") + ^^ (t => Body(t.mkString))) + + def refBracket : Parser[Input] = ( + "[" ~ rep(number) ~ "] " ^^^ Stream.Empty) + + def refLine : Parser[Input] = ( + takeLinesUntil("\n" | refBracket)) + + def refAuthors : Parser[List[Author]] = ( + until(", “") && split(", and " | " and " | ", ") + ^^ { x => x.init.map { a => Author(a.mkString) } } ) + + def refTitle : Parser[Title] = ( + until(",\"" | "\"," | "\"." | ".") ^^ (s => Title(s.mkString)) // Character modification. Possible errors in the future !!! + | success(Title(""))) + + def reference : Parser[Reference] = ( + refLine && (refAuthors ~ refTitle) + ^^ { case a~t => Reference(a, t) }) + + def references : Parser[List[Reference]] = ( + dropLinesUntil(refBracket) ~> rep(reference) ^^ cleanRefs) + + + // The function for actually parsing a paper + def parse(file : Source) : Option[Paper] = { + paper(getText(file)) match { + case Failure(msg, rest) => println("Failure: " + msg); None + case Success(result, rest) => Some(result.setMeta("parsed" -> "yes")) + } + } + } + + + def cleanRefs(refs : List[Reference]) : List[Reference] = { + val ret = for (r <- refs if r.title.t.stripMargin != "" && r.authors.length > 0) yield { + // Clean authors + var authors = for (a <- r.authors if a.name.stripMargin.length > 2) yield Author(a.name.stripMargin) + Reference(authors, r.title) + } + return ret + } + + def formatAuthor(name : String) : String = { + var result = "" + var names = name.split(" ").filter(n => n.length > 0) + if (names.length > 0) { + result = names.init.filter(n => n.length > 0).map(n => n.head).mkString("",". ",". ") + names.last + } + return result + } + + + + type Input = Stream[Char] + sealed abstract class Result[+T] + case class ~ [+T, +U](r1 : T, r2 : U) + case class Success[T](result: T, in : Input) extends Result[T] + case class Failure(msg : String, in : Input) extends Result[Nothing] + + val lineSep : List[Char] = List('\n','\r') + val tokenSep : List[Char] = List(' ',',','.',':','[',']','-') ::: lineSep + + abstract class Parser[+T] extends (Input => Result[T]) { + p => + + def ~ [U](q: => Parser[U]) = new Parser[T~U] { + def apply(in: Input) = p(in) match { + case Success(x, in1) => q(in1) match { + case Success(y, in2) => Success(new ~(x, y), in2) + case Failure(msg, in) => Failure(msg, in) + } + case Failure(msg, in) => Failure(msg, in) + } + } + + def | [U >: T](q: => Parser[U]) = new Parser[U] { + def apply(in: Input) = p(in) match { + case s @ Success(x, rest) => s + case Failure(_,_) => q(in) + } + } + + def ^ [U](f: (T, Input) => U, g: (T, Input) => Input) : Parser[U] = new Parser[U] { + def apply(in: Input) = p(in) match { + case Success(x, rest) => Success(f(x, rest), g(x, rest)) + case Failure(msg, in) => Failure(msg, in) + } + } + + def ^^ [U](f: T => U) : Parser[U] = p ^ ({ case (x, _) => f(x) }, { case (_,r) => r }) + def ^^^ [U](v: U) = p ^^ { case _ => v } + def ~> [U](q: => Parser[U]) = (p ~ q) ^^ { case a~b => b } + def <~ [U](q: => Parser[U]) = (p ~ q) ^^ { case a~b => a } + + def &&[U](q: => Parser[U]) = new Parser[U] { + def apply(in: Input) = p(in) match { + case f @ Failure(msg, in) => f + case Success(x1, rest) => { + // Because I don't know the result of parser q, I'm backtracing to figure out what was matched + var matched = in.zipWithIndex.takeWhile{case (x,i) => !in.drop(i).equals(rest)}.unzip._1 + q(matched) match { + case Success(x2, rest2) => Success(x2, rest) + case Failure(msg, rest2) => Failure(msg, rest) + } + } + } + } + } + + //def inLine[U](q : => Parser[U]) : Parser[U] = q <~ "\n" + + def line : Parser[Input] = next(lineSep) + def token : Parser[Input] = next(tokenSep) + + def number : Parser[Input] = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0" + + def trim(s : Input) : Input = s.dropWhile(c => c==' ' || c=='\t') + def line(p : Parser[Input]) : Parser[Input] = line && p && rest + + + // Splits input by letting the parser p be the delimiter + def split(p : Parser[Input]) : Parser[List[Input]] = rep(until(p)) + + def until[U](p : => Parser[U]) : Parser[Input] = new Parser[Input] { + override def apply(in: Input) : Result[Input] = { + + def gather(s : Input, soFar : Input) : Result[Input] = p(s) match { + case Success(result, rest) => Success(soFar, rest) + case Failure(msg, Stream.Empty) => Success(soFar, Stream.Empty) + case Failure(_, _) => gather(s.drop(1), soFar ++ s.take(1)) + } + + if (in == Stream.Empty) return Failure("[Until] Reached end of input", in) + else return gather(in, Stream.Empty) + } + } + + // Much faster than the naive version, and also avoids a stackoverflow + def takeLinesUntil[U](p : => Parser[U]) : Parser[Input] = new Parser[Input] { + override def apply(in: Input) : Result[Input] = { + + def gather(s : Input, soFar : Input) : Result[Input] = { + p(s) match { + case Success(result, rest) => Success(soFar, rest) + case Failure(msg, Stream.Empty) => Success(soFar, Stream.Empty) + case Failure(_, _) => gather(s.dropWhile(c => c != '\n').drop(1), soFar ++ s.takeWhile(c => c != '\n').drop(1)) + } + } + + if (in == Stream.Empty) return Failure("[takeLinesUntil] Reached end of input", in) + else return gather(in, Stream.Empty) + } + } + + //def takeLinesUntil(p : Parser[Input]) = rep(line(p)) + def dropLinesUntil[U](p : Parser[U]) = takeLinesUntil(p) ~> success(Stream.Empty) + + + def not(s: String) : Parser[Input] = new Parser[Input] { + override def apply(in: Input) : Result[Input] = in.take(s.length).mkString == s match { + case true => Failure("Failed: " + s + " was matched", in) + case false => Success(Stream.Empty, in) + } + } + + def opt [T](q : => Parser[T]) : Parser[Option[T]] = ( + q ^^ { case a => Some(a) } + | success(None)) + + def rep [T](p : => Parser[T]) : Parser[List[T]] = ( + p ~ rep(p) ^^ { case a~b => a::b } + | success(List())) + + def repsep [T, U](p : => Parser[T], sep : => Parser[U]) : Parser[List[T]] = ( + p ~ rep(sep ~> p) ^^ { case a~b => a::b } + | success(List())) + + def success[T](v: T) : Parser[T] = new Parser[T] { + override def apply(in: Input) : Result[T] = Success(v,in) + } + + def rest : Parser[Input] = new Parser[Input] { + override def apply(in: Input) : Result[Input] = { + in.length match { + case 0 => Failure("[Rest] Reached end of input",in) + case n => Success(in, Stream.Empty) + } + } + } + + def next(sep : List[Char]) : Parser[Input] = new Parser[Input] { + def apply(in: Input) = in.span(c => !sep.contains(c)) match { + case (Stream.Empty, Stream.Empty) => Failure("[Next] Reached end of input", in) + case (head, rest) => Success(head.init, rest.drop(1)) + } + } + + implicit def predicate(p: String => Boolean) : Parser[Input] = new Parser[Input] { + def apply(in: Input) = { + p(in.mkString) match { + case true => Success(Stream.Empty, in) + case false => Failure("Couldn't match predicate on:\n" + in.mkString, Stream.Empty) + } + } + } + + implicit def str(t: String) : Parser[Input] = new Parser[Stream[Char]] { + def apply(in: Input) = in.take(t.length).mkString == t match { + case true => Success(in.take(t.length), in.drop(t.length)) + case _ => Failure("Couldn't match expected: '" + t + "' given " + in.mkString, in) + } + } + + implicit def resultToStream(r: Result[Input]) : Input = r match { + case Success(x, rest) => x + case Failure(_,_) => Stream.Empty + } + + // //implicit def Stream2Str(s : Stream[Char]) : String = s.mkString + +} + diff --git a/app/paper/RecognitionClasses.scala b/app/paper/RecognitionClasses.scala new file mode 100644 index 0000000..0a5f49b --- /dev/null +++ b/app/paper/RecognitionClasses.scala @@ -0,0 +1,124 @@ +package paper + +object ExtractionRegexes { + val and = """(and|&)""" + val quoteB = """(“|\")""" + val quoteE = """(”|\")""" + val tabulation = """ \t """ + val authorsSeparator = """( ?, and | ?, | and | ?, \t | \t | & )""" + val referencesName = """(REFERENCES|R EFERENCES|References|R eferences)""" + val titleTermination = """[\.\?]""" +} + +// This class is a the top of the hierarchy +abstract class ReferenceProcessor { + def extract(ref: String): (Option[Title], Option[List[Author]]) +} + +// This class tries to extract information using a list of existent defined formats +object ReferenceProcessorExecuter { + val recognitionClasses: List[ReferenceProcessor] = List[ReferenceProcessor](NumberedReferenceProcessor1, NumberedReferenceProcessor2, TextualReferenceProcessor1) + + def extract(ref: String): (Option[Title], Option[List[Author]]) = { + def extract0(refProcessors: List[ReferenceProcessor]): (Option[Title], Option[List[Author]]) = refProcessors match{ + case List() => (None, None) + case x::List() => x.extract(ref) + case x::xs => { + val input = extract0(xs) + val title = input._1 + val authors = input._2 + + if(title == None && authors == None) x.extract(ref) + else (title, authors) + } + } + + extract0(recognitionClasses.reverse) + } +} + + + +// This class can extract information out of a reference having the following format: [digit] authors "title" +object NumberedReferenceProcessor1 extends ReferenceProcessor { + def extract(ref: String): (Option[Title], Option[List[Author]]) = { + def extractTitle: Option[Title] = { + val t = (ExtractionRegexes.quoteB + """.+""" + ExtractionRegexes.quoteE).r.findFirstIn(ref) + if(!t.isDefined) return None + + // Dropping the " characters + val title = t.get.drop(1).dropRight(1) + val finalTitle = if(title.last.equals(',')) title.dropRight(1) else title + Some(new Title(finalTitle)) + } + + def extractAuthors: Option[List[Author]] = { + val t = ("""^\[\d+\].+""" + ExtractionRegexes.quoteB).r.findFirstIn(ref) + if(!t.isDefined) return None + + val totAuths = t.get + val auths = ("""^\[\d+\]""").r.replaceAllIn(totAuths.dropRight(1), "") + + val authorsStringList = ("""([A-Z]\.[ -])+.+?( """ + ExtractionRegexes.and + """|,)""").r.findAllIn(auths).toList + + Some(authorsStringList.map((s:String) => new Author(("""( """ + ExtractionRegexes.and + """)""").r.replaceAllIn(s, "").replace(",", "")))) + } + + if(("""^\[\d+\].+""" + ExtractionRegexes.quoteB + """.+""" + ExtractionRegexes.quoteE + """(.+)?$""").r.findFirstIn(ref).isDefined){ + (extractTitle, extractAuthors) + } else (None, None) + } +} + + +// This class can extract information out of a reference having the following format: [digit] authors. title +object NumberedReferenceProcessor2 extends ReferenceProcessor { + def extract(ref: String): (Option[Title], Option[List[Author]]) = { + def extract0(ref: String): (Option[Title], Option[List[Author]]) = { + val authRegex = ("""([A-Z]\.[ -])+.+?( """ + ExtractionRegexes.and + """|,|, """ + ExtractionRegexes.and + """|\.)""").r + + val ref2 = ("""^\[\d+\]( )""").r.replaceAllIn(ref, "") + val authorsStringList = authRegex.findAllIn(ref2).toList + + val auths = Some(authorsStringList.map((s:String) => new Author(("""( """ + ExtractionRegexes.and + """)""").r.replaceAllIn(s, "").replace(",", "").dropRight(1)))) + + val t = ("""^.+?""" + ExtractionRegexes.titleTermination + """""").r.findFirstIn(authRegex.replaceAllIn(ref2, "")) + if(!t.isDefined) return (None, None) + + // Dropping until a the capital character is founded + val title = Some(new Title(t.get.replace(".", "").dropWhile((c:Char) => """[^A-Z]""".r.findFirstIn(""+c).isDefined))) + + (title, auths) + } + + if(("""^\[\d+\].+$""").r.findFirstIn(ref).isDefined) extract0(ref) + else (None, None) + } +} + +// This class can extract information out of a reference having the following format: authors (digits) title +object TextualReferenceProcessor1 extends ReferenceProcessor { + def extract(ref: String): (Option[Title], Option[List[Author]]) = { + def extractTitle: Option[Title] = { + val t = ("""\)\..+?""" + ExtractionRegexes.titleTermination + """""").r.findFirstIn(ref) + if(!t.isDefined) return None + + Some(new Title(t.get.drop(3))) + } + + def extractAuthors: Option[List[Author]] = { + val t = """^.+?\(""".r.findFirstIn(ref) + if(!t.isDefined) return None + + // Dropping the " (" string + val auths = t.get.dropRight(2) + + val authorsStringList = (""".+?,( [A-Z]\.)+(, (""" + ExtractionRegexes.and + """ )?)?""").r.findAllIn(auths).toList + + Some(authorsStringList.map((s:String) => new Author(("""( """ + ExtractionRegexes.and + """)""").r.replaceAllIn(s, "").replace(",", "")))) + } + + if(("""^.+?\(\d+\)\..+?\..+?\.$""").r.findFirstIn(ref).isDefined) (extractTitle, extractAuthors) + else (None, None) + } +} diff --git a/app/paper/Terms.scala b/app/paper/Terms.scala new file mode 100644 index 0000000..7329835 --- /dev/null +++ b/app/paper/Terms.scala @@ -0,0 +1,106 @@ +package paper + +/** Abstract Syntax Trees for terms. */ +sealed abstract class Term + + +// Try to keep this immutable +case class Paper(val id : Int, + val index : Int, + val title: Title, + val authors: List[Author], + val abstr: Abstract, + val body: Body, + val refs: List[Reference], + val meta: Map[String, String], + val links : List[Link]) extends Term { + + // Add a field that contains options, such as parsed and linked + + val parsed : Boolean = false + val linked : Boolean = false + + override def toString: String = title + "\n" + authors.mkString(", ") + "\n" + abstr + "\n" + body + "\n" + refs.mkString("\n") + + def getDistinctNames : List[String] = { + val as = authors ::: refs.flatMap(r => r.authors) + val names = as.map(a => a.toString) + return names.distinct + } + + def getTitle : Title = title + + def getAuthors : List[Author] = authors + def getAbstract : Abstract = abstr + def getBody : Body = body + def getReferences : List[Reference] = refs + + def clean : Paper = + return Paper(id, index, title, authors.filter(a => a.name.length > 4), abstr, body, refs.map(r => r.clean), meta, links) + + def setMeta(p : (String, String)) : Paper = + return Paper(id, index, title, authors, abstr, body, refs, meta + p, links) + + def setTitle(t : Title) : Paper = + return Paper(id, index, t, authors, abstr, body, refs, meta, links) + + def setAuthors(as : List[Author]) : Paper = + return Paper(id, index, title, as, abstr, body, refs, meta, links) + + def hasMeta(l : String) : Boolean = (meta.get(l) != None) + + def setId(newId : Int) : Paper = + return Paper(newId, index, title, authors, abstr, body, refs, meta, links) + + def setIndex(newIndex : Int) : Paper = + return Paper(id, newIndex, title, authors, abstr, body, refs, meta, links) + + def setLinks(newLinks : List[Link]) : Paper = + return Paper(id, index, title, authors, abstr, body, refs, meta, newLinks) + + def setAbstract(newAbstract : Abstract) : Paper = + return Paper(id, index, title, authors, newAbstract, body, refs, meta, links) + + def setBody(newBody : Body) : Paper = + return Paper(id, index, title, authors, abstr, newBody, refs, meta, links) + + def setReferences(newRefs : List[Reference]) : Paper = + return Paper(id, index, title, authors, abstr, body, newRefs, meta, links) +} + +case class Title(t: String) extends Term { + override def toString: String = t + + def getText: String = t +} + +case class Author(name: String) extends Term { + override def toString: String = name + + def getName: String = name +} + +case class Abstract(text: String) extends Term { + override def toString : String = "Abstract:\t" + text.take(40) + " ... " + + def getText: String = text +} + +case class Body(text: String) extends Term { + override def toString: String = "Body:\t\t" + text.take(100) ++ " ... \n" + + def getText: String = text +} + +case class Reference(authors: List[Author], title: Title) extends Term { + def clean : Reference = return Reference(authors.filter(a => a.name.stripMargin.length > 0), title) + override def toString : String = authors.mkString("\n") + "\n--\n" + title + + def getAuthors: List[Author] = authors + def getTitle: Title = title +} + +case class Link(index : Int, weight : Int) extends Term { + override def toString : String = index + " " + weight +} + diff --git a/app/paper/XMLObjects.scala b/app/paper/XMLObjects.scala new file mode 100644 index 0000000..712b412 --- /dev/null +++ b/app/paper/XMLObjects.scala @@ -0,0 +1,108 @@ +package paper + +// This class represents a position (can be a paragraph or even a page) +class XMLPosition(x: Int, y: Int, width: Int, height: Int) { + def getX: Int = x + def getY: Int = y + def getWidth: Int = width + def getHeight: Int = height + + override def toString(): String = "[x= " + x + ", y= " + y + ", width= " + width + ", height= " + height + "]" +} + +// This class defines a particular font (with the totality of xml ids defining it) +class XMLFont(IDs:String, size: String, family: String, color: String) { + def getID: String = IDs + def getSize: String = size + def getFamily: String = family + def getColor: String = color + + // This method adds a new xml id to the definition of the font + def addID(id: String): XMLFont = new XMLFont(IDs + "-" + id, size, family, color) + + // This method checks if a particular xml id is defining that font. Use "xmlFont.checkID(myid)" instead of "xmlFont.getID == myid" + def checkID(id: String): Boolean = ("(^(" + IDs.replace("-", "|") + ")$)|(^(" + IDs.replace("-", "|") + ")-)|(-(" + IDs.replace("-", "|") + ")$)|(-(" + IDs.replace("-", "|") + ")-)").r.findFirstIn(id).isDefined + + // This method checks if two xml font are basically the same + def compareXMLFont(font: XMLFont): Boolean = (size == font.getSize && family == font.getFamily && color == font.getColor) +} + +// This class contains the fonts of the document +class XMLFontsContainer(fonts: List[XMLFont]){ + def getXMLFont(id: String): Option[XMLFont] = fonts.find(f => f.checkID(id)) + def filter (f:XMLFont => Boolean) = fonts.filter(f) +} + + +object XMLParagraphOptions { + val CENTERED = "CTR" + val PAGE_CENTERED = "PCT" + val JUSTIFY = "JFY" + val COLUMN_LEFT = "CLL" + val COLUMN_RIGHT = "CLR" + val NO_COLUMN = "NCL" + val ENUMERATION = "ENM" + val NONE = "NON" +} + +class XMLParagraphOptionsContainer(value: String) { + def getValue: String = value + def addOption(option: String): XMLParagraphOptionsContainer = if(!hasOption(option)) new XMLParagraphOptionsContainer(value + "|" + option) else this + def hasOption(option: String): Boolean = ("^(" + value + ")$").r.findFirstIn(option).isDefined + def removeOption(option: String): XMLParagraphOptionsContainer = new XMLParagraphOptionsContainer(value.replace("|" + option, "")) +} + +class XMLLine(fontID: String, position: XMLPosition, text: String) { + def getFontID: String = fontID + def getPosition: XMLPosition = position + def getText: String = text + + def setFontID(newFont: String) = new XMLLine(newFont, position, text) + def addText(newLine: XMLLine): XMLLine = new XMLLine(fontID, new XMLPosition(position.getX, position.getY, (newLine.getPosition.getX + newLine.getPosition.getWidth) - position.getX, position.getHeight), text + newLine.getText) + def setText(newText: String): XMLLine = new XMLLine(fontID, position, newText) +} + +// This class represents a paragraph contained in a page +class XMLParagraph(fontID: String, position: XMLPosition, options: XMLParagraphOptionsContainer, lines: List[XMLLine], linesSeparator: String, text: String, enumFormat: String) { + def getFontID: String = fontID + def getPosition: XMLPosition = position + def getText: String = text + def getLines: List[XMLLine] = lines + def getEnumerationFormat: String = enumFormat + + def addOption(option: String): XMLParagraph = new XMLParagraph(fontID, position, options.addOption(option), lines, linesSeparator, text, enumFormat) + def hasOption(option: String): Boolean = options.hasOption(option) + def removeOption(option: String): XMLParagraph = new XMLParagraph(fontID, position, options.removeOption(option), lines, linesSeparator, text, enumFormat) + def getOptionsValue: String = options.getValue + + // This method adds a new XMLLine to the paragraph. However, the added line will be the first one on the list, so pay attention! + // The text and position arguments will be correctly updated + def addLine(line: XMLLine): XMLParagraph = new XMLParagraph(fontID, new XMLPosition(Math.min(position.getX, line.getPosition.getX), position.getY, Math.max(position.getX + position.getWidth, line.getPosition.getX + line.getPosition.getWidth) - Math.min(position.getX, line.getPosition.getX), (line.getPosition.getY + line.getPosition.getHeight) - position.getY), options, line :: lines, linesSeparator, text + linesSeparator + line.getText, enumFormat) + def addParagraph(newParagraph: XMLParagraph): XMLParagraph = new XMLParagraph(fontID, new XMLPosition(Math.min(position.getX, newParagraph.getPosition.getX), position.getY, Math.max(position.getX + position.getWidth, newParagraph.getPosition.getX + newParagraph.getPosition.getWidth) - Math.min(position.getX, newParagraph.getPosition.getX), (newParagraph.getPosition.getY + newParagraph.getPosition.getHeight) - position.getY), options, newParagraph.getLines ::: lines, linesSeparator, text + linesSeparator + newParagraph.getText, enumFormat) + def reverseLines: XMLParagraph = new XMLParagraph(fontID, position, options, lines.reverse, linesSeparator, text, enumFormat) +} + +// This class is the representation of a page +class XMLPage(number: Int, position: XMLPosition, paragraphs: List[XMLParagraph]) { + def getNumber: Int = number + def getPosition: XMLPosition = position + def getParagraphs: List[XMLParagraph] = paragraphs +} + +// This class defines the entire xml file structure +class XMLDocument(fontsContainer: XMLFontsContainer, pages: List[XMLPage]) { + private val paragraphs = { + def get(pageList: List[XMLPage], accu: List[XMLParagraph]):List[XMLParagraph] = pageList match { + case List() => accu + case x::xs => get(xs, accu ::: x.getParagraphs) + } + + get(pages, List()) + } + + def getFontsContainer: XMLFontsContainer = fontsContainer + def getPage(pageNumber: Int): XMLPage = (pages.filter(p => p.getNumber == pageNumber)).head + def getParagraphs: List[XMLParagraph] = paragraphs +} + + diff --git a/app/paper/XMLObjectsManager.scala b/app/paper/XMLObjectsManager.scala new file mode 100644 index 0000000..3e7a51d --- /dev/null +++ b/app/paper/XMLObjectsManager.scala @@ -0,0 +1,115 @@ +package paper +import scala.xml.XML +import scala.xml.Elem +import scala.xml.NodeSeq + + +object XMLObjectsManager { + + def getCleanXMLParagraph(lineSeparator: String): XMLParagraph = new XMLParagraph("", new XMLPosition(0, 0, 0, 0), new XMLParagraphOptionsContainer(XMLParagraphOptions.NONE), List(), lineSeparator, "", "") + + // Since the xml file sometimes creates different fonts with the same features (size, family, etc), it + // is important to create a structure that takes into account this detail and hides it. + // The XMLFont class performs this job. XMLFontsContainer just contains the list of XMLFont objects + private def getFontsContainer(xml: Elem): Option[XMLFontsContainer] = { + val pages = (xml \\ "page") + + + // This method updates the previous XMLFont list with the new fonts defined in the page. + def getXMLFontListFromPage(previousList: List[XMLFont], pageNumber: String): List[XMLFont] = { + // Recursive method that runs through the page's fonts list and updates the given XMLFont list + def constructFontLists(fonts: NodeSeq, accu: List[XMLFont]): List[XMLFont] = { + + // This method runs through the given XMLFont list and checks if the new XMLFont defined object is already in the list + def checkIfExist(xmlFont: XMLFont, list: List[XMLFont], accu: List[XMLFont]): List[XMLFont] = list match{ + case List() => (xmlFont :: accu).reverse // Putting the new XMLFont at the end of the list + case x::xs => if(x.compareXMLFont(xmlFont)) (x.addID(xmlFont.getID) :: accu).reverse ::: xs // Updating the given XMLFont list + else checkIfExist(xmlFont, xs, x :: accu) + } + + fonts.isEmpty match { + case true => accu + case false => { + // Creating then new XMLFont object according to the font parameters + val xmlFont = new XMLFont((fonts.head \ "@id").text, (fonts.head \ "@size").text, (fonts.head \ "@family").text, (fonts.head \ "@color").text) + constructFontLists(fonts.tail, checkIfExist(xmlFont, accu, List())) + } + } + + } + + // Getting the page + val page = pages filter((n) => (n \ "@number").text.equals(pageNumber)) + + if(page.length != 1) previousList + else { + val fonts = page.head \\ "fontspec" + + // Updating the XMLFont list + constructFontLists(fonts, previousList) + } + } + + // Method for running through the pages list + def constructUntilPage(pagesNumber: Int, accu: List[XMLFont], currentPage: Int): List[XMLFont] = { + if(currentPage > pagesNumber) accu + else constructUntilPage(pagesNumber, getXMLFontListFromPage(accu, currentPage.toString()), currentPage + 1) + } + + // Getting the xml fonts list + val xmlFonts = constructUntilPage(pages.length, List(), 1) + + // Creating the container + if(xmlFonts.length >= 1) Some(new XMLFontsContainer(xmlFonts)) + else None + } + + // This method creates the pages of the document. The final list is reversed + private def constructXMLPages(pages: NodeSeq, fontsContainer: Option[XMLFontsContainer], lineSeparator: String): Option[List[XMLPage]] = { + // This method constructs the xml page + def constructXMLPage(page: xml.Node): Option[XMLPage] = { + try { + // First we get the global page parameters + val number = (page \ "@number").text.toInt + val x = (page \ "@top").text.toInt + val y = (page \ "@left").text.toInt + val width = (page \ "@width").text.toInt + val height = (page \ "@height").text.toInt + val position = new XMLPosition(x, y, width, height) + // Construction of the paragraphs + val paragraphs = XMLParagraphsConstructor.constructXMLParagraphs(page, position, fontsContainer.get, lineSeparator) + + if (paragraphs != None) Some(new XMLPage(number, position, paragraphs.get)) + else None + }catch { + case _ => None + } + + } + + // Recursive method in order to run through the pages list + def constructXMLPages0(pages: NodeSeq, accu: Option[List[XMLPage]]): Option[List[XMLPage]] = { + if(pages.isEmpty) accu + else { + val page = constructXMLPage(pages.head) + + if(page == None) None + else constructXMLPages0(pages.tail, Some(page.get :: accu.get)) + } + } + + if(fontsContainer != None) constructXMLPages0(pages, Some(List())) + else None + } + + // This method constructs the xml document of the file + def constructXMLDocument(xml:Elem, lineSeparator:String): Option[XMLDocument] = { + // getting fontsContainer and xml pages + val fontsContainer = getFontsContainer(xml) + val xmlPages = constructXMLPages(xml \\ "page", fontsContainer, lineSeparator) + + // If everything is fine, then create the document + if(xmlPages != None) Some(new XMLDocument(fontsContainer.get, xmlPages.get.reverse)) + else None + } +} \ No newline at end of file diff --git a/app/paper/XMLParagraphsConstructor.scala b/app/paper/XMLParagraphsConstructor.scala new file mode 100644 index 0000000..5b11604 --- /dev/null +++ b/app/paper/XMLParagraphsConstructor.scala @@ -0,0 +1,180 @@ +package paper +import scala.xml.NodeSeq + +object XMLParagraphsConstructor { + private class ParagraphDelimiter(value: Int, tolerance: Int) { + // !!! Equal to = (assignment, not comparing) + def == (cValue: Int): ParagraphDelimiter = new ParagraphDelimiter(cValue, tolerance) + + def >= (cValue: Int): Boolean = (cValue <= value + tolerance) + def <= (cValue: Int): Boolean = (cValue >= value - tolerance) + def > (cValue: Int): Boolean = (cValue < value + tolerance) + def < (cValue: Int): Boolean = (cValue > value - tolerance) + + // Comparing + def === (cValue: Int): Boolean = this >= cValue && this <= cValue + def != (cValue: Int): Boolean = !(this === cValue) + } + + + def constructXMLParagraphs(page: xml.Node, pagePosition: XMLPosition, fontsContainer: XMLFontsContainer, lineSeparator: String): Option[List[XMLParagraph]] = { + val lines = page \\ "text" + val pageCenter = new ParagraphDelimiter(pagePosition.getWidth / 2, 3) + + def createXMLLine(line: xml.Node) = new XMLLine((line \ "@font").text, new XMLPosition((line \ "@left").text.toInt, (line \ "@top").text.toInt, (line \ "@width").text.toInt, (line \ "@height").text.toInt), line.text) + + // This method incorporates the lines and finds out the real line font (see documentation) + def incorporate(nextLines: NodeSeq, currentLine: XMLLine, fontLengthMap: Map[String, Int]): (NodeSeq, XMLLine) = nextLines.isEmpty match{ + case true => { + // Determining of the real line font + val maxFontLength = fontLengthMap.toList.map((f:(String, Int)) => f._2).max + (nextLines, currentLine.setFontID(fontLengthMap.filter((p:(String, Int)) => p._2 == maxFontLength).head._1)) + } + case false => + val nextLine = createXMLLine(nextLines.head) + val currentLineYRange = new ParagraphDelimiter(currentLine.getPosition.getY, currentLine.getPosition.getHeight - 3) + val tabulation = if(nextLine.getPosition.getX - (currentLine.getPosition.getX + currentLine.getPosition.getWidth) >= 2*currentLine.getPosition.getHeight) " \t " else " " + + + // If the top of the next line is in the range, then it must be added to the current line + if(currentLineYRange === nextLine.getPosition.getY) { + // Counting of the characters having a particular font + val nextFontLength = fontLengthMap.get(nextLine.getFontID) + // If a font is always present in the map, then add to the current value the number of characters, otherwise create a new font key + val newMap = if(nextFontLength == None) fontLengthMap + ((nextLine.getFontID, (tabulation + nextLine.getText).length)) else fontLengthMap - (nextLine.getFontID) + ((nextLine.getFontID, (tabulation + nextLine.getText).length + nextFontLength.get)) + + incorporate(nextLines.tail, currentLine.addText(nextLine.setText(tabulation + nextLine.getText)), newMap) + } + else { + // Determining of the real line font + val maxFontLength = fontLengthMap.toList.map((f:(String, Int)) => f._2).max + (nextLines, currentLine.setFontID(fontLengthMap.filter((p:(String, Int)) => p._2 == maxFontLength).head._1)) + } + } + + // This is the main step of the process (see documentation). The output of the method is (newParagraph, line included?, paragraph will continue?) + def linkLine(line: XMLLine, paragraph: XMLParagraph): (XMLParagraph, Boolean, Boolean) = { + def constructEnumFormat(line: String): String = { + val enumRegex = """^([^0-9]*)?[0-9]+([^0-9]+?) """ + + if(line.length < 5) return "" + else { + val result = enumRegex.r.findFirstIn(line.take(5)) + if(result.isDefined) return """[0-9]""".r.replaceAllIn(result.get, "{d}").dropRight(1) + else return "" + } + } + + val lineCenter = ((2 * line.getPosition.getX) + line.getPosition.getWidth) / 2 + val enumFormat = constructEnumFormat(line.getText) + + // First paragraph's line (rule 1) + if(paragraph.getLines.length == 0) { + val optionContainer = if(pageCenter === lineCenter) (new XMLParagraphOptionsContainer(XMLParagraphOptions.NONE)).addOption(XMLParagraphOptions.PAGE_CENTERED) else new XMLParagraphOptionsContainer(XMLParagraphOptions.NONE) + val enumeratedOptionContainer = if(enumFormat != "") optionContainer.addOption(XMLParagraphOptions.ENUMERATION) else optionContainer + + return (new XMLParagraph(line.getFontID, line.getPosition, enumeratedOptionContainer, List(line), lineSeparator, line.getText, enumFormat), true, true) + } + + // Calculate some important parameters + val previousLineCenter = new ParagraphDelimiter(((2 * paragraph.getLines.head.getPosition.getX) + paragraph.getLines.head.getPosition.getWidth) / 2, 3) + val previousLineText = paragraph.getLines.head.getText + val previousLineTop = paragraph.getLines.head.getPosition.getY + val previousLineHeight = paragraph.getLines.head.getPosition.getHeight + val previousLineBegin = new ParagraphDelimiter(paragraph.getLines.head.getPosition.getX, 3) + val previousLineEnd = new ParagraphDelimiter(paragraph.getLines.head.getPosition.getX + paragraph.getLines.head.getPosition.getWidth, 3) + val lineBegin = line.getPosition.getX + val lineEnd = line.getPosition.getX + line.getPosition.getWidth + val lineTop = line.getPosition.getY + val lineHeight = line.getPosition.getHeight + val previousLineCapitalVersurNotDifference = """[A-Z]""".r.findAllIn(previousLineText).length - """[a-z]""".r.findAllIn(previousLineText).length + val lineCapitalVersurNotDifference = """[A-Z]""".r.findAllIn(line.getText).length - """[a-z]""".r.findAllIn(line.getText).length + + // Rule 2 + if(lineTop - previousLineTop > 2*lineHeight || !fontsContainer.getXMLFont(paragraph.getFontID).get.checkID(line.getFontID)) return (paragraph, false, false) + // Rule 3: The current line is not a title but previous is (contains only capital letters), even if the have the same font + if(lineCapitalVersurNotDifference <= 0 && previousLineCapitalVersurNotDifference > 0) return (paragraph, false, false) + // If both lines have the same enumeration format (which must be defined), then the current line is a new enumeration, hence it belongs to a new paragraph + if(paragraph.hasOption(XMLParagraphOptions.ENUMERATION) && enumFormat == paragraph.getEnumerationFormat) return (paragraph, false, false) + + + // This is the second paragraph's line + if(paragraph.getLines.length == 1) { + // Rule 4 + if(previousLineBegin === lineBegin && previousLineEnd === lineEnd && previousLineCenter === lineCenter) return (paragraph.addLine(line).addOption(XMLParagraphOptions.CENTERED).addOption(XMLParagraphOptions.JUSTIFY), true, true) + // Rule 5 + else if(previousLineBegin != lineBegin && previousLineEnd != lineEnd && previousLineCenter === lineCenter) return (paragraph.addLine(line).addOption(XMLParagraphOptions.CENTERED), true, true) + // Rule 6 + else if(previousLineEnd >= lineEnd) return (paragraph.addLine(line).addOption(XMLParagraphOptions.JUSTIFY), true, true) + } + + // Normal line (more than the second) + if(paragraph.getLines.length > 1) { + if(paragraph.hasOption(XMLParagraphOptions.CENTERED) && !paragraph.hasOption(XMLParagraphOptions.JUSTIFY)) { + // Rule 7.a + if(previousLineCenter === lineCenter) return (paragraph.addLine(line), true, true) + } + else if(!paragraph.hasOption(XMLParagraphOptions.CENTERED) && paragraph.hasOption(XMLParagraphOptions.JUSTIFY)) { + // Rule 8.a + if(previousLineBegin === lineBegin && previousLineEnd === lineEnd) return (paragraph.addLine(line), true, true) + // Rule 8.b + else if(previousLineBegin === lineBegin && previousLineEnd > lineEnd) return (paragraph.addLine(line), true, false) + } + else if(paragraph.hasOption(XMLParagraphOptions.CENTERED) && paragraph.hasOption(XMLParagraphOptions.JUSTIFY)) { + // Rule 9.a + if(previousLineBegin === lineBegin && previousLineEnd === lineEnd) return (paragraph.addLine(line), true, true) + // Rule 9.b + else if(previousLineBegin != lineBegin && previousLineEnd != lineEnd && previousLineCenter === lineCenter) return (paragraph.addLine(line).removeOption(XMLParagraphOptions.JUSTIFY), true, true) + // Rule 9.c + else if(previousLineBegin === lineBegin && previousLineEnd > lineEnd) return (paragraph.addLine(line).removeOption(XMLParagraphOptions.CENTERED), true, false) + } + } + + // For all other cases + (paragraph, false, false) + } + + + // This method applies the layout rules. + def setLayout(paragraph: XMLParagraph): XMLParagraph = { + if(pageCenter > paragraph.getPosition.getX + paragraph.getPosition.getWidth) paragraph.addOption(XMLParagraphOptions.COLUMN_LEFT) + else if(pageCenter < paragraph.getPosition.getX) paragraph.addOption(XMLParagraphOptions.COLUMN_RIGHT) + else paragraph.addOption(XMLParagraphOptions.NO_COLUMN) + } + + def constructNewParagraph(lines: NodeSeq, currentParagraph: XMLParagraph): (NodeSeq, XMLParagraph) = lines.isEmpty match{ + case true => (lines, currentParagraph) + case false => + val tempLine = createXMLLine(lines.head) + // Incorporation + val incorporation = incorporate(lines.tail, tempLine, Map((tempLine.getFontID, tempLine.getText.length))) + + val remainingLines = incorporation._1 + // Linkage + val linkage = linkLine(incorporation._2, currentParagraph) + + // If the line was added + val finalRemainingLines = if(linkage._2 == true) remainingLines else lines + + // If the paragraph continues + if(linkage._3 == true) constructNewParagraph(finalRemainingLines, linkage._1) + else (finalRemainingLines, linkage._1) + } + + // This method constructs the paragraphs. Be careful because the final list is reversed + def constructParagraphs(lines: NodeSeq, accu: List[XMLParagraph]): List[XMLParagraph] = lines.isEmpty match { + case true => accu + case false => + val construction = constructNewParagraph(lines, XMLObjectsManager.getCleanXMLParagraph(lineSeparator)) + val layoutParagraph = setLayout(construction._2.reverseLines) + constructParagraphs(construction._1, layoutParagraph :: accu) + } + + // Global page processing + def processGlobalPage(paragraphs: List[XMLParagraph]): List[XMLParagraph] = paragraphs.remove(p => (p.getLines.length == 1 && p.getText.length() <= 3) || p.getPosition.getX < 0 || (p.getPosition.getX + p.getPosition.getWidth) > (pagePosition.getX + pagePosition.getWidth) || p.getPosition.getY < 0 || (p.getPosition.getY + p.getPosition.getHeight) > (pagePosition.getY + pagePosition.getHeight)) + + val finalParagraphs = processGlobalPage(constructParagraphs(lines, List()).reverse) + + Some(finalParagraphs) + } +} \ No newline at end of file diff --git a/app/paper/XMLParser.scala b/app/paper/XMLParser.scala new file mode 100644 index 0000000..f4157fd --- /dev/null +++ b/app/paper/XMLParser.scala @@ -0,0 +1,79 @@ +package paper +import scala.io.Source +import scala.xml.XML +import scala.xml.Elem +import scala.xml.NodeSeq +import scala.xml.TypeSymbol +import scala.util.matching.Regex.MatchIterator +import sun.nio.cs.Unicode + + +object XMLParser extends Parsers with TitleExtractor1 + with AuthorsExtractor1 + with AbstractExtractor1 + with BodyExtractor1 + with ReferencesExtractor1{ + + val extractionOrder: List[(Paper, XMLDocument, List[XMLParagraph]) => (List[XMLParagraph], Paper)] = List(extractTitle, extractAuthors, extractAbstract, extractBody, extractReferences) + + + // This method returns the xml representation of the text contained in the Source object + def getXMLObject(in: Source): Option[Elem] = { + // String generation and illegal xml characters removing + val text = in.mkString.replace("" + '\uffff', "").replace("" + "\u001f", "").replace("\u0010", "").replace("\u000b", "").replace("\u000c", "") + // This instruction is important, otherwise the xml file can't be deleted + in.close + + try { + // The replacement of the and tags is important because loadString sometimes generate an exception about these tags + // Of course, some information is lost, but not really an important one + Some(XML.loadString("""""".r.replaceAllIn(text, ""))) + } catch { + case _ => println("Couldn't load the XML file."); None + } + } + + + // Method for references extraction following the extraction order + def extract(extractors: List[(Paper, XMLDocument, List[XMLParagraph]) => (List[XMLParagraph], Paper)], t : (XMLDocument, Option[Paper], List[XMLParagraph])): (XMLDocument, Option[Paper], List[XMLParagraph]) = { + def extract0(extractors: List[(Paper, XMLDocument, List[XMLParagraph]) => (List[XMLParagraph], Paper)], t : (XMLDocument, Option[Paper], List[XMLParagraph])): (XMLDocument, Option[Paper], List[XMLParagraph]) = { + if(extractors.length == 0) return t + + val input = if(extractors.length == 1) t else extract0(extractors.tail, t) + val xml = input._1 + val paper = input._2 + val paragraphs = input._3 + + if(paper != None) { + // Calling the extraction method of the extractor + val extraction = extractors.head(paper.get, xml, paragraphs) + return (xml, Some(extraction._2), extraction._1) + } + + (xml, None, paragraphs) + } + + extract0(extractors.reverse, t) + } + + // The function for actually parsing a paper + def parse(in: Source) : Option[Paper] = { + val xml = getXMLObject(in) + + if(xml == None) None + else { + val cleanPaper = Paper(0, 0, Title(""), Nil, Abstract("Not saved"), Body("Not saved"), List(), Map.empty, List()) + val xmlDocument = XMLObjectsManager.constructXMLDocument(xml.get, "\n") + + // print + //xmlDocument.get.getParagraphs.foreach((p : XMLParagraph) => println(p.getText + "\n" + p.getOptionsValue + "\n" + p.getEnumerationFormat + "\n\n\n")) + + if(xmlDocument == None) return None + val paper = extract(extractionOrder, (xmlDocument.get, Some(cleanPaper), xmlDocument.get.getParagraphs)) + + if(paper._2 == None) None + else Some(paper._2.get.setMeta("parsed" -> "yes")) + } + } + +} \ No newline at end of file diff --git a/app/paper/XMLScheduleParser.scala b/app/paper/XMLScheduleParser.scala new file mode 100644 index 0000000..f02a25e --- /dev/null +++ b/app/paper/XMLScheduleParser.scala @@ -0,0 +1,153 @@ +package paper +import java.io.File + +trait XMLScheduleParser { + + import scala.xml._ + import scala.collection.immutable.Map._ + + // Overall function that loads the xml schedule and returns the papers with the extra data + def getXMLSchedule(paperPos : String, papers : Option[List[Paper]]) : List[Paper] = { + println("BEGIN OF XML SCHEDULING") + val path = paperPos + Paths.sep + "schedule.xml" + + val schedule = (new File(path)).exists() + + val loadedPapers = if(papers == None) CacheLoader.load(paperPos, Cache.parsed) else papers.get + + // Parse schedule + val xml : Map[Int, Elem] = if(schedule) parse(path) else Map() + + println("END OF XML SCHEDULING") + // match schedule with papers + return matchXML(xml, loadedPapers, schedule) + } + + // Function for taking care of parsing the xml + def parse(paperPos : String) : Map[Int, Elem] = { + + // Load schedule file + val schedule : Elem = XML.loadFile(paperPos) + + // Initialize Map + var data : Map[Int, Elem] = Map.empty + + // For each session record room, date, session + (schedule \\ "session") foreach (session => { + + var date = (session \ "date").text + var room = (session \ "room").text + var sess = (session \ "code").text + ": " + (session \ "sessiontitle").text + + // Now for each paper record starttime, endtime, paperid, papertitle, abstract + (session \\ "paper") foreach (paper => { + // Create a hunk of xml containing all the data + var xml = { date }{ room }{ sess }{ paper } + var id = (paper \\ "paperid").text + data = data + (id.toInt -> xml) + }) + }) + + // Return the map of all the data + return data + } + + // Function for putting the xml in the right paper + def matchXML(xml : Map[Int, Elem], papers : List[Paper], schedule: Boolean) : List[Paper]= { + def apply(p: Paper, data: Option[Elem] ): Paper = { + // Get resulting paper + val result = setXMLData(data, p, schedule) + + // Save result + Cache.save(result, Cache.scheduled) + + // Return result + result + } + + // Loop through all papers and add the xml elements the appropriate one + return for (p <- papers) yield { + val xmlObject = xml.get(p.id) + if(schedule && xmlObject == None) {println("No schedule data for paper with id: " + p.id); p} + else apply(p, xmlObject) + } + } + + // Putting the xml in a paper + def setXMLData(xmlObject : Option[Elem], paper : Paper, schedule: Boolean) : Paper = { + if(schedule) { + val xml = xmlObject.get + paper.setMeta("xmldate" -> getDate(xml)) + .setMeta("xmlroom" -> getRoom(xml \\ "room")) + .setMeta("xmlsession" -> (xml \\ "sess").text) + .setMeta("xmlstarttime" -> (xml \\ "starttime").text) + .setMeta("xmlendtime" -> (xml \\ "endtime").text) + .setMeta("xmlpaperid" -> (xml \\ "paperid").text) + .setMeta("xmlsessionid" -> (xml \\ "sessionid").text) + .setMeta("xmlpapertitle" -> (xml \\ "papertitle").text) + .setMeta("xmlabstract" -> (xml \\ "abstract").text) + .setMeta("xmlauthors" -> getAuthors(xml \\ "authors").mkString(", ")) + .setTitle(new Title((xml \\ "papertitle").text)) + .setAuthors(getAuthors(xml \\ "authors").map(a => Author(formatAuthors(a)))) + } else { + paper.setMeta("xmldate" -> "-") + .setMeta("xmlroom" -> "-") + .setMeta("xmlpapertitle" -> paper.title.toString()) + .setMeta("xmlauthors" -> paper.authors.mkString(", ")) + } + } + + // Converts an authors XML note to string + def getAuthors(authors : NodeSeq) : List[String] = { + return (for (a <- (authors \ "author")) yield (a \\ "name").text).toList + } + + def getRoom(room : NodeSeq) : String = { + room.text match { + case "Track 1" => "Kresge Rehearsal B (030)" + case "Track 2" => "Kresge Auditorium (109)" + case "Track 3" => "Stratton S. de P. Rico (202)" + case "Track 4" => "Stratton 20 Chimneys (306)" + case "Track 5" => "Kresge Little Theatre (035)" + case "Track 6" => "Kresge Rehearsal A (033)" + case "Track 7" => "Stratton (407)" + case "Track 8" => "Stratton (491)" + case "Track 9" => "Stratton West Lounge (201)" + } + } + + def getDate(xml : Elem) : String = { + import java.util.Calendar + import java.sql.Timestamp + + var date = (xml \\ "date").text + var time = (xml \\ "starttime").text + + var dateNum : Int = date.takeWhile(_.isDigit).toInt + var hourNum : Int = time.split(':').head.toInt + var minNum : Int = time.split(':').last.toInt + + // Get Calendar + var c = Calendar.getInstance + + // Set starting point + c.set(2012, 6, dateNum, hourNum, minNum) + c.set(Calendar.SECOND,0) + c.set(Calendar.MILLISECOND,0) + + // Get a timeStamp + var t = (new Timestamp(c.getTime.getTime).getTime).toString + + return t + } + + def formatAuthors(name : String) : String = { + var result = "" + var names = name.split(" ").filter(n => n.length > 0) + if (names.length > 0) { + result = names.init.filter(n => n.length > 0).map(n => n.head).mkString("",". ",". ") + names.last + } + return result + } + +} diff --git a/ajax.php b/app/views/ajax.php similarity index 95% rename from ajax.php rename to app/views/ajax.php index 65fa69e..1997f9b 100644 --- a/ajax.php +++ b/app/views/ajax.php @@ -26,11 +26,11 @@ function get_abstract() { // Get ID $id = $_GET["id"]; - $file = "data/".$id.".abstract.txt"; + $file = $id.".abstract.txt"; // Make sure we have sufficient zeros in front for ($i = 0; $i < 10 && !file_exists( $file ); $i++) - $file = "data/".str_repeat("0",$i).$id.".abstract.txt"; + $file = str_repeat("0",$i).$id.".abstract.txt"; // Now get contents (which are formatted as UTF-16) $content = file_get_contents($file, FILE_TEXT); diff --git a/index.html b/app/views/index.scala.html old mode 100755 new mode 100644 similarity index 65% rename from index.html rename to app/views/index.scala.html index 41126d5..59d711d --- a/index.html +++ b/app/views/index.scala.html @@ -1,42 +1,48 @@ +@(link: String) +@import helper._ + + + + - + - - - + + + - - - - - + + + + + - - + + + + - - Trailhead: A Graphical Representation of Articles -
-