From a5173c981bd9565dde70d6eeca34f07374be50fd Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Thu, 19 May 2016 15:01:28 +0100 Subject: [PATCH 1/5] Initial commit to new repo --- .env.example | 52 + .env.travis | 11 + .gitattributes | 3 + .gitignore | 11 + .styleci.yml | 7 + .travis.yml | 31 + app/Article.php | 148 + app/Client.php | 22 + app/Console/Commands/Inspire.php | 33 + app/Console/Kernel.php | 30 + app/Contact.php | 22 + app/Events/Event.php | 8 + app/Exceptions/Handler.php | 87 + app/Exceptions/RemoteContentNotFound.php | 10 + app/Http/Controllers/AdminController.php | 35 + .../Controllers/ArticlesAdminController.php | 140 + app/Http/Controllers/ArticlesController.php | 69 + app/Http/Controllers/Auth/AuthController.php | 72 + .../Controllers/Auth/PasswordController.php | 32 + app/Http/Controllers/AuthController.php | 29 + .../Controllers/ClientsAdminController.php | 87 + .../Controllers/ContactsAdminController.php | 166 + app/Http/Controllers/ContactsController.php | 49 + app/Http/Controllers/Controller.php | 14 + app/Http/Controllers/IndieAuthController.php | 164 + .../Controllers/MicropubClientController.php | 333 ++ app/Http/Controllers/MicropubController.php | 143 + app/Http/Controllers/NotesAdminController.php | 100 + app/Http/Controllers/NotesController.php | 240 + app/Http/Controllers/PhotosController.php | 94 + .../Controllers/PlacesAdminController.php | 85 + app/Http/Controllers/PlacesController.php | 89 + app/Http/Controllers/ShortURLsController.php | 120 + app/Http/Controllers/TokensController.php | 61 + .../Controllers/WebMentionsController.php | 100 + app/Http/Kernel.php | 55 + app/Http/Middleware/Authenticate.php | 30 + app/Http/Middleware/EncryptCookies.php | 17 + app/Http/Middleware/LinkHeadersMiddleware.php | 26 + app/Http/Middleware/MyAuthMiddleware.php | 25 + .../Middleware/RedirectIfAuthenticated.php | 26 + app/Http/Middleware/VerifyCsrfToken.php | 20 + app/Http/Requests/Request.php | 10 + app/Http/routes.php | 150 + app/Jobs/Job.php | 21 + app/Jobs/ProcessWebMention.php | 256 + app/Jobs/SendWebMentions.php | 86 + app/Jobs/SyndicateToTwitter.php | 108 + app/Listeners/.gitkeep | 1 + app/Note.php | 230 + app/Place.php | 133 + app/Policies/.gitkeep | 1 + app/Providers/AppServiceProvider.php | 57 + app/Providers/AuthServiceProvider.php | 31 + app/Providers/EventServiceProvider.php | 33 + app/Providers/RouteServiceProvider.php | 61 + app/Services/IndieAuthService.php | 113 + app/Services/NoteService.php | 67 + app/Services/PlaceService.php | 39 + app/Services/TokenService.php | 54 + app/Tag.php | 39 + app/User.php | 26 + app/WebMention.php | 32 + artisan | 51 + bootstrap/app.php | 55 + bootstrap/autoload.php | 34 + bootstrap/cache/.gitignore | 2 + bower.json | 26 + composer.json | 68 + composer.lock | 5025 +++++++++++++++++ config/app.php | 241 + config/auth.php | 107 + config/broadcasting.php | 52 + config/cache.php | 81 + config/compile.php | 35 + config/database.php | 131 + config/debugbar.php | 145 + config/filesystems.php | 72 + config/laravel-medialibrary.php | 40 + config/mail.php | 112 + config/queue.php | 85 + config/services.php | 38 + config/session.php | 166 + config/ttwitter.php | 18 + config/url.php | 11 + config/view.php | 33 + database/.gitignore | 1 + database/factories/ModelFactory.php | 28 + database/migrations/.gitkeep | 1 + ...015_02_28_132629_create_articles_table.php | 38 + .../2015_02_28_144939_create_notes_table.php | 40 + .../2015_03_02_084342_create_tags_table.php | 31 + ...015_03_02_084956_create_note_tag_table.php | 33 + ...015_03_02_105623_create_contacts_table.php | 34 + ...03_02_114340_create_web_mentions_table.php | 39 + ...2015_07_17_111512_create_clients_table.php | 32 + ..._07_22_084423_create_failed_jobs_table.php | 33 + .../2015_10_08_155111_create_media_table.php | 35 + .../2015_11_07_130637_create_places_table.php | 35 + ..._19_221933_add_place_relation_to_notes.php | 33 + database/seeds/.gitkeep | 1 + database/seeds/ArticlesTableSeeder.php | 23 + database/seeds/ClientsTableSeeder.php | 21 + database/seeds/ContactsTableSeeder.php | 32 + database/seeds/DatabaseSeeder.php | 20 + database/seeds/NotesTableSeeder.php | 39 + database/seeds/PlacesTableSeeder.php | 23 + gulpfile.js | 81 + package.json | 17 + phpunit.xml | 30 + public/.htaccess | 20 + public/assets/css/alertify.css | 1 + public/assets/css/global.css | 243 + public/assets/css/global.css.map | 1 + public/assets/css/images/icons-000000@2x.png | Bin 0 -> 1548 bytes public/assets/css/normalize.css | 424 ++ public/assets/css/prism.css | 188 + public/assets/css/projects.css | 10 + public/assets/css/sanitize.min.css | 2 + public/assets/img/escheresque.png | Bin 0 -> 395 bytes public/assets/img/escheresque@2x.png | Bin 0 -> 3977 bytes public/assets/img/jmb-bw.png | Bin 0 -> 30162 bytes public/assets/img/notes/.gitignore | 3 + public/assets/jonnybarnes-public-key-ecc.asc | 22 + public/assets/jonnybarnes-public-key.asc | 52 + public/assets/js/Autolinker.min.js | 10 + public/assets/js/alertify.js | 1 + public/assets/js/fetch.js | 389 ++ public/assets/js/form-save.js | 69 + public/assets/js/links.js | 25 + public/assets/js/maps.js | 15 + public/assets/js/marked.min.js | 6 + public/assets/js/newnote.js | 284 + public/assets/js/newplace.js | 45 + public/assets/js/prism.js | 15 + public/assets/js/store2.min.js | 5 + public/assets/old-shorturls.json | 19 + public/assets/profile-images/.gitignore | 3 + public/assets/profile-images/default-image | Bin 0 -> 8867 bytes .../build/assets/css/alertify-d84546f82d.css | 1 + .../assets/css/alertify-d84546f82d.css.br | Bin 0 -> 857 bytes .../assets/css/alertify-d84546f82d.css.gz | Bin 0 -> 1043 bytes public/build/assets/css/global-ef9dfef096.css | 243 + .../build/assets/css/global-ef9dfef096.css.br | Bin 0 -> 1061 bytes .../build/assets/css/global-ef9dfef096.css.gz | Bin 0 -> 1250 bytes public/build/assets/css/global.css.map | 1 + public/build/assets/css/prism-5c98941a94.css | 188 + .../build/assets/css/prism-5c98941a94.css.br | Bin 0 -> 1095 bytes .../build/assets/css/prism-5c98941a94.css.gz | Bin 0 -> 1274 bytes .../build/assets/css/projects-d945298e4f.css | 10 + .../assets/css/projects-d945298e4f.css.br | Bin 0 -> 82 bytes .../assets/css/projects-d945298e4f.css.gz | Bin 0 -> 119 bytes .../assets/css/sanitize.min-535bccd783.css | 2 + .../assets/css/sanitize.min-535bccd783.css.br | Bin 0 -> 790 bytes .../assets/css/sanitize.min-535bccd783.css.gz | Bin 0 -> 978 bytes .../assets/js/Autolinker.min-b46556773a.js | 10 + .../assets/js/Autolinker.min-b46556773a.js.br | Bin 0 -> 7715 bytes .../assets/js/Autolinker.min-b46556773a.js.gz | Bin 0 -> 8473 bytes public/build/assets/js/alertify-269e23cb46.js | 1 + .../build/assets/js/alertify-269e23cb46.js.br | Bin 0 -> 2762 bytes .../build/assets/js/alertify-269e23cb46.js.gz | Bin 0 -> 3143 bytes public/build/assets/js/fetch-5e9040330a.js | 389 ++ public/build/assets/js/fetch-5e9040330a.js.br | Bin 0 -> 2381 bytes public/build/assets/js/fetch-5e9040330a.js.gz | Bin 0 -> 2643 bytes .../build/assets/js/form-save-7849d1a5f3.js | 69 + .../assets/js/form-save-7849d1a5f3.js.br | Bin 0 -> 565 bytes .../assets/js/form-save-7849d1a5f3.js.gz | Bin 0 -> 712 bytes public/build/assets/js/links-ea4c99f585.js | 25 + public/build/assets/js/links-ea4c99f585.js.br | Bin 0 -> 337 bytes public/build/assets/js/links-ea4c99f585.js.gz | Bin 0 -> 434 bytes public/build/assets/js/maps-ffa37774ae.js | 15 + public/build/assets/js/maps-ffa37774ae.js.br | Bin 0 -> 352 bytes public/build/assets/js/maps-ffa37774ae.js.gz | Bin 0 -> 406 bytes .../build/assets/js/marked.min-c2a88705e2.js | 6 + .../assets/js/marked.min-c2a88705e2.js.br | Bin 0 -> 5184 bytes .../assets/js/marked.min-c2a88705e2.js.gz | Bin 0 -> 5514 bytes public/build/assets/js/newnote-c1700073b7.js | 284 + .../build/assets/js/newnote-c1700073b7.js.br | Bin 0 -> 2371 bytes .../build/assets/js/newnote-c1700073b7.js.gz | Bin 0 -> 2636 bytes public/build/assets/js/newplace-18722f800b.js | 45 + .../build/assets/js/newplace-18722f800b.js.br | Bin 0 -> 548 bytes .../build/assets/js/newplace-18722f800b.js.gz | Bin 0 -> 649 bytes public/build/assets/js/prism-f6e997bc6d.js | 15 + public/build/assets/js/prism-f6e997bc6d.js.br | Bin 0 -> 6464 bytes public/build/assets/js/prism-f6e997bc6d.js.gz | Bin 0 -> 6938 bytes .../build/assets/js/store2.min-c4daa8f871.js | 5 + .../assets/js/store2.min-c4daa8f871.js.br | Bin 0 -> 1303 bytes .../assets/js/store2.min-c4daa8f871.js.gz | Bin 0 -> 1426 bytes public/build/rev-manifest.json | 18 + public/favicon.ico | 0 public/index.php | 58 + public/media/.gitignore | 2 + public/robots.txt | 2 + public/web.config | 23 + readme.md | 27 + resources/assets/sass/app.scss | 2 + resources/assets/sass/components/colours.scss | 12 + resources/assets/sass/components/fonts.scss | 41 + resources/assets/sass/components/forms.scss | 45 + resources/assets/sass/components/twitter.scss | 9 + resources/assets/sass/global.scss | 41 + resources/assets/sass/layout.scss | 197 + resources/lang/en/auth.php | 19 + resources/lang/en/pagination.php | 19 + resources/lang/en/passwords.php | 22 + resources/lang/en/validation.php | 113 + resources/views/admin/deletearticle.blade.php | 13 + .../admin/deletearticlesuccess.blade.php | 9 + .../views/admin/deleteclientsuccess.blade.php | 9 + resources/views/admin/deletecontact.blade.php | 14 + .../admin/deletecontactsuccess.blade.php | 9 + resources/views/admin/deletetoken.blade.php | 13 + .../views/admin/deletetokensuccess.blade.php | 9 + resources/views/admin/editarticle.blade.php | 41 + .../views/admin/editarticlesuccess.blade.php | 9 + resources/views/admin/editclient.blade.php | 15 + .../views/admin/editclientsuccess.blade.php | 9 + resources/views/admin/editcontact.blade.php | 20 + .../views/admin/editcontactsuccess.blade.php | 9 + resources/views/admin/editnote.blade.php | 18 + .../views/admin/editnotesuccess.blade.php | 9 + resources/views/admin/editplace.blade.php | 18 + .../views/admin/editplacesuccess.blade.php | 9 + .../views/admin/getavatarsuccess.blade.php | 10 + resources/views/admin/listarticles.blade.php | 14 + resources/views/admin/listclients.blade.php | 17 + resources/views/admin/listcontacts.blade.php | 27 + resources/views/admin/listnotes.blade.php | 14 + resources/views/admin/listplaces.blade.php | 15 + resources/views/admin/listtokens.blade.php | 21 + resources/views/admin/newarticle.blade.php | 49 + .../views/admin/newarticlesuccess.blade.php | 9 + resources/views/admin/newclient.blade.php | 15 + .../views/admin/newclientsuccess.blade.php | 9 + resources/views/admin/newcontact.blade.php | 17 + .../views/admin/newcontactsuccess.blade.php | 9 + resources/views/admin/newnote.blade.php | 34 + .../views/admin/newnotesuccess.blade.php | 9 + resources/views/admin/newplace.blade.php | 24 + .../views/admin/newplacesuccess.blade.php | 9 + resources/views/admin/welcome.blade.php | 24 + resources/views/allnotes.blade.php | 31 + resources/views/allplaces.blade.php | 13 + resources/views/contact-template.blade.php | 10 + resources/views/contact.blade.php | 9 + resources/views/contacts.blade.php | 11 + resources/views/errors/503.blade.php | 47 + resources/views/homepage.blade.php | 29 + resources/views/login.blade.php | 12 + resources/views/master.blade.php | 58 + resources/views/micropubnewnotepage.blade.php | 45 + resources/views/mini-hcard-template.blade.php | 4 + resources/views/multipost.blade.php | 30 + resources/views/projects.blade.php | 14 + resources/views/rss.blade.php | 22 + resources/views/singlenote.blade.php | 43 + resources/views/singleplace.blade.php | 21 + resources/views/singlepost.blade.php | 24 + resources/views/taggednotes.blade.php | 13 + .../views/templates/new-note-form.blade.php | 16 + resources/views/templates/note.blade.php | 26 + .../views/templates/social-links.blade.php | 31 + resources/views/vendor/.gitkeep | 1 + resources/views/webmention-endpoint.blade.php | 9 + resources/views/welcome.blade.php | 45 + server.php | 21 + storage/HTML/.gitignore | 3 + storage/HTML/.gitkeep | 0 storage/HTMLPurifier/.gitignore | 2 + storage/app/.gitignore | 3 + storage/app/public/.gitignore | 2 + storage/debugbar/.gitignore | 2 + storage/framework/.gitignore | 8 + storage/framework/cache/.gitignore | 2 + storage/framework/sessions/.gitignore | 2 + storage/framework/views/.gitignore | 2 + storage/logs/.gitignore | 2 + storage/media-tmp/.gitkeep | 0 storage/medialibrary/.gitignore | 2 + storage/tokens/.gitignore | 3 + storage/tokens/.gitkeep | 0 tests/ArticlesTest.php | 78 + tests/ContactsTest.php | 52 + tests/ExampleTest.php | 19 + tests/IndieAuthTest.php | 79 + tests/MicropubClientTest.php | 73 + tests/MicropubTest.php | 112 + tests/NotesTest.php | 179 + tests/PlacesTest.php | 52 + tests/TestCase.php | 25 + tests/TokenServiceTest.php | 43 + tests/aaron.png | Bin 0 -> 6527 bytes 292 files changed, 17472 insertions(+) create mode 100644 .env.example create mode 100644 .env.travis create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .styleci.yml create mode 100644 .travis.yml create mode 100644 app/Article.php create mode 100644 app/Client.php create mode 100644 app/Console/Commands/Inspire.php create mode 100644 app/Console/Kernel.php create mode 100644 app/Contact.php create mode 100644 app/Events/Event.php create mode 100644 app/Exceptions/Handler.php create mode 100644 app/Exceptions/RemoteContentNotFound.php create mode 100644 app/Http/Controllers/AdminController.php create mode 100644 app/Http/Controllers/ArticlesAdminController.php create mode 100644 app/Http/Controllers/ArticlesController.php create mode 100644 app/Http/Controllers/Auth/AuthController.php create mode 100644 app/Http/Controllers/Auth/PasswordController.php create mode 100644 app/Http/Controllers/AuthController.php create mode 100644 app/Http/Controllers/ClientsAdminController.php create mode 100644 app/Http/Controllers/ContactsAdminController.php create mode 100644 app/Http/Controllers/ContactsController.php create mode 100644 app/Http/Controllers/Controller.php create mode 100644 app/Http/Controllers/IndieAuthController.php create mode 100644 app/Http/Controllers/MicropubClientController.php create mode 100644 app/Http/Controllers/MicropubController.php create mode 100644 app/Http/Controllers/NotesAdminController.php create mode 100644 app/Http/Controllers/NotesController.php create mode 100644 app/Http/Controllers/PhotosController.php create mode 100644 app/Http/Controllers/PlacesAdminController.php create mode 100644 app/Http/Controllers/PlacesController.php create mode 100644 app/Http/Controllers/ShortURLsController.php create mode 100644 app/Http/Controllers/TokensController.php create mode 100644 app/Http/Controllers/WebMentionsController.php create mode 100644 app/Http/Kernel.php create mode 100644 app/Http/Middleware/Authenticate.php create mode 100644 app/Http/Middleware/EncryptCookies.php create mode 100644 app/Http/Middleware/LinkHeadersMiddleware.php create mode 100644 app/Http/Middleware/MyAuthMiddleware.php create mode 100644 app/Http/Middleware/RedirectIfAuthenticated.php create mode 100644 app/Http/Middleware/VerifyCsrfToken.php create mode 100644 app/Http/Requests/Request.php create mode 100644 app/Http/routes.php create mode 100644 app/Jobs/Job.php create mode 100644 app/Jobs/ProcessWebMention.php create mode 100644 app/Jobs/SendWebMentions.php create mode 100644 app/Jobs/SyndicateToTwitter.php create mode 100644 app/Listeners/.gitkeep create mode 100644 app/Note.php create mode 100644 app/Place.php create mode 100644 app/Policies/.gitkeep create mode 100644 app/Providers/AppServiceProvider.php create mode 100644 app/Providers/AuthServiceProvider.php create mode 100644 app/Providers/EventServiceProvider.php create mode 100644 app/Providers/RouteServiceProvider.php create mode 100644 app/Services/IndieAuthService.php create mode 100644 app/Services/NoteService.php create mode 100644 app/Services/PlaceService.php create mode 100644 app/Services/TokenService.php create mode 100644 app/Tag.php create mode 100644 app/User.php create mode 100644 app/WebMention.php create mode 100755 artisan create mode 100644 bootstrap/app.php create mode 100644 bootstrap/autoload.php create mode 100644 bootstrap/cache/.gitignore create mode 100644 bower.json create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 config/app.php create mode 100644 config/auth.php create mode 100644 config/broadcasting.php create mode 100644 config/cache.php create mode 100644 config/compile.php create mode 100644 config/database.php create mode 100644 config/debugbar.php create mode 100644 config/filesystems.php create mode 100644 config/laravel-medialibrary.php create mode 100644 config/mail.php create mode 100644 config/queue.php create mode 100644 config/services.php create mode 100644 config/session.php create mode 100644 config/ttwitter.php create mode 100644 config/url.php create mode 100644 config/view.php create mode 100644 database/.gitignore create mode 100644 database/factories/ModelFactory.php create mode 100644 database/migrations/.gitkeep create mode 100644 database/migrations/2015_02_28_132629_create_articles_table.php create mode 100644 database/migrations/2015_02_28_144939_create_notes_table.php create mode 100644 database/migrations/2015_03_02_084342_create_tags_table.php create mode 100644 database/migrations/2015_03_02_084956_create_note_tag_table.php create mode 100644 database/migrations/2015_03_02_105623_create_contacts_table.php create mode 100644 database/migrations/2015_03_02_114340_create_web_mentions_table.php create mode 100644 database/migrations/2015_07_17_111512_create_clients_table.php create mode 100644 database/migrations/2015_07_22_084423_create_failed_jobs_table.php create mode 100644 database/migrations/2015_10_08_155111_create_media_table.php create mode 100644 database/migrations/2015_11_07_130637_create_places_table.php create mode 100644 database/migrations/2015_11_19_221933_add_place_relation_to_notes.php create mode 100644 database/seeds/.gitkeep create mode 100644 database/seeds/ArticlesTableSeeder.php create mode 100644 database/seeds/ClientsTableSeeder.php create mode 100644 database/seeds/ContactsTableSeeder.php create mode 100644 database/seeds/DatabaseSeeder.php create mode 100644 database/seeds/NotesTableSeeder.php create mode 100644 database/seeds/PlacesTableSeeder.php create mode 100644 gulpfile.js create mode 100644 package.json create mode 100644 phpunit.xml create mode 100644 public/.htaccess create mode 100644 public/assets/css/alertify.css create mode 100644 public/assets/css/global.css create mode 100644 public/assets/css/global.css.map create mode 100644 public/assets/css/images/icons-000000@2x.png create mode 100644 public/assets/css/normalize.css create mode 100644 public/assets/css/prism.css create mode 100644 public/assets/css/projects.css create mode 100644 public/assets/css/sanitize.min.css create mode 100644 public/assets/img/escheresque.png create mode 100644 public/assets/img/escheresque@2x.png create mode 100644 public/assets/img/jmb-bw.png create mode 100644 public/assets/img/notes/.gitignore create mode 100644 public/assets/jonnybarnes-public-key-ecc.asc create mode 100644 public/assets/jonnybarnes-public-key.asc create mode 100644 public/assets/js/Autolinker.min.js create mode 100644 public/assets/js/alertify.js create mode 100644 public/assets/js/fetch.js create mode 100644 public/assets/js/form-save.js create mode 100644 public/assets/js/links.js create mode 100644 public/assets/js/maps.js create mode 100644 public/assets/js/marked.min.js create mode 100644 public/assets/js/newnote.js create mode 100644 public/assets/js/newplace.js create mode 100644 public/assets/js/prism.js create mode 100644 public/assets/js/store2.min.js create mode 100644 public/assets/old-shorturls.json create mode 100644 public/assets/profile-images/.gitignore create mode 100644 public/assets/profile-images/default-image create mode 100644 public/build/assets/css/alertify-d84546f82d.css create mode 100644 public/build/assets/css/alertify-d84546f82d.css.br create mode 100644 public/build/assets/css/alertify-d84546f82d.css.gz create mode 100644 public/build/assets/css/global-ef9dfef096.css create mode 100644 public/build/assets/css/global-ef9dfef096.css.br create mode 100644 public/build/assets/css/global-ef9dfef096.css.gz create mode 100644 public/build/assets/css/global.css.map create mode 100644 public/build/assets/css/prism-5c98941a94.css create mode 100644 public/build/assets/css/prism-5c98941a94.css.br create mode 100644 public/build/assets/css/prism-5c98941a94.css.gz create mode 100644 public/build/assets/css/projects-d945298e4f.css create mode 100644 public/build/assets/css/projects-d945298e4f.css.br create mode 100644 public/build/assets/css/projects-d945298e4f.css.gz create mode 100644 public/build/assets/css/sanitize.min-535bccd783.css create mode 100644 public/build/assets/css/sanitize.min-535bccd783.css.br create mode 100644 public/build/assets/css/sanitize.min-535bccd783.css.gz create mode 100644 public/build/assets/js/Autolinker.min-b46556773a.js create mode 100644 public/build/assets/js/Autolinker.min-b46556773a.js.br create mode 100644 public/build/assets/js/Autolinker.min-b46556773a.js.gz create mode 100644 public/build/assets/js/alertify-269e23cb46.js create mode 100644 public/build/assets/js/alertify-269e23cb46.js.br create mode 100644 public/build/assets/js/alertify-269e23cb46.js.gz create mode 100644 public/build/assets/js/fetch-5e9040330a.js create mode 100644 public/build/assets/js/fetch-5e9040330a.js.br create mode 100644 public/build/assets/js/fetch-5e9040330a.js.gz create mode 100644 public/build/assets/js/form-save-7849d1a5f3.js create mode 100644 public/build/assets/js/form-save-7849d1a5f3.js.br create mode 100644 public/build/assets/js/form-save-7849d1a5f3.js.gz create mode 100644 public/build/assets/js/links-ea4c99f585.js create mode 100644 public/build/assets/js/links-ea4c99f585.js.br create mode 100644 public/build/assets/js/links-ea4c99f585.js.gz create mode 100644 public/build/assets/js/maps-ffa37774ae.js create mode 100644 public/build/assets/js/maps-ffa37774ae.js.br create mode 100644 public/build/assets/js/maps-ffa37774ae.js.gz create mode 100644 public/build/assets/js/marked.min-c2a88705e2.js create mode 100644 public/build/assets/js/marked.min-c2a88705e2.js.br create mode 100644 public/build/assets/js/marked.min-c2a88705e2.js.gz create mode 100644 public/build/assets/js/newnote-c1700073b7.js create mode 100644 public/build/assets/js/newnote-c1700073b7.js.br create mode 100644 public/build/assets/js/newnote-c1700073b7.js.gz create mode 100644 public/build/assets/js/newplace-18722f800b.js create mode 100644 public/build/assets/js/newplace-18722f800b.js.br create mode 100644 public/build/assets/js/newplace-18722f800b.js.gz create mode 100644 public/build/assets/js/prism-f6e997bc6d.js create mode 100644 public/build/assets/js/prism-f6e997bc6d.js.br create mode 100644 public/build/assets/js/prism-f6e997bc6d.js.gz create mode 100644 public/build/assets/js/store2.min-c4daa8f871.js create mode 100644 public/build/assets/js/store2.min-c4daa8f871.js.br create mode 100644 public/build/assets/js/store2.min-c4daa8f871.js.gz create mode 100644 public/build/rev-manifest.json create mode 100644 public/favicon.ico create mode 100644 public/index.php create mode 100644 public/media/.gitignore create mode 100644 public/robots.txt create mode 100644 public/web.config create mode 100644 readme.md create mode 100644 resources/assets/sass/app.scss create mode 100644 resources/assets/sass/components/colours.scss create mode 100644 resources/assets/sass/components/fonts.scss create mode 100644 resources/assets/sass/components/forms.scss create mode 100644 resources/assets/sass/components/twitter.scss create mode 100644 resources/assets/sass/global.scss create mode 100644 resources/assets/sass/layout.scss create mode 100644 resources/lang/en/auth.php create mode 100644 resources/lang/en/pagination.php create mode 100644 resources/lang/en/passwords.php create mode 100644 resources/lang/en/validation.php create mode 100644 resources/views/admin/deletearticle.blade.php create mode 100644 resources/views/admin/deletearticlesuccess.blade.php create mode 100644 resources/views/admin/deleteclientsuccess.blade.php create mode 100644 resources/views/admin/deletecontact.blade.php create mode 100644 resources/views/admin/deletecontactsuccess.blade.php create mode 100644 resources/views/admin/deletetoken.blade.php create mode 100644 resources/views/admin/deletetokensuccess.blade.php create mode 100644 resources/views/admin/editarticle.blade.php create mode 100644 resources/views/admin/editarticlesuccess.blade.php create mode 100644 resources/views/admin/editclient.blade.php create mode 100644 resources/views/admin/editclientsuccess.blade.php create mode 100644 resources/views/admin/editcontact.blade.php create mode 100644 resources/views/admin/editcontactsuccess.blade.php create mode 100644 resources/views/admin/editnote.blade.php create mode 100644 resources/views/admin/editnotesuccess.blade.php create mode 100644 resources/views/admin/editplace.blade.php create mode 100644 resources/views/admin/editplacesuccess.blade.php create mode 100644 resources/views/admin/getavatarsuccess.blade.php create mode 100644 resources/views/admin/listarticles.blade.php create mode 100644 resources/views/admin/listclients.blade.php create mode 100644 resources/views/admin/listcontacts.blade.php create mode 100644 resources/views/admin/listnotes.blade.php create mode 100644 resources/views/admin/listplaces.blade.php create mode 100644 resources/views/admin/listtokens.blade.php create mode 100644 resources/views/admin/newarticle.blade.php create mode 100644 resources/views/admin/newarticlesuccess.blade.php create mode 100644 resources/views/admin/newclient.blade.php create mode 100644 resources/views/admin/newclientsuccess.blade.php create mode 100644 resources/views/admin/newcontact.blade.php create mode 100644 resources/views/admin/newcontactsuccess.blade.php create mode 100644 resources/views/admin/newnote.blade.php create mode 100644 resources/views/admin/newnotesuccess.blade.php create mode 100644 resources/views/admin/newplace.blade.php create mode 100644 resources/views/admin/newplacesuccess.blade.php create mode 100644 resources/views/admin/welcome.blade.php create mode 100644 resources/views/allnotes.blade.php create mode 100644 resources/views/allplaces.blade.php create mode 100644 resources/views/contact-template.blade.php create mode 100644 resources/views/contact.blade.php create mode 100644 resources/views/contacts.blade.php create mode 100644 resources/views/errors/503.blade.php create mode 100644 resources/views/homepage.blade.php create mode 100644 resources/views/login.blade.php create mode 100644 resources/views/master.blade.php create mode 100644 resources/views/micropubnewnotepage.blade.php create mode 100644 resources/views/mini-hcard-template.blade.php create mode 100644 resources/views/multipost.blade.php create mode 100644 resources/views/projects.blade.php create mode 100644 resources/views/rss.blade.php create mode 100644 resources/views/singlenote.blade.php create mode 100644 resources/views/singleplace.blade.php create mode 100644 resources/views/singlepost.blade.php create mode 100644 resources/views/taggednotes.blade.php create mode 100644 resources/views/templates/new-note-form.blade.php create mode 100644 resources/views/templates/note.blade.php create mode 100644 resources/views/templates/social-links.blade.php create mode 100644 resources/views/vendor/.gitkeep create mode 100644 resources/views/webmention-endpoint.blade.php create mode 100644 resources/views/welcome.blade.php create mode 100644 server.php create mode 100644 storage/HTML/.gitignore create mode 100644 storage/HTML/.gitkeep create mode 100644 storage/HTMLPurifier/.gitignore create mode 100644 storage/app/.gitignore create mode 100644 storage/app/public/.gitignore create mode 100644 storage/debugbar/.gitignore create mode 100644 storage/framework/.gitignore create mode 100644 storage/framework/cache/.gitignore create mode 100644 storage/framework/sessions/.gitignore create mode 100644 storage/framework/views/.gitignore create mode 100644 storage/logs/.gitignore create mode 100644 storage/media-tmp/.gitkeep create mode 100644 storage/medialibrary/.gitignore create mode 100644 storage/tokens/.gitignore create mode 100644 storage/tokens/.gitkeep create mode 100644 tests/ArticlesTest.php create mode 100644 tests/ContactsTest.php create mode 100644 tests/ExampleTest.php create mode 100644 tests/IndieAuthTest.php create mode 100644 tests/MicropubClientTest.php create mode 100644 tests/MicropubTest.php create mode 100644 tests/NotesTest.php create mode 100644 tests/PlacesTest.php create mode 100644 tests/TestCase.php create mode 100644 tests/TokenServiceTest.php create mode 100644 tests/aaron.png diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..606b9714 --- /dev/null +++ b/.env.example @@ -0,0 +1,52 @@ +APP_ENV=local +APP_DEBUG=true +APP_KEY=SomeRandomString +APP_TIMEZONE=UTC +APP_LANG=en +APP_LOG=daily + +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=homestead +DB_USERNAME=homestead +DB_PASSWORD=secret +DB_CONNECTION=pgsql + +CACHE_DRIVER=file +SESSION_DRIVER=file +QUEUE_DRIVER=sync + +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_DRIVER=smtp +MAIL_HOST=mailtrap.io +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAILGUN_DOMAIN=null +MAILGUN_SECRET=null + +AWS_S3_KEY=your-key +AWS_S3_SECRET=your-secret +AWS_S3_REGION=region +AWS_S3_BUCKET=your-bucket +AWS_S3_URL=https://xxxxxxx.s3-region.amazonaws.com + +APP_URL=https://example.com +APP_LONGURL=example.com +APP_SHORTURL=examp.le + +ADMIN_USER=admin +ADMIN_PASS=password + +PIWIK_URL= +PIWIK_SITE_ID= + +TWITTER_CONSUMER_KEY= +TWITTER_CONSUMER_SECRET= +TWITTER_ACCESS_TOKEN= +TWITTER_ACCESS_TOKEN_SECRET= diff --git a/.env.travis b/.env.travis new file mode 100644 index 00000000..b15c8b3a --- /dev/null +++ b/.env.travis @@ -0,0 +1,11 @@ +APP_ENV=testing +APP_KEY= +APP_URL=http://localhost:8000 +APP_LONGURL=localhost +APP_SHORTURL=local + +DB_CONNECTION=travis + +CACHE_DRIVER=array +SESSION_DRIVER=array +QUEUE_DRIVER=sync diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..a8763f8e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto +*.css linguist-vendored +*.scss linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f791bec4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/vendor +/node_modules +/bower_components +/public/storage +Homestead.yaml +Homestead.json +.env +/.sass-cache +/public/files +/public/keybase.txt +/coverage diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 00000000..645435d1 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,7 @@ +preset: laravel + +disabled: + - concat_without_spaces + +finder: + path: app/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..87638d6c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,31 @@ +language: php + +sudo: false + +addons: + postgresql: "9.4" + +services: + - postgresql + +php: + - 7.0 + - nightly +matrix: + allow_failures: + - php: nightly + +before_script: + - psql -U travis -c 'create database travis_ci_test' + - psql -U travis -d travis_ci_test -c 'create extension postgis' + - cp .env.travis .env + - travis_retry composer self-update --preview + - travis_retry composer install --no-interaction + - php artisan key:generate + - php artisan migrate + - php artisan db:seed + - php artisan serve & + - sleep 5 # Give artisan some time to start serving + +script: + - phpdbg -qrr vendor/bin/phpunit --coverage-text diff --git a/app/Article.php b/app/Article.php new file mode 100644 index 00000000..5ca3f582 --- /dev/null +++ b/app/Article.php @@ -0,0 +1,148 @@ +morphMany('App\WebMention', 'commentable'); + } + + /** + * We shall set a blacklist of non-modifiable model attributes. + * + * @var array + */ + protected $guarded = ['id']; + + /** + * Process the article for display. + * + * @return string + */ + public function getMainAttribute($value) + { + $unicode = new UnicodeTools(); + $markdown = new CommonMarkConverter(); + $html = $markdown->convertToHtml($unicode->convertUnicodeCodepoints($value)); + //change
[lang] ~> 

+        $match = '/
\[(.*)\]\n/';
+        $replace = '
';
+        $text = preg_replace($match, $replace, $html);
+        $default = preg_replace('/
/', '
', $text);
+
+        return $default;
+    }
+
+    /**
+     * Convert updated_at to W3C time format.
+     *
+     * @return string
+     */
+    public function getW3cTimeAttribute()
+    {
+        return $this->updated_at->toW3CString();
+    }
+
+    /**
+     * Convert updated_at to a tooltip appropriate format.
+     *
+     * @return string
+     */
+    public function getTooltipTimeAttribute()
+    {
+        return $this->updated_at->toRFC850String();
+    }
+
+    /**
+     * Convert updated_at to a human readable format.
+     *
+     * @return string
+     */
+    public function getHumanTimeAttribute()
+    {
+        return $this->updated_at->diffForHumans();
+    }
+
+    /**
+     * Get the pubdate value for RSS feeds.
+     *
+     * @return string
+     */
+    public function getPubdateAttribute()
+    {
+        return $this->updated_at->toRSSString();
+    }
+
+    /**
+     * A link to the article, i.e. `/blog/1999/12/25/merry-christmas`.
+     *
+     * @return string
+     */
+    public function getLinkAttribute()
+    {
+        return '/blog/' . $this->updated_at->year . '/' . $this->updated_at->format('m') . '/' . $this->titleurl;
+    }
+
+    /**
+     * Scope a query to only include articles from a particular year/month.
+     *
+     * @return \Illuminate\Database\Eloquent\Builder
+     */
+    public function scopeDate($query, $year = null, $month = null)
+    {
+        if ($year == null) {
+            return $query;
+        }
+        $start = $year . '-01-01 00:00:00';
+        $end = ($year + 1) . '-01-01 00:00:00';
+        if (($month !== null) && ($month !== '12')) {
+            $start = $year . '-' . $month . '-01 00:00:00';
+            $end = $year . '-' . ($month + 1) . '-01 00:00:00';
+        }
+        if ($month === '12') {
+            $start = $year . '-12-01 00:00:00';
+            //$end as above
+        }
+
+        return $query->where([
+            ['updated_at', '>=', $start],
+            ['updated_at', '<', $end],
+        ]);
+    }
+}
diff --git a/app/Client.php b/app/Client.php
new file mode 100644
index 00000000..6461399c
--- /dev/null
+++ b/app/Client.php
@@ -0,0 +1,22 @@
+comment(PHP_EOL.Inspiring::quote().PHP_EOL);
+    }
+}
diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php
new file mode 100644
index 00000000..71c519d3
--- /dev/null
+++ b/app/Console/Kernel.php
@@ -0,0 +1,30 @@
+command('inspire')
+        //          ->hourly();
+    }
+}
diff --git a/app/Contact.php b/app/Contact.php
new file mode 100644
index 00000000..18cc6fa2
--- /dev/null
+++ b/app/Contact.php
@@ -0,0 +1,22 @@
+renderExceptionWithWhoops($exc);
+        }
+
+        if ($exc instanceof ModelNotFoundException) {
+            $exc = new NotFoundHttpException($exc->getMessage(), $exc);
+        }
+
+        if ($exc instanceof TokenMismatchException) {
+            return redirect()->back()
+                ->withInput($request->except('password', '_token'))
+                ->withErrors('Validation Token has expired. Please try again', 'csrf');
+        }
+
+        return parent::render($request, $exc);
+    }
+
+    /**
+     * Render an exception using Whoops.
+     *
+     * @param  \Exception $exc
+     * @return \Illuminate\Http\Response
+     */
+    protected function renderExceptionWithWhoops(Exception $exc)
+    {
+        $whoops = new \Whoops\Run;
+        $handler = new \Whoops\Handler\PrettyPageHandler();
+        $handler->setEditor(function ($file, $line) {
+            return "atom://open?file=$file&line=$line";
+        });
+        $whoops->pushHandler($handler);
+
+        return new \Illuminate\Http\Response(
+            $whoops->handleException($exc),
+            $exc->getStatusCode(),
+            $exc->getHeaders()
+        );
+    }
+}
diff --git a/app/Exceptions/RemoteContentNotFound.php b/app/Exceptions/RemoteContentNotFound.php
new file mode 100644
index 00000000..04049903
--- /dev/null
+++ b/app/Exceptions/RemoteContentNotFound.php
@@ -0,0 +1,10 @@
+username = env('ADMIN_USER');
+    }
+
+    /**
+     * Show the main admin CP page.
+     *
+     * @return \Illuminate\View\Factory view
+     */
+    public function showWelcome()
+    {
+        return view('admin.welcome', ['name' => $this->username]);
+    }
+}
diff --git a/app/Http/Controllers/ArticlesAdminController.php b/app/Http/Controllers/ArticlesAdminController.php
new file mode 100644
index 00000000..21f4124d
--- /dev/null
+++ b/app/Http/Controllers/ArticlesAdminController.php
@@ -0,0 +1,140 @@
+ $message]);
+    }
+
+    /**
+     * List the articles that can be edited.
+     *
+     * @return \Illuminate\View\Factory view
+     */
+    public function listArticles()
+    {
+        $posts = Article::select('id', 'title', 'published')->orderBy('id', 'desc')->get();
+
+        return view('admin.listarticles', ['posts' => $posts]);
+    }
+
+    /**
+     * Show the edit form for an existing article.
+     *
+     * @param  string  The article id
+     * @return \Illuminate\View\Factory view
+     */
+    public function editArticle($articleId)
+    {
+        $post = Article::select(
+            'title',
+            'main',
+            'url',
+            'published'
+        )->where('id', $articleId)->get();
+
+        return view('admin.editarticle', ['id' => $articleId, 'post' => $post]);
+    }
+
+    /**
+     * Show the delete confirmation form for an article.
+     *
+     * @param  string  The article id
+     * @return \Illuminate\View\Factory view
+     */
+    public function deleteArticle($articleId)
+    {
+        return view('admin.deletearticle', ['id' => $articleId]);
+    }
+
+    /**
+     * Process an incoming request for a new article and save it.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\View\Factory view
+     */
+    public function postNewArticle(Request $request)
+    {
+        $published = $request->input('published');
+        if ($published == null) {
+            $published = '0';
+        }
+        //if a `.md` is attached use that for the main content.
+        $content = null; //set default value
+        if ($request->hasFile('article')) {
+            $file = $request->file('article')->openFile();
+            $content = $file->fread($file->getSize());
+        }
+        $main = $content ?? $request->input('main');
+        try {
+            $article = Article::create(
+                [
+                    'url' => $request->input('url'),
+                    'title' => $request->input('title'),
+                    'main' => $main,
+                    'published' => $published,
+                ]
+            );
+        } catch (Exception $e) {
+            $msg = $e->getMessage();
+            $unique = strpos($msg, '1062');
+            if ($unique !== false) {
+                //We've checked for error 1062, i.e. duplicate titleurl
+                return redirect('admin/blog/new')->withInput()->with('message', 'Duplicate title, please change');
+            }
+            //this isn't the error you're looking for
+            throw $e;
+        }
+
+        return view('admin.newarticlesuccess', ['id' => $article->id, 'title' => $article->title]);
+    }
+
+    /**
+     * Process an incoming request to edit an article.
+     *
+     * @param  string
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate|View\Factory view
+     */
+    public function postEditArticle($articleId, Request $request)
+    {
+        $published = $request->input('published');
+        if ($published == null) {
+            $published = '0';
+        }
+        $article = Article::find($articleId);
+        $article->title = $request->input('title');
+        $article->url = $request->input('url');
+        $article->main = $request->input('main');
+        $article->published = $published;
+        $article->save();
+
+        return view('admin.editarticlesuccess', ['id' => $articleId]);
+    }
+
+    /**
+     * Process a request to delete an aricle.
+     *
+     * @param  string The article id
+     * @return \Illuminate\View\Factory view
+     */
+    public function postDeleteArticle($articleId)
+    {
+        Article::where('id', $articleId)->delete();
+
+        return view('admin.deletearticlesuccess', ['id' => $articleId]);
+    }
+}
diff --git a/app/Http/Controllers/ArticlesController.php b/app/Http/Controllers/ArticlesController.php
new file mode 100644
index 00000000..95ee9453
--- /dev/null
+++ b/app/Http/Controllers/ArticlesController.php
@@ -0,0 +1,69 @@
+date($year, $month)
+                    ->orderBy('updated_at', 'desc')
+                    ->simplePaginate(5);
+
+        return view('multipost', ['data' => $articles]);
+    }
+
+    /**
+     * Show a single article.
+     *
+     * @return \Illuminate\View\Factory view
+     */
+    public function singleArticle($year, $month, $slug)
+    {
+        $article = Article::where('titleurl', $slug)->first();
+        if ($article->updated_at->year != $year || $article->updated_at->month != $month) {
+            throw new \Exception;
+        }
+
+        return view('singlepost', ['article' => $article]);
+    }
+
+    /**
+     * We only have the ID, work out post title, year and month
+     * and redirect to it.
+     *
+     * @return \Illuminte\Routing\RedirectResponse redirect
+     */
+    public function onlyIdInUrl($inURLId)
+    {
+        $numbers = new Numbers();
+        $realId = $numbers->b60tonum($inURLId);
+        $article = Article::findOrFail($realId);
+
+        return redirect($article->link);
+    }
+
+    /**
+     * Returns the RSS feed.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function makeRSS()
+    {
+        $articles = Article::where('published', '1')->orderBy('updated_at', 'desc')->get();
+        $buildDate = $articles->first()->updated_at->toRssString();
+        $contents = (string) view('rss', ['articles' => $articles, 'buildDate' => $buildDate]);
+
+        return (new Response($contents, '200'))->header('Content-Type', 'application/rss+xml');
+    }
+}
diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php
new file mode 100644
index 00000000..a100dd6e
--- /dev/null
+++ b/app/Http/Controllers/Auth/AuthController.php
@@ -0,0 +1,72 @@
+middleware($this->guestMiddleware(), ['except' => 'logout']);
+    }
+
+    /**
+     * Get a validator for an incoming registration request.
+     *
+     * @param  array  $data
+     * @return \Illuminate\Contracts\Validation\Validator
+     */
+    protected function validator(array $data)
+    {
+        return Validator::make($data, [
+            'name' => 'required|max:255',
+            'email' => 'required|email|max:255|unique:users',
+            'password' => 'required|min:6|confirmed',
+        ]);
+    }
+
+    /**
+     * Create a new user instance after a valid registration.
+     *
+     * @param  array  $data
+     * @return User
+     */
+    protected function create(array $data)
+    {
+        return User::create([
+            'name' => $data['name'],
+            'email' => $data['email'],
+            'password' => bcrypt($data['password']),
+        ]);
+    }
+}
diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php
new file mode 100644
index 00000000..1ceed97b
--- /dev/null
+++ b/app/Http/Controllers/Auth/PasswordController.php
@@ -0,0 +1,32 @@
+middleware('guest');
+    }
+}
diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php
new file mode 100644
index 00000000..f752fa21
--- /dev/null
+++ b/app/Http/Controllers/AuthController.php
@@ -0,0 +1,29 @@
+input('username') === env('ADMIN_USER')
+            &&
+            $request->input('password') === env('ADMIN_PASS')
+        ) {
+            session(['loggedin' => true]);
+
+            return redirect()->intended('admin');
+        }
+
+        return redirect()->route('login');
+    }
+}
diff --git a/app/Http/Controllers/ClientsAdminController.php b/app/Http/Controllers/ClientsAdminController.php
new file mode 100644
index 00000000..c374aa24
--- /dev/null
+++ b/app/Http/Controllers/ClientsAdminController.php
@@ -0,0 +1,87 @@
+ $clients]);
+    }
+
+    /**
+     * Show form to add a client name.
+     *
+     * @return \Illuminate\View\Factory view
+     */
+    public function newClient()
+    {
+        return view('admin.newclient');
+    }
+
+    /**
+     * Process the request to adda new client name.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\View\Factory view
+     */
+    public function postNewClient(Request $request)
+    {
+        Client::create([
+            'client_url' => $request->input('client_url'),
+            'client_name' => $request->input('client_name'),
+        ]);
+
+        return view('admin.newclientsuccess');
+    }
+
+    /**
+     * Show a form to edit a client name.
+     *
+     * @param  string The client id
+     * @return \Illuminate\View\Factory view
+     */
+    public function editClient($clientId)
+    {
+        $client = Client::findOrFail($clientId);
+
+        return view('admin.editclient', [
+            'id' => $clientId,
+            'client_url' => $client->client_url,
+            'client_name' => $client->client_name,
+        ]);
+    }
+
+    /**
+     * Process the request to edit a client name.
+     *
+     * @param  string  The client id
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\View\Factory view
+     */
+    public function postEditClient($clientId, Request $request)
+    {
+        $client = Client::findOrFail($clientId);
+        if ($request->input('edit')) {
+            $client->client_url = $request->input('client_url');
+            $client->client_name = $request->input('client_name');
+            $client->save();
+
+            return view('admin.editclientsuccess');
+        }
+        if ($request->input('delete')) {
+            $client->delete();
+
+            return view('admin.deleteclientsuccess');
+        }
+    }
+}
diff --git a/app/Http/Controllers/ContactsAdminController.php b/app/Http/Controllers/ContactsAdminController.php
new file mode 100644
index 00000000..890f1241
--- /dev/null
+++ b/app/Http/Controllers/ContactsAdminController.php
@@ -0,0 +1,166 @@
+ $contacts]);
+    }
+
+    /**
+     * Show the form to edit an existing contact.
+     *
+     * @param  string  The contact id
+     * @return \Illuminate\View\Factory view
+     */
+    public function editContact($contactId)
+    {
+        $contact = Contact::findOrFail($contactId);
+
+        return view('admin.editcontact', ['contact' => $contact]);
+    }
+
+    /**
+     * Show the form to confirm deleting a contact.
+     *
+     * @return \Illuminate\View\Factory view
+     */
+    public function deleteContact($contactId)
+    {
+        return view('admin.deletecontact', ['id' => $contactId]);
+    }
+
+    /**
+     * Process the request to add a new contact.
+     *
+     * @param  \Illuminate\Http|request $request
+     * @return \Illuminate\View\Factory view
+     */
+    public function postNewContact(Request $request)
+    {
+        $contact = new Contact();
+        $contact->name = $request->input('name');
+        $contact->nick = $request->input('nick');
+        $contact->homepage = $request->input('homepage');
+        $contact->twitter = $request->input('twitter');
+        $contact->save();
+        $contactId = $contact->id;
+
+        return view('admin.newcontactsuccess', ['id' => $contactId]);
+    }
+
+    /**
+     * Process the request to edit a contact.
+     *
+     * @todo   Allow saving profile pictures for people without homepages
+     *
+     * @param  string  The contact id
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\View\Factory view
+     */
+    public function postEditContact($contactId, Request $request)
+    {
+        $contact = Contact::findOrFail($contactId);
+        $contact->name = $request->input('name');
+        $contact->nick = $request->input('nick');
+        $contact->homepage = $request->input('homepage');
+        $contact->twitter = $request->input('twitter');
+        $contact->save();
+
+        if ($request->hasFile('avatar')) {
+            if ($request->input('homepage') != '') {
+                $dir = parse_url($request->input('homepage'))['host'];
+                $destination = public_path() . '/assets/profile-images/' . $dir;
+                $filesystem = new Filesystem();
+                if ($filesystem->isDirectory($destination) === false) {
+                    $filesystem->makeDirectory($destination);
+                }
+                $request->file('avatar')->move($destination, 'image');
+            }
+        }
+
+        return view('admin.editcontactsuccess');
+    }
+
+    /**
+     * Process the request to delete a contact.
+     *
+     * @param  string  The contact id
+     * @return \Illuminate\View\Factory view
+     */
+    public function postDeleteContact($contactId)
+    {
+        $contact = Contact::findOrFail($contactId);
+        $contact->delete();
+
+        return view('admin.deletecontactsuccess');
+    }
+
+    /**
+     * Download the avatar for a contact.
+     *
+     * This method attempts to find the microformat marked-up profile image
+     * from a given homepage and save it accordingly
+     *
+     * @param  string  The contact id
+     * @return \Illuminate\View\Factory view
+     */
+    public function getAvatar($contactId)
+    {
+        $contact = Contact::findOrFail($contactId);
+        $homepage = $contact->homepage;
+        if (($homepage !== null) && ($homepage !== '')) {
+            $client = new Client();
+            try {
+                $response = $client->get($homepage);
+                $html = (string) $response->getBody();
+                $mf2 = \Mf2\parse($html, $homepage);
+            } catch (\GuzzleHttp\Exception\BadResponseException $e) {
+                return "Bad Response from $homepage";
+            }
+            $avatarURL = null; // Initialising
+            foreach ($mf2['items'] as $microformat) {
+                if ($microformat['type'][0] == 'h-card') {
+                    $avatarURL = $microformat['properties']['photo'][0];
+                    break;
+                }
+            }
+            try {
+                $avatar = $client->get($avatarURL);
+            } catch (\GuzzleHttp\Exception\BadResponseException $e) {
+                return "Unable to get $avatarURL";
+            }
+            $directory = public_path() . '/assets/profile-images/' . parse_url($homepage)['host'];
+            $filesystem = new Filesystem();
+            if ($filesystem->isDirectory($directory) === false) {
+                $filesystem->makeDirectory($directory);
+            }
+            $filesystem->put($directory . '/image', $avatar->getBody());
+
+            return view('admin.getavatarsuccess', ['homepage' => parse_url($homepage)['host']]);
+        }
+    }
+}
diff --git a/app/Http/Controllers/ContactsController.php b/app/Http/Controllers/ContactsController.php
new file mode 100644
index 00000000..01528411
--- /dev/null
+++ b/app/Http/Controllers/ContactsController.php
@@ -0,0 +1,49 @@
+homepagePretty = parse_url($contact->homepage)['host'];
+            $file = public_path() . '/assets/profile-images/' . $contact->homepagePretty . '/image';
+            $contact->image = ($filesystem->exists($file)) ?
+                '/assets/profile-images/' . $contact->homepagePretty . '/image'
+            :
+                '/assets/profile-images/default-image';
+        }
+
+        return view('contacts', ['contacts' => $contacts]);
+    }
+
+    /**
+     * Show a single contact.
+     *
+     * @return \Illuminate\View\Factory view
+     */
+    public function showSingle($nick)
+    {
+        $filesystem = new Filesystem();
+        $contact = Contact::where('nick', '=', $nick)->firstOrFail();
+        $contact->homepagePretty = parse_url($contact->homepage)['host'];
+        $file = public_path() . '/assets/profile-images/' . $contact->homepagePretty . '/image';
+        $contact->image = ($filesystem->exists($file)) ?
+            '/assets/profile-images/' . $contact->homepagePretty . '/image'
+        :
+            '/assets/profile-images/default-image';
+
+        return view('contact', ['contact' => $contact]);
+    }
+}
diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php
new file mode 100644
index 00000000..d492e0b3
--- /dev/null
+++ b/app/Http/Controllers/Controller.php
@@ -0,0 +1,14 @@
+indieAuthService = $indieAuthService ?? new IndieAuthService();
+        $this->client = $client ?? new Client();
+        $this->tokenService = $tokenService ?? new TokenService();
+    }
+
+    /**
+     * Begin the indie auth process. This method ties in to the login page
+     * from our micropub client. Here we then query the user’s homepage
+     * for their authorisation endpoint, and redirect them there with a
+     * unique secure state value.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\Routing\RedirectResponse redirect
+     */
+    public function beginauth(Request $request)
+    {
+        $authorizationEndpoint = $this->indieAuthService->getAuthorizationEndpoint(
+            $request->input('me'),
+            $this->client
+        );
+        if ($authorizationEndpoint) {
+            $authorizationURL = $this->indieAuthService->buildAuthorizationURL(
+                $authorizationEndpoint,
+                $request->input('me'),
+                $this->client
+            );
+            if ($authorizationURL) {
+                return redirect($authorizationURL);
+            }
+        }
+
+        return redirect('/notes/new')->withErrors('Unable to determine authorisation endpoint', 'indieauth');
+    }
+
+    /**
+     * Once they have verified themselves through the authorisation endpint
+     * the next step is retreiveing a token from the token endpoint.
+     *
+     * @param  \Illuminate\Http\Rrequest $request
+     * @return \Illuminate\Routing\RedirectResponse redirect
+     */
+    public function indieauth(Request $request)
+    {
+        if ($request->session()->get('state') != $request->input('state')) {
+            return redirect('/notes/new')->withErrors(
+                'Invalid state value returned from indieauth server',
+                'indieauth'
+            );
+        }
+        $tokenEndpoint = $this->indieAuthService->getTokenEndpoint($request->input('me'), $this->client);
+        $redirectURL = config('app.url') . '/indieauth';
+        $clientId = config('app.url') . '/notes/new';
+        $data = [
+            'endpoint' => $tokenEndpoint,
+            'code' => $request->input('code'),
+            'me' => $request->input('me'),
+            'redirect_url' => $redirectURL,
+            'client_id' => $clientId,
+            'state' => $request->input('state'),
+        ];
+        $token = $this->indieAuthService->getAccessToken($data, $this->client);
+
+        if (array_key_exists('access_token', $token)) {
+            $request->session()->put('me', $token['me']);
+            $request->session()->put('token', $token['access_token']);
+
+            return redirect('/notes/new');
+        }
+
+        return redirect('/notes/new')->withErrors('Unable to get a token from the endpoint', 'indieauth');
+    }
+
+    /**
+     * If the user has auth’d via IndieAuth, issue a valid token.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\Http\Response
+     */
+    public function tokenEndpoint(Request $request)
+    {
+        $authData = [
+            'code' => $request->input('code'),
+            'me' => $request->input('me'),
+            'redirect_url' => $request->input('redirect_uri'),
+            'client_id' => $request->input('client_id'),
+            'state' => $request->input('state'),
+        ];
+        $auth = $this->indieAuthService->verifyIndieAuthCode($authData, $this->client);
+        if (array_key_exists('me', $auth)) {
+            $scope = $auth['scope'] ?? '';
+            $tokenData = [
+                'me' => $request->input('me'),
+                'client_id' => $request->input('client_id'),
+                'scope' => $auth['scope'],
+            ];
+            $token = $this->tokenService->getNewToken($tokenData);
+            $content = http_build_query([
+                'me' => $request->input('me'),
+                'scope' => $scope,
+                'access_token' => $token,
+            ]);
+
+            return (new Response($content, 200))
+                           ->header('Content-Type', 'application/x-www-form-urlencoded');
+        }
+        $content = 'There was an error verifying the authorisation code.';
+
+        return new Response($content, 400);
+    }
+
+    /**
+     * Log out the user, flush an session data, and overwrite any cookie data.
+     *
+     * @param  \Illuminate\Cookie\CookieJar $cookie
+     * @return \Illuminate\Routing\RedirectResponse redirect
+     */
+    public function indieauthLogout(Request $request, CookieJar $cookie)
+    {
+        $request->session()->flush();
+        $cookie->queue('me', 'loggedout', 5);
+
+        return redirect('/notes/new');
+    }
+}
diff --git a/app/Http/Controllers/MicropubClientController.php b/app/Http/Controllers/MicropubClientController.php
new file mode 100644
index 00000000..9978d985
--- /dev/null
+++ b/app/Http/Controllers/MicropubClientController.php
@@ -0,0 +1,333 @@
+indieAuthService = $indieAuthService ?? new IndieAuthService();
+        $this->guzzleClient = $guzzleClient ?? new GuzzleClient();
+        $this->indieClient = $indieClient ?? new IndieClient();
+    }
+
+    /**
+     * Display the new notes form.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\View\Factory view
+     */
+    public function newNotePage(Request $request)
+    {
+        $url = $request->session()->get('me');
+        $syndication = $this->parseSyndicationTargets(
+            $request->session()->get('syndication')
+        );
+
+        return view('micropubnewnotepage', [
+            'url' => $url,
+            'syndication' => $syndication,
+        ]);
+    }
+
+    /**
+     * Post the notes content to the relavent micropub API endpoint.
+     *
+     * @todo   make sure this works with multiple syndication targets
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @return mixed
+     */
+    public function postNewNote(Request $request)
+    {
+        $domain = $request->session()->get('me');
+        $token = $request->session()->get('token');
+
+        $micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint(
+            $domain,
+            $this->indieClient
+        );
+        if (! $micropubEndpoint) {
+            return redirect('notes/new')->withErrors('Unable to determine micropub API endpoint', 'endpoint');
+        }
+
+        $response = $this->postNoteRequest($request, $micropubEndpoint, $token);
+
+        if ($response->getStatusCode() == 201) {
+            $location = $response->getHeader('Location');
+            if (is_array($location)) {
+                return redirect($location[0]);
+            }
+
+            return redirect($location);
+        }
+
+        return redirect('notes/new')->withErrors('Endpoint didn’t create the note.', 'endpoint');
+    }
+
+    /**
+     * We make a request to the micropub endpoint requesting syndication targets
+     * and store them in the session.
+     *
+     * @todo better handling of response regarding mp-syndicate-to
+     *       and syndicate-to
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @param  \IndieAuth\Client $indieClient
+     * @param  \GuzzleHttp\Client $guzzleClient
+     * @return \Illuminate\Routing\Redirector redirect
+     */
+    public function refreshSyndicationTargets(Request $request)
+    {
+        $domain = $request->session()->get('me');
+        $token = $request->session()->get('token');
+        $micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
+
+        if (! $micropubEndpoint) {
+            return redirect('notes/new')->withErrors('Unable to determine micropub API endpoint', 'endpoint');
+        }
+
+        try {
+            $response = $this->guzzleClient->get($micropubEndpoint, [
+                'headers' => ['Authorization' => 'Bearer ' . $token],
+                'query' => ['q' => 'syndicate-to'],
+            ]);
+        } catch (\GuzzleHttp\Exception\BadResponseException $e) {
+            return redirect('notes/new')->withErrors('Bad response when refreshing syndication targets', 'endpoint');
+        }
+        $body = (string) $response->getBody();
+        $syndication = str_replace(['&', '[]'], [';', ''], $body);
+
+        $request->session()->put('syndication', $syndication);
+
+        return redirect('notes/new');
+    }
+
+    /**
+     * This method performs the actual POST request.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @param  string The Micropub endpoint to post to
+     * @param  string The token to authenticate the request with
+     * @return \GuzzleHttp\Response $response | \Illuminate\RedirectFactory redirect
+     */
+    private function postNoteRequest(
+        Request $request,
+        $micropubEndpoint,
+        $token
+    ) {
+        $multipart = [
+            [
+                'name' => 'h',
+                'contents' => 'entry',
+            ],
+            [
+                'name' => 'content',
+                'contents' => $request->input('content'),
+            ],
+        ];
+        if ($request->hasFile('photo')) {
+            $photos = $request->file('photo');
+            foreach ($photos as $photo) {
+                $filename = $photo->getClientOriginalName();
+                $photo->move(storage_path() . '/media-tmp', $filename);
+                $multipart[] = [
+                    'name' => 'photo[]',
+                    'contents' => fopen(storage_path() . '/media-tmp/' . $filename, 'r'),
+                ];
+            }
+        }
+        if ($request->input('in-reply-to') != '') {
+            $multipart[] = [
+                'name' => 'in-reply-to',
+                'contents' => $request->input('reply-to'),
+            ];
+        }
+        if ($request->input('mp-syndicate-to')) {
+            foreach ($request->input('mp-syndicate-to') as $syn) {
+                $multipart[] = [
+                    'name' => 'mp-syndicate-to',
+                    'contents' => $syn,
+                ];
+            }
+        }
+        if ($request->input('confirmlocation')) {
+            $latLng = $request->input('location');
+            $geoURL = 'geo:' . str_replace(' ', '', $latLng);
+            $multipart[] = [
+                'name' => 'location',
+                'contents' => $geoURL,
+            ];
+            if ($request->input('address') != '') {
+                $multipart[] = [
+                    'name' => 'place_name',
+                    'contents' => $request->input('address'),
+                ];
+            }
+        }
+        $headers = [
+            'Authorization' => 'Bearer ' . $token,
+        ];
+        try {
+            $response = $this->guzzleClient->post($micropubEndpoint, [
+                'multipart' => $multipart,
+                'headers' => $headers,
+            ]);
+        } catch (\GuzzleHttp\Exception\BadResponseException $e) {
+            return redirect('notes/new')
+                ->withErrors('There was a bad response from the micropub endpoint.', 'endpoint');
+        }
+
+        return $response;
+    }
+
+    /**
+     * Create a new place.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @return mixed
+     */
+    public function postNewPlace(Request $request)
+    {
+        $domain = $request->session()->get('me');
+        $token = $request->session()->get('token');
+
+        $micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
+        if (! $micropubEndpoint) {
+            return (new Response(json_encode([
+                'error' => true,
+                'message' => 'Could not determine the micropub endpoint.',
+            ]), 400))
+            ->header('Content-Type', 'application/json');
+        }
+
+        $place = $this->postPlaceRequest($request, $micropubEndpoint, $token);
+        if ($place === false) {
+            return (new Response(json_encode([
+                'error' => true,
+                'message' => 'Unable to create the new place',
+            ]), 400))
+            ->header('Content-Type', 'application/json');
+        }
+
+        return (new Response(json_encode([
+            'url' => $place,
+            'name' => $request->input('place-name'),
+            'latitude' => $request->input('place-latitude'),
+            'longitude' => $request->input('place-longitude'),
+        ]), 200))
+        ->header('Content-Type', 'application/json');
+    }
+
+    /**
+     * Actually make a micropub request to make a new place.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @param  string The Micropub endpoint to post to
+     * @param  string The token to authenticate the request with
+     * @param  \GuzzleHttp\Client $client
+     * @return \GuzzleHttp\Response $response | \Illuminate\RedirectFactory redirect
+     */
+    private function postPlaceRequest(
+        Request $request,
+        $micropubEndpoint,
+        $token
+    ) {
+        $formParams = [
+            'h' => 'card',
+            'name' => $request->input('place-name'),
+            'description' => $request->input('place-description'),
+            'geo' => 'geo:' . $request->input('place-latitude') . ',' . $request->input('place-longitude'),
+        ];
+        $headers = [
+            'Authorization' => 'Bearer ' . $token,
+        ];
+        try {
+            $response = $this->guzzleClient->request('POST', $micropubEndpoint, [
+                'form_params' => $formParams,
+                'headers' => $headers,
+            ]);
+        } catch (ClientException $e) {
+            //not sure yet...
+        }
+        if ($response->getStatusCode() == 201) {
+            return $response->getHeader('Location')[0];
+        }
+
+        return false;
+    }
+
+    /**
+     * Make a request to the micropub endpoint requesting any nearby places.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @param  string $latitude
+     * @param  string $longitude
+     * @return \Illuminate\Http\Response
+     */
+    public function nearbyPlaces(
+        Request $request,
+        $latitude,
+        $longitude
+    ) {
+        $domain = $request->session()->get('me');
+        $token = $request->session()->get('token');
+        $micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
+
+        if (! $micropubEndpoint) {
+            return;
+        }
+
+        try {
+            $response = $this->guzzleClient->get($micropubEndpoint, [
+                'headers' => ['Authorization' => 'Bearer ' . $token],
+                'query' => ['q' => 'geo:' . $latitude . ',' . $longitude],
+            ]);
+        } catch (\GuzzleHttp\Exception\BadResponseException $e) {
+            return;
+        }
+
+        return (new Response($response->getBody(), 200))
+                ->header('Content-Type', 'application/json');
+    }
+
+    /**
+     * Parse the syndication targets retreived from a cookie, to a form that can
+     * be used in a view.
+     *
+     * @param  string $syndicationTargets
+     * @return array|null
+     */
+    private function parseSyndicationTargets($syndicationTargets = null)
+    {
+        if ($syndicationTargets === null) {
+            return;
+        }
+        $mpSyndicateTo = [];
+        $parts = explode(';', $syndicationTargets);
+        foreach ($parts as $part) {
+            $target = explode('=', $part);
+            $mpSyndicateTo[] = urldecode($target[1]);
+        }
+        if (count($mpSyndicateTo) > 0) {
+            return $mpSyndicateTo;
+        }
+    }
+}
diff --git a/app/Http/Controllers/MicropubController.php b/app/Http/Controllers/MicropubController.php
new file mode 100644
index 00000000..1a941125
--- /dev/null
+++ b/app/Http/Controllers/MicropubController.php
@@ -0,0 +1,143 @@
+tokenService = $tokenService ?? new TokenService();
+        $this->noteService = $noteService ?? new NoteService();
+        $this->placeService = $placeService ?? new PlaceService();
+    }
+
+    /**
+     * This function receives an API request, verifies the authenticity
+     * then passes over the info to the relavent Service class.
+     *
+     * @param  \Illuminate\Http\Request request
+     * @return \Illuminate\Http\Response
+     */
+    public function post(Request $request)
+    {
+        $httpAuth = $request->header('Authorization');
+        if (preg_match('/Bearer (.+)/', $httpAuth, $match)) {
+            $token = $match[1];
+            $tokenData = $this->tokenService->validateToken($token);
+            if ($tokenData->hasClaim('scope')) {
+                $scopes = explode(' ', $tokenData->getClaim('scope'));
+                if (array_search('post', $scopes) !== false) {
+                    $clientId = $tokenData->getClaim('client_id');
+                    $type = $request->input('h');
+                    if ($type == 'entry') {
+                        $note = $this->noteService->createNote($request, $clientId);
+                        $content = 'Note created at ' . $note->longurl;
+
+                        return (new Response($content, 201))
+                                      ->header('Location', $note->longurl);
+                    }
+                    if ($type == 'card') {
+                        $place = $this->placeService->createPlace($request);
+                        $content = 'Place created at ' . $place->longurl;
+
+                        return (new Response($content, 201))
+                                      ->header('Location', $place->longurl);
+                    }
+                }
+            }
+            $content = http_build_query([
+                'error' => 'invalid_token',
+                'error_description' => 'The token provided is not valid or does not have the necessary scope',
+            ]);
+
+            return (new Response($content, 400))
+                          ->header('Content-Type', 'application/x-www-form-urlencoded');
+        }
+        $content = 'No OAuth token sent with request.';
+
+        return new Response($content, 400);
+    }
+
+    /**
+     * A GET request has been made to `api/post` with an accompanying
+     * token, here we check wether the token is valid and respond
+     * appropriately. Further if the request has the query parameter
+     * synidicate-to we respond with the known syndication endpoints.
+     *
+     * @todo   Move the syndication endpoints into a .env variable
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\Http\Response
+     */
+    public function getEndpoint(Request $request)
+    {
+        $httpAuth = $request->header('Authorization');
+        if (preg_match('/Bearer (.+)/', $httpAuth, $match)) {
+            $token = $match[1];
+            $valid = $this->tokenService->validateToken($token);
+
+            if ($valid === null) {
+                return new Response('Invalid token', 400);
+            }
+            //we have a valid token, is `syndicate-to` set?
+            if ($request->input('q') === 'syndicate-to') {
+                $content = http_build_query([
+                    'mp-syndicate-to' => 'twitter.com/jonnybarnes',
+                ]);
+
+                return (new Response($content, 200))
+                              ->header('Content-Type', 'application/x-www-form-urlencoded');
+            }
+            //nope, how about a geo URL?
+            if (substr($request->input('q'), 0, 4) === 'geo:') {
+                $geo = explode(':', $request->input('q'));
+                $latlng = explode(',', $geo[1]);
+                $latitude = $latlng[0];
+                $longitude = $latlng[1];
+                $places = Place::near($latitude, $longitude, 1000);
+
+                return (new Response(json_encode($places), 200))
+                        ->header('Content-Type', 'application/json');
+            }
+            //nope, just return the token
+            $content = http_build_query([
+                'me' => $valid->getClaim('me'),
+                'scope' => $valid->getClaim('scope'),
+                'client_id' => $valid->getClaim('client_id'),
+            ]);
+
+            return (new Response($content, 200))
+                          ->header('Content-Type', 'application/x-www-form-urlencoded');
+        }
+        $content = 'No OAuth token sent with request.';
+
+        return new Response($content, 400);
+    }
+}
diff --git a/app/Http/Controllers/NotesAdminController.php b/app/Http/Controllers/NotesAdminController.php
new file mode 100644
index 00000000..6fd48096
--- /dev/null
+++ b/app/Http/Controllers/NotesAdminController.php
@@ -0,0 +1,100 @@
+orderBy('id', 'desc')->get();
+        foreach ($notes as $note) {
+            $note->originalNote = $note->getOriginal('note');
+        }
+
+        return view('admin.listnotes', ['notes' => $notes]);
+    }
+
+    /**
+     * Display the form to edit a specific note.
+     *
+     * @param  string The note id
+     * @return \Illuminate\View\Factory view
+     */
+    public function editNotePage($noteId)
+    {
+        $note = Note::find($noteId);
+        $note->originalNote = $note->getOriginal('note');
+
+        return view('admin.editnote', ['id' => $noteId, 'note' => $note]);
+    }
+
+    /**
+     * Process a request to make a new note.
+     *
+     * @param Illuminate\Http\Request $request
+     * @todo  Sort this mess out
+     */
+    public function createNote(Request $request)
+    {
+        $validator = Validator::make(
+            $request->all(),
+            ['photo' => 'photosize'],
+            ['photosize' => 'At least one uploaded file exceeds size limit of 5MB']
+        );
+        if ($validator->fails()) {
+            return redirect('/admin/note/new')
+                ->withErrors($validator)
+                ->withInput();
+        }
+
+        $note = $this->noteService->createNote($request);
+
+        return view('admin.newnotesuccess', [
+            'id' => $note->id,
+            'shorturl' => $note->shorturl,
+        ]);
+    }
+
+    /**
+     * Process a request to edit a note. Easy since this can only be done
+     * from the admin CP.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @return \Illuminate\View\Factory view
+     */
+    public function editNote($noteId, Request $request)
+    {
+        //update note data
+        $note = Note::find($noteId);
+        $note->note = $request->input('content');
+        $note->in_reply_to = $request->input('in-reply-to');
+        $note->save();
+
+        if ($request->input('webmentions')) {
+            $wmc = new WebMentionsController();
+            $wmc->send($note);
+        }
+
+        return view('admin.editnotesuccess', ['id' => $noteId]);
+    }
+}
diff --git a/app/Http/Controllers/NotesController.php b/app/Http/Controllers/NotesController.php
new file mode 100644
index 00000000..2a5dcb3f
--- /dev/null
+++ b/app/Http/Controllers/NotesController.php
@@ -0,0 +1,240 @@
+with('webmentions', 'place')->simplePaginate(10);
+        foreach ($notes as $note) {
+            $replies = 0;
+            foreach ($note->webmentions as $webmention) {
+                if ($webmention->type == 'reply') {
+                    $replies = $replies + 1;
+                }
+            }
+            $note->replies = $replies;
+            $note->twitter = $this->checkTwitterReply($note->in_reply_to);
+            $note->iso8601_time = $note->updated_at->toISO8601String();
+            $note->human_time = $note->updated_at->diffForHumans();
+            if ($note->location && ($note->place === null)) {
+                $pieces = explode(':', $note->location);
+                $latlng = explode(',', $pieces[0]);
+                $note->latitude = trim($latlng[0]);
+                $note->longitude = trim($latlng[1]);
+                if (count($pieces) == 2) {
+                    $note->address = $pieces[1];
+                }
+            }
+            if ($note->place !== null) {
+                preg_match('/\((.*)\)/', $note->place->location, $matches);
+                $lnglat = explode(' ', $matches[1]);
+                $note->latitude = $lnglat[1];
+                $note->longitude = $lnglat[0];
+                $note->address = $note->place->name;
+                $note->placeLink = '/places/' . $note->place->slug;
+            }
+            $photoURLs = [];
+            $photos = $note->getMedia();
+            foreach ($photos as $photo) {
+                $photoURLs[] = $photo->getUrl();
+            }
+            $note->photoURLs = $photoURLs;
+        }
+
+        return view('allnotes', ['notes' => $notes]);
+    }
+
+    /**
+     * Show a single note.
+     *
+     * @param  string The id of the note
+     * @return \Illuminate\View\Factory view
+     */
+    public function singleNote($urlId)
+    {
+        $numbers = new Numbers();
+        $realId = $numbers->b60tonum($urlId);
+        $note = Note::find($realId);
+        $replies = [];
+        $reposts = [];
+        $likes = [];
+        foreach ($note->webmentions as $webmention) {
+            switch ($webmention->type) {
+                case 'reply':
+                    $content = unserialize($webmention->content);
+                    $content['source'] = $this->bridgyReply($webmention->source);
+                    $content['photo'] = $this->createPhotoLink($content['photo']);
+                    $content['date'] = $carbon->parse($content['date'])->toDayDateTimeString();
+                    $replies[] = $content;
+                    break;
+
+                case 'repost':
+                    $content = unserialize($webmention->content);
+                    $content['photo'] = $this->createPhotoLink($content['photo']);
+                    $content['date'] = $carbon->parse($content['date'])->toDayDateTimeString();
+                    $reposts[] = $content;
+                    break;
+
+                case 'like':
+                    $content = unserialize($webmention->content);
+                    $content['photo'] = $this->createPhotoLink($content['photo']);
+                    $likes[] = $content;
+                    break;
+            }
+        }
+        $note->twitter = $this->checkTwitterReply($note->in_reply_to);
+        $note->iso8601_time = $note->updated_at->toISO8601String();
+        $note->human_time = $note->updated_at->diffForHumans();
+        if ($note->location && ($note->place === null)) {
+            $pieces = explode(':', $note->location);
+            $latlng = explode(',', $pieces[0]);
+            $note->latitude = trim($latlng[0]);
+            $note->longitude = trim($latlng[1]);
+            if (count($pieces) == 2) {
+                $note->address = $pieces[1];
+            }
+        }
+        if ($note->place !== null) {
+            preg_match('/\((.*)\)/', $note->place->location, $matches);
+            $lnglat = explode(' ', $matches[1]);
+            $note->latitude = $lnglat[1];
+            $note->longitude = $lnglat[0];
+            $note->address = $note->place->name;
+            $note->placeLink = '/places/' . $note->place->slug;
+        }
+
+        $note->photoURLs = [];
+        foreach ($note->getMedia() as $photo) {
+            $note->photoURLs[] = $photo->getUrl();
+        }
+
+        return view('singlenote', [
+            'note' => $note,
+            'replies' => $replies,
+            'reposts' => $reposts,
+            'likes' => $likes,
+        ]);
+    }
+
+    /**
+     * Redirect /note/{decID} to /notes/{nb60id}.
+     *
+     * @param  string The decimal id of he note
+     * @return \Illuminate\Routing\RedirectResponse redirect
+     */
+    public function singleNoteRedirect($decId)
+    {
+        $numbers = new Numbers();
+        $realId = $numbers->numto60($decId);
+
+        $url = config('app.url') . '/notes/' . $realId;
+
+        return redirect($url);
+    }
+
+    /**
+     * Show all notes tagged with {tag}.
+     *
+     * @param  string The tag
+     * @return \Illuminate\View\Factory view
+     */
+    public function taggedNotes($tag)
+    {
+        $tagId = Tag::where('tag', $tag)->pluck('id');
+        $notes = Tag::find($tagId)->notes()->orderBy('updated_at', 'desc')->get();
+        foreach ($notes as $note) {
+            $note->iso8601_time = $note->updated_at->toISO8601String();
+            $note->human_time = $note->updated_at->diffForHumans();
+        }
+
+        return view('taggednotes', ['notes' => $notes, 'tag' => $tag]);
+    }
+
+    /**
+     * Swap a brid.gy URL shim-ing a twitter reply to a real twitter link.
+     *
+     * @param  string
+     * @return string
+     */
+    public function bridgyReply($source)
+    {
+        $url = $source;
+        if (mb_substr($source, 0, 28, 'UTF-8') == 'https://brid-gy.appspot.com/') {
+            $parts = explode('/', $source);
+            $tweetId = array_pop($parts);
+            if ($tweetId) {
+                $url = 'https://twitter.com/_/status/' . $tweetId;
+            }
+        }
+
+        return $url;
+    }
+
+    /**
+     * Create the photo link.
+     *
+     * @param  string
+     * @return string
+     */
+    public function createPhotoLink($url)
+    {
+        $host = parse_url($url)['host'];
+        if ($host != 'twitter.com' && $host != 'pbs.twimg.com') {
+            return '/assets/profile-images/' . $host . '/image';
+        }
+        if (mb_substr($url, 0, 20) == 'http://pbs.twimg.com') {
+            return str_replace('http://', 'https://', $url);
+        }
+    }
+
+    /**
+     * Twitter!!!
+     *
+     * @param  string  The reply to URL
+     * @return string | null
+     */
+    private function checkTwitterReply($url)
+    {
+        if ($url == null) {
+            return;
+        }
+
+        if (mb_substr($url, 0, 20, 'UTF-8') !== 'https://twitter.com/') {
+            return;
+        }
+
+        $arr = explode('/', $url);
+        $tweetId = end($arr);
+        if (Cache::has($tweetId)) {
+            return Cache::get($tweetId);
+        }
+        try {
+            $oEmbed = Twitter::getOembed([
+                'id' => $tweetId,
+                'align' => 'center',
+                'omit_script' => true,
+                'maxwidth' => 550,
+            ]);
+        } catch (\Exception $e) {
+            return;
+        }
+        Cache::put($tweetId, $oEmbed, ($oEmbed->cache_age / 60));
+
+        return $oEmbed;
+    }
+}
diff --git a/app/Http/Controllers/PhotosController.php b/app/Http/Controllers/PhotosController.php
new file mode 100644
index 00000000..9eaeb769
--- /dev/null
+++ b/app/Http/Controllers/PhotosController.php
@@ -0,0 +1,94 @@
+imageResizeLimit = 800;
+    }
+
+    /**
+     * Save an uploaded photo to the image folder.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  string  The associated note’s nb60 ID
+     * @return bool
+     */
+    public function saveImage(Request $request, $nb60id)
+    {
+        if ($request->hasFile('photo') !== true) {
+            return false;
+        }
+        $photoFilename = 'note-' . $nb60id;
+        $path = public_path() . '/assets/img/notes/';
+        $ext = $request->file('photo')->getClientOriginalExtension();
+        $photoFilename .= '.' . $ext;
+        $request->file('photo')->move($path, $photoFilename);
+
+        return true;
+    }
+
+    /**
+     * Prepare a photo for posting to twitter.
+     *
+     * @param  string  photo fileanme
+     * @return string  small photo filename, or null
+     */
+    public function makeSmallPhotoForTwitter($photoFilename)
+    {
+        $imagine = new Imagine();
+        $orig = $imagine->open(public_path() . '/assets/img/notes/' . $photoFilename);
+        $size = [$orig->getSize()->getWidth(), $orig->getSize()->getHeight()];
+        if ($size[0] > $this->imageResizeLimit || $size[1] > $this->imageResizeLimit) {
+            $filenameParts = explode('.', $photoFilename);
+            $preExt = count($filenameParts) - 2;
+            $filenameParts[$preExt] .= '-small';
+            $photoFilenameSmall = implode('.', $filenameParts);
+            $aspectRatio = $size[0] / $size[1];
+            $box = ($aspectRatio >= 1) ?
+                [$this->imageResizeLimit, (int) round($this->imageResizeLimit / $aspectRatio)]
+                :
+                [(int) round($this->imageResizeLimit * $aspectRatio), $this->imageResizeLimit];
+            $orig->resize(new Box($box[0], $box[1]))
+                 ->save(public_path() . '/assets/img/notes/' . $photoFilenameSmall);
+
+            return $photoFilenameSmall;
+        }
+    }
+
+    /**
+     * Get the image path for a note.
+     *
+     * @param  string $nb60id
+     * @return string | null
+     */
+    public function getPhotoPath($nb60id)
+    {
+        $filesystem = new Filesystem();
+        $photoDir = public_path() . '/assets/img/notes';
+        $files = $filesystem->files($photoDir);
+        foreach ($files as $file) {
+            $parts = explode('.', $file);
+            $name = $parts[0];
+            $dirs = explode('/', $name);
+            $actualname = last($dirs);
+            if ($actualname == 'note-' . $nb60id) {
+                $ext = $parts[1];
+            }
+        }
+        if (isset($ext)) {
+            return '/assets/img/notes/note-' . $nb60id . '.' . $ext;
+        }
+    }
+}
diff --git a/app/Http/Controllers/PlacesAdminController.php b/app/Http/Controllers/PlacesAdminController.php
new file mode 100644
index 00000000..24f492f9
--- /dev/null
+++ b/app/Http/Controllers/PlacesAdminController.php
@@ -0,0 +1,85 @@
+ $places]);
+    }
+
+    /**
+     * Show the form to make a new place.
+     *
+     * @return \Illuminate\View\Factory view
+     */
+    public function newPlacePage()
+    {
+        return view('admin.newplace');
+    }
+
+    /**
+     * Display the form to edit a specific place.
+     *
+     * @param  string The place id
+     * @return \Illuminate\View\Factory view
+     */
+    public function editPlacePage($placeId)
+    {
+        $place = Place::findOrFail($placeId);
+
+        $latitude = $place->getLatitude();
+        $longitude = $place->getLongitude();
+
+        return view('admin.editplace', [
+            'id' => $placeId,
+            'name' => $place->name,
+            'description' => $place->description,
+            'latitude' => $latitude,
+            'longitude' => $longitude,
+        ]);
+    }
+
+    /**
+     * Process a request to make a new place.
+     *
+     * @param  Illuminate\Http\Request $request
+     * @return Illuminate\View\Factory view
+     */
+    public function createPlace(Request $request)
+    {
+        $this->placeService->createPlace($request);
+
+        return view('admin.newplacesuccess');
+    }
+
+    /**
+     * Process a request to edit a place.
+     *
+     * @param string The place id
+     * @param Illuminate\Http\Request $request
+     * @return Illuminate\View\Factory view
+     */
+    public function editPlace($placeId, Request $request)
+    {
+        $place = Place::findOrFail($placeId);
+        $place->name = $request->name;
+        $place->description = $request->description;
+        $place->location = new Point((float) $request->latitude, (float) $request->longitude);
+        $place->save();
+
+        return view('admin.editplacesuccess');
+    }
+}
diff --git a/app/Http/Controllers/PlacesController.php b/app/Http/Controllers/PlacesController.php
new file mode 100644
index 00000000..d28a6852
--- /dev/null
+++ b/app/Http/Controllers/PlacesController.php
@@ -0,0 +1,89 @@
+ $places]);
+    }
+
+    /**
+     * Show the form for creating a new resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function create()
+    {
+        //
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  string  $slug
+     * @return \Illuminate\Http\Response
+     */
+    public function show($slug)
+    {
+        $place = Place::where('slug', '=', $slug)->first();
+
+        return view('singleplace', ['place' => $place]);
+    }
+
+    /**
+     * Show the form for editing the specified resource.
+     *
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function edit($id)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, $id)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy($id)
+    {
+        //
+    }
+}
diff --git a/app/Http/Controllers/ShortURLsController.php b/app/Http/Controllers/ShortURLsController.php
new file mode 100644
index 00000000..9c34ca0f
--- /dev/null
+++ b/app/Http/Controllers/ShortURLsController.php
@@ -0,0 +1,120 @@
+b60tonum($shortURLId);
+        $shorturl = ShortURL::find($num);
+        $redirect = $shorturl->redirect;
+
+        return redirect($redirect);
+    }
+
+    /**
+     * I had an old redirect systme breifly, but cool URLs should still work.
+     *
+     * @param  string URL ID
+     * @return \Illuminate\Routing\Redirector redirect
+     */
+    public function oldRedirect($shortURLId)
+    {
+        $filename = base_path() . '/public/assets/old-shorturls.json';
+        $handle = fopen($filename, 'r');
+        $contents = fread($handle, filesize($filename));
+        $object = json_decode($contents);
+
+        foreach ($object as $key => $val) {
+            if ($shortURLId == $key) {
+                return redirect($val);
+            }
+        }
+
+        return 'This id was never used.
+        Old redirects are located at
+        
+            old-shorturls.json
+        .';
+    }
+}
diff --git a/app/Http/Controllers/TokensController.php b/app/Http/Controllers/TokensController.php
new file mode 100644
index 00000000..5f896e80
--- /dev/null
+++ b/app/Http/Controllers/TokensController.php
@@ -0,0 +1,61 @@
+tokenService = $tokenService ?? new TokenService();
+    }
+
+    /**
+     * Show all the saved tokens.
+     *
+     * @return \Illuminate\View\Factory view
+     */
+    public function showTokens()
+    {
+        $tokens = $$his->tokenService->getAll();
+
+        return view('admin.listtokens', ['tokens' => $tokens]);
+    }
+
+    /**
+     * Show the form to delete a certain token.
+     *
+     * @param  string The token id
+     * @return \Illuminate\View\Factory view
+     */
+    public function deleteToken($tokenId)
+    {
+        return view('admin.deletetoken', ['id' => $tokenId]);
+    }
+
+    /**
+     * Process the request to delete a token.
+     *
+     * @param  string The token id
+     * @return \Illuminate\View\Factory view
+     */
+    public function postDeleteToken($tokenId)
+    {
+        $this->tokenService->deleteToken($tokenId);
+
+        return view('admin.deletetokensuccess', ['id' => $tokenId]);
+    }
+}
diff --git a/app/Http/Controllers/WebMentionsController.php b/app/Http/Controllers/WebMentionsController.php
new file mode 100644
index 00000000..ccffd451
--- /dev/null
+++ b/app/Http/Controllers/WebMentionsController.php
@@ -0,0 +1,100 @@
+has('target') !== true) || ($request->has('source') !== true)) {
+            return new Response(
+                'You need both the target and source parameters',
+                400
+            );
+        }
+
+        //next check the $target is valid
+        $path = parse_url($request->input('target'))['path'];
+        $pathParts = explode('/', $path);
+
+        switch ($pathParts[1]) {
+            case 'notes':
+                //we have a note
+                $noteId = $pathParts[2];
+                $numbers = new Numbers();
+                $realId = $numbers->b60tonum($noteId);
+                try {
+                    $note = Note::findOrFail($realId);
+                    $this->dispatch(new ProcessWebMention($note, $request->input('source')));
+                } catch (ModelNotFoundException $e) {
+                    return new Response('This note doesn’t exist.', 400);
+                }
+
+                return new Response(
+                    'Webmention received, it will be processed shortly',
+                    202
+                );
+                break;
+            case 'blog':
+                return new Response(
+                    'I don’t accept webmentions for blog posts yet.',
+                    501
+                );
+                break;
+            default:
+                return new Response(
+                    'Invalid request',
+                    400
+                );
+                break;
+        }
+    }
+
+    /**
+     * Send a webmention.
+     *
+     * @param  \App\Note  $note
+     * @return array   An array of successful then failed URLs
+     */
+    public function send(Note $note)
+    {
+        //grab the URLs
+        $urlsInReplyTo = explode(' ', $note->in_reply_to);
+        $urlsNote = $this->getLinks($note->note);
+        $urls = array_filter(array_merge($urlsInReplyTo, $urlsNote)); //filter out none URLs
+        foreach ($urls as $url) {
+            $this->dispatch(new SendWebMentions($url, $note->longurl));
+        }
+    }
+
+    /**
+     * Get the URLs from a note.
+     */
+    private function getLinks($html)
+    {
+        $urls = [];
+        $dom = new \DOMDocument();
+        $dom->loadHTML($html);
+        $anchors = $dom->getElementsByTagName('a');
+        foreach ($anchors as $anchor) {
+            $urls[] = ($anchor->hasAttribute('href')) ? $anchor->getAttribute('href') : false;
+        }
+
+        return $urls;
+    }
+}
diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php
new file mode 100644
index 00000000..ebad4d16
--- /dev/null
+++ b/app/Http/Kernel.php
@@ -0,0 +1,55 @@
+ [
+            \App\Http\Middleware\EncryptCookies::class,
+            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
+            \Illuminate\Session\Middleware\StartSession::class,
+            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
+            \App\Http\Middleware\VerifyCsrfToken::class,
+            \App\Http\Middleware\LinkHeadersMiddleware::class,
+        ],
+
+        'api' => [
+            'throttle:60,1',
+        ],
+    ];
+
+    /**
+     * The application's route middleware.
+     *
+     * These middleware may be assigned to groups or used individually.
+     *
+     * @var array
+     */
+    protected $routeMiddleware = [
+        'auth' => \App\Http\Middleware\Authenticate::class,
+        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
+        'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
+        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
+        'myauth' => \App\Http\Middleware\MyAuthMiddleware::class,
+        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
+    ];
+}
diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php
new file mode 100644
index 00000000..67abcaea
--- /dev/null
+++ b/app/Http/Middleware/Authenticate.php
@@ -0,0 +1,30 @@
+guest()) {
+            if ($request->ajax() || $request->wantsJson()) {
+                return response('Unauthorized.', 401);
+            } else {
+                return redirect()->guest('login');
+            }
+        }
+
+        return $next($request);
+    }
+}
diff --git a/app/Http/Middleware/EncryptCookies.php b/app/Http/Middleware/EncryptCookies.php
new file mode 100644
index 00000000..3aa15f8d
--- /dev/null
+++ b/app/Http/Middleware/EncryptCookies.php
@@ -0,0 +1,17 @@
+header('Link', '; rel="authorization_endpoint"', false);
+        $response->header('Link', config('app.url') . '/api/token>; rel="token_endpoint"', false);
+        $response->header('Link', config('app.url') . '/api/post>; rel="micropub"', false);
+        $response->header('Link', config('app.url') . '/webmention>; rel="webmention"', false);
+
+        return $response;
+    }
+}
diff --git a/app/Http/Middleware/MyAuthMiddleware.php b/app/Http/Middleware/MyAuthMiddleware.php
new file mode 100644
index 00000000..5354e55b
--- /dev/null
+++ b/app/Http/Middleware/MyAuthMiddleware.php
@@ -0,0 +1,25 @@
+session()->has('loggedin') !== true) {
+            //they’re not logged in, so send them to login form
+            return redirect()->route('login');
+        }
+
+        return $next($request);
+    }
+}
diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php
new file mode 100644
index 00000000..e27860e2
--- /dev/null
+++ b/app/Http/Middleware/RedirectIfAuthenticated.php
@@ -0,0 +1,26 @@
+check()) {
+            return redirect('/');
+        }
+
+        return $next($request);
+    }
+}
diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php
new file mode 100644
index 00000000..c8545185
--- /dev/null
+++ b/app/Http/Middleware/VerifyCsrfToken.php
@@ -0,0 +1,20 @@
+ config('url.longurl')], function () {
+    //Static homepage
+    Route::get('/', function () {
+        return view('homepage');
+    });
+
+    //Static project page
+    Route::get('projects', function () {
+        return view('projects');
+    });
+
+    //The login routes to get authe'd for admin
+    Route::get('login', ['as' => 'login', function () {
+        return view('login');
+    }]);
+    Route::post('login', 'AuthController@login');
+
+    //Admin pages grouped for filter
+    Route::group(['middleware' => 'myauth'], function () {
+        Route::get('admin', 'AdminController@showWelcome');
+
+        //Articles
+        Route::get('admin/blog/new', 'ArticlesAdminController@newArticle');
+        Route::get('admin/blog/edit', 'ArticlesAdminController@listArticles');
+        Route::get('admin/blog/edit/{id}', 'ArticlesAdminController@editArticle');
+        Route::get('admin/blog/delete/{id}', 'ArticlesAdminController@deleteArticle');
+        Route::post('admin/blog/new', 'ArticlesAdminController@postNewArticle');
+        Route::post('admin/blog/edit/{id}', 'ArticlesAdminController@postEditArticle');
+        Route::post('admin/blog/delete/{id}', 'ArticlesAdminController@postDeleteArticle');
+
+        //Notes
+        Route::get('admin/note/new', 'NotesAdminController@newNotePage');
+        Route::get('admin/note/edit', 'NotesAdminController@listNotesPage');
+        Route::get('admin/note/edit/{id}', 'NotesAdminController@editNotePage');
+        Route::post('admin/note/new', 'NotesAdminController@createNote');
+        Route::post('admin/note/edit/{id}', 'NotesAdminController@editNote');
+
+        //Tokens
+        Route::get('admin/tokens', 'TokensController@showTokens');
+        Route::get('admin/tokens/delete/{id}', 'TokensController@deleteToken');
+        Route::post('admin/tokens/delete/{id}', 'TokensController@postDeleteToken');
+
+        //Micropub Clients
+        Route::get('admin/clients', 'ClientsAdminController@listClients');
+        Route::get('admin/clients/new', 'ClientsAdminController@newClient');
+        Route::get('admin/clients/edit/{id}', 'ClientsAdminController@editClient');
+        Route::post('admin/clients/new', 'ClientsAdminController@postNewClient');
+        Route::post('admin/clients/edit/{id}', 'ClientsAdminController@postEditClient');
+
+        //Contacts
+        Route::get('admin/contacts/new', 'ContactsAdminController@newContact');
+        Route::get('admin/contacts/edit', 'ContactsAdminController@listContacts');
+        Route::get('admin/contacts/edit/{id}', 'ContactsAdminController@editContact');
+        Route::get('admin/contacts/edit/{id}/getavatar', 'ContactsAdminController@getAvatar');
+        Route::get('admin/contacts/delete/{id}', 'ContactsAdminController@deleteContact');
+        Route::post('admin/contacts/new', 'ContactsAdminController@postNewContact');
+        Route::post('admin/contacts/edit/{id}', 'ContactsAdminController@postEditContact');
+        Route::post('admin/contacts/delete/{id}', 'ContactsAdminController@postDeleteContact');
+
+        //Places
+        Route::get('admin/places/new', 'PlacesAdminController@newPlacePage');
+        Route::get('admin/places/edit', 'PlacesAdminController@listPlacesPage');
+        Route::get('admin/places/edit/{id}', 'PlacesAdminController@editPlacePage');
+        Route::post('admin/places/new', 'PlacesAdminController@createPlace');
+        Route::post('admin/places/edit/{id}', 'PlacesAdminController@editPlace');
+    });
+
+    //Blog pages using ArticlesController
+    Route::get('blog/s/{id}', 'ArticlesController@onlyIdInURL');
+    Route::get('blog/{year?}/{month?}', 'ArticlesController@showAllArticles');
+    Route::get('blog/{year}/{month}/{slug}', 'ArticlesController@singleArticle');
+
+    //micropub new notes page
+    //this needs to be first so `notes/new` doesn't match `notes/{id}`
+    Route::get('notes/new', 'MicropubClientController@newNotePage');
+    Route::post('notes/new', 'MicropubClientController@postNewNote');
+
+    //Notes pages using NotesController
+    Route::get('notes', 'NotesController@showNotes');
+    Route::get('note/{id}', 'NotesController@singleNoteRedirect');
+    Route::get('notes/{id}', 'NotesController@singleNote');
+    Route::get('notes/tagged/{tag}', 'NotesController@taggedNotes');
+
+    //indieauth
+    Route::any('beginauth', 'IndieAuthController@beginauth');
+    Route::get('indieauth', 'IndieAuthController@indieauth');
+    Route::post('api/token', 'IndieAuthController@tokenEndpoint');
+    Route::get('logout', 'IndieAuthController@indieauthLogout');
+
+    //micropub endoints
+    Route::post('api/post', 'MicropubController@post');
+    Route::get('api/post', 'MicropubController@getEndpoint');
+
+    //micropub refresh syndication targets
+    Route::get('refresh-syndication-targets', 'MicropubClientController@refreshSyndicationTargets');
+
+    //webmention
+    Route::get('webmention', function () {
+        return view('webmention-endpoint');
+    });
+    Route::post('webmention', 'WebMentionsController@receive');
+
+    //Contacts
+    Route::get('contacts', 'ContactsController@showAll');
+    Route::get('contacts/{nick}', 'ContactsController@showSingle');
+
+    //Places
+    Route::get('places', 'PlacesController@index');
+    Route::get('places/{slug}', 'PlacesController@show');
+    //Places micropub
+    Route::get('places/near/{lat}/{lng}', 'MicropubClientController@nearbyPlaces');
+    Route::post('places/new', 'MicropubClientController@postNewPlace');
+
+    Route::get('feed', 'ArticlesController@makeRSS');
+});
+
+//Short URL
+Route::group(['domain' => config('url.shorturl')], function () {
+    Route::get('/', 'ShortURLsController@baseURL');
+    Route::get('@', 'ShortURLsController@twitter');
+    Route::get('+', 'ShortURLsController@googlePlus');
+    Route::get('α', 'ShortURLsController@appNet');
+
+    Route::get('{type}/{id}', 'ShortURLsController@expandType')->where(
+        [
+            'type' => '[bt]',
+            'id' => '[0-9A-HJ-NP-Z_a-km-z]+',
+        ]
+    );
+
+    Route::get('h/{id}', 'ShortURLsController@redirect');
+    Route::get('{id}', 'ShortURLsController@oldRedirect')->where(
+        [
+            'id' => '[0-9A-HJ-NP-Z_a-km-z]{4}',
+        ]
+    );
+});
diff --git a/app/Jobs/Job.php b/app/Jobs/Job.php
new file mode 100644
index 00000000..55ece29a
--- /dev/null
+++ b/app/Jobs/Job.php
@@ -0,0 +1,21 @@
+note = $note;
+        $this->source = $source;
+    }
+
+    /**
+     * Execute the job.
+     *
+     * @param  \Jonnybarnes\WebmentionsParser\Parser $parser
+     * @return void
+     */
+    public function handle(Parser $parser)
+    {
+        $sourceURL = parse_url($this->source);
+        $baseURL = $sourceURL['scheme'] . '://' . $sourceURL['host'];
+        $remoteContent = $this->getRemoteContent($this->source);
+        $microformats = $this->parseHTML($remoteContent, $baseURL);
+        $count = WebMention::where('source', '=', $this->source)->count();
+        if ($count > 0) {
+            //we already have a webmention from this source
+            $webmentions = WebMention::where('source', '=', $this->source)->get();
+            foreach ($webmentions as $webmention) {
+                //now check it still 'mentions' this target
+                //we switch for each type of mention (reply/like/repost)
+                switch ($webmention->type) {
+                    case 'reply':
+                        if ($parser->checkInReplyTo($microformats, $note->longurl) == false) {
+                            //it doesn't so delete
+                            $webmention->delete();
+
+                            return true;
+                        }
+                        //webmenion is still a reply, so update content
+                        $content = $parser->replyContent($microformats);
+                        $this->saveImage($content);
+                        $content['reply'] = $this->filterHTML($content['reply']);
+                        $content = serialize($content);
+                        $webmention->content = $content;
+                        $webmention->save();
+
+                        return true;
+                        break;
+                    case 'like':
+                        if ($parser->checkLikeOf($microformats, $note->longurl) == false) {
+                            //it doesn't so delete
+                            $webmention->delete();
+
+                            return true;
+                        } //note we don't need to do anything if it still is a like
+                        break;
+                    case 'repost':
+                        if ($parser->checkRepostOf($microformats, $note->longurl) == false) {
+                            //it doesn't so delete
+                            $webmention->delete();
+
+                            return true;
+                        } //again, we don't need to do anything if it still is a repost
+                        break;
+                }//switch
+            }//foreach
+        }//if
+        //no wemention in db so create new one
+        $webmention = new WebMention();
+        //check it is in fact a reply
+        if ($parser->checkInReplyTo($microformats, $note->longurl)) {
+            $content = $parser->replyContent($microformats);
+            $this->saveImage($content);
+            $content['reply'] = $this->filterHTML($content['reply']);
+            $content = serialize($content);
+            $webmention->source = $this->source;
+            $webmention->target = $note->longurl;
+            $webmention->commentable_id = $this->note->id;
+            $webmention->commentable_type = 'App\Note';
+            $webmention->type = 'reply';
+            $webmention->content = $content;
+            $webmention->save();
+
+            return true;
+        } elseif ($parser->checkLikeOf($microformats, $note->longurl)) {
+            //it is a like
+            $content = $parser->likeContent($microformats);
+            $this->saveImage($content);
+            $content = serialize($content);
+            $webmention->source = $this->source;
+            $webmention->target = $note->longurl;
+            $webmention->commentable_id = $this->note->id;
+            $webmention->commentable_type = 'App\Note';
+            $webmention->type = 'like';
+            $webmention->content = $content;
+            $webmention->save();
+
+            return true;
+        } elseif ($parser->checkRepostOf($microformats, $note->longurl)) {
+            //it is a repost
+            $content = $parser->repostContent($microformats);
+            $this->saveImage($content);
+            $content = serialize($content);
+            $webmention->source = $this->source;
+            $webmention->target = $note->longurl;
+            $webmention->commentable_id = $this->note->id;
+            $webmention->commentable_type = 'App\Note';
+            $webmention->type = 'repost';
+            $webmention->content = $content;
+            $webmention->save();
+
+            return true;
+        }
+    }
+
+    /**
+     * Retreive the remote content from a URL, and caches the result.
+     *
+     * @param  string  The URL to retreive content from
+     * @return string  The HTML from the URL
+     */
+    private function getRemoteContent($url)
+    {
+        $client = new Client();
+
+        $response = $client->get($url);
+        $html = (string) $response->getBody();
+        $path = storage_path() . '/HTML/' . $this->createFilenameFromURL($url);
+        $this->fileForceContents($path, $html);
+
+        return $html;
+    }
+
+    /**
+     * Create a file path from a URL. This is used when caching the HTML
+     * response.
+     *
+     * @param  string  The URL
+     * @return string  The path name
+     */
+    private function createFilenameFromURL($url)
+    {
+        $url = str_replace(['https://', 'http://'], ['', ''], $url);
+        if (substr($url, -1) == '/') {
+            $url = $url . 'index.html';
+        }
+
+        return $url;
+    }
+
+    /**
+     * Save a file, and create any necessary folders.
+     *
+     * @param string  The directory to save to
+     * @param binary  The file to save
+     */
+    private function fileForceContents($dir, $contents)
+    {
+        $parts = explode('/', $dir);
+        $name = array_pop($parts);
+        $dir = implode('/', $parts);
+        if (! is_dir($dir)) {
+            mkdir($dir, 0755, true);
+        }
+        file_put_contents("$dir/$name", $contents);
+    }
+
+    /**
+     * A wrapper function for php-mf2’s parse method.
+     *
+     * @param  string  The HTML to parse
+     * @param  string  The base URL to resolve relative URLs in the HTML against
+     * @return array   The porcessed microformats
+     */
+    private function parseHTML($html, $baseurl)
+    {
+        $microformats = \Mf2\parse((string) $html, $baseurl);
+
+        return $microformats;
+    }
+
+    /**
+     * Save a profile image to the local cache.
+     *
+     * @param  array  source content
+     * @return bool   wether image was saved or not (we don’t save twitter profiles)
+     */
+    public function saveImage(array $content)
+    {
+        $photo = $content['photo'];
+        $home = $content['url'];
+        //dont save pbs.twimg.com links
+        if (parse_url($photo)['host'] != 'pbs.twimg.com'
+              && parse_url($photo)['host'] != 'twitter.com') {
+            $client = new Client();
+            try {
+                $response = $client->get($photo);
+                $image = $response->getBody(true);
+                $path = public_path() . '/assets/profile-images/' . parse_url($home)['host'] . '/image';
+                $this->fileForceContents($path, $image);
+            } catch (Exception $e) {
+                // we are openning and reading the default image so that
+                // fileForceContent work
+                $default = public_path() . '/assets/profile-images/default-image';
+                $handle = fopen($default, 'rb');
+                $image = fread($handle, filesize($default));
+                fclose($handle);
+                $path = public_path() . '/assets/profile-images/' . parse_url($home)['host'] . '/image';
+                $this->fileForceContents($path, $image);
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Purify HTML received from a webmention.
+     *
+     * @param  string  The HTML to be processed
+     * @return string  The processed HTML
+     */
+    public function filterHTML($html)
+    {
+        $config = HTMLPurifier_Config::createDefault();
+        $config->set('Cache.SerializerPath', storage_path() . '/HTMLPurifier');
+        $purifier = new HTMLPurifier($config);
+
+        return $purifier->purify($html);
+    }
+}
diff --git a/app/Jobs/SendWebMentions.php b/app/Jobs/SendWebMentions.php
new file mode 100644
index 00000000..796fc97c
--- /dev/null
+++ b/app/Jobs/SendWebMentions.php
@@ -0,0 +1,86 @@
+url = $url;
+        $this->source = $source;
+    }
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     */
+    public function handle(Client $client)
+    {
+        $endpoint = $this->discoverWebmentionEndpoint($this->url, $client);
+        if ($endpoint) {
+            $client->post($endpoint, [
+                'form_params' => [
+                    'source' => $this->source,
+                    'target' => $this->url,
+                ],
+            ]);
+        }
+    }
+
+    /**
+     * Discover if a URL has a webmention endpoint.
+     *
+     * @param  string  The URL
+     * @param  \GuzzleHttp\Client $client
+     * @return string  The webmention endpoint URL
+     */
+    private function discoverWebmentionEndpoint($url, $client)
+    {
+        $endpoint = null;
+
+        $response = $client->get($url);
+        //check HTTP Headers for webmention endpoint
+        $links = \GuzzleHttp\Psr7\parse_header($response->getHeader('Link'));
+        foreach ($links as $link) {
+            if ($link['rel'] == 'webmention') {
+                return trim($link[0], '<>');
+            }
+        }
+
+        //failed to find a header so parse HTML
+        $html = (string) $response->getBody();
+
+        $mf2 = new \Mf2\Parser($html, $url);
+        $rels = $mf2->parseRelsAndAlternates();
+        if (array_key_exists('webmention', $rels[0])) {
+            $endpoint = $rels[0]['webmention'][0];
+        } elseif (array_key_exists('http://webmention.org/', $rels[0])) {
+            $endpoint = $rels[0]['http://webmention.org/'][0];
+        }
+        if ($endpoint) {
+            if (filter_var($endpoint, FILTER_VALIDATE_URL)) {
+                return $endpoint;
+            }
+            //it must be a relative url, so resolve with php-mf2
+            return $mf2->resolveUrl($endpoint);
+        }
+
+        return false;
+    }
+}
diff --git a/app/Jobs/SyndicateToTwitter.php b/app/Jobs/SyndicateToTwitter.php
new file mode 100644
index 00000000..377932f7
--- /dev/null
+++ b/app/Jobs/SyndicateToTwitter.php
@@ -0,0 +1,108 @@
+note = $note;
+    }
+
+    /**
+     * Execute the job.
+     *
+     * @param  \Jonnybarnes\IndieWeb\Numbers $numbers
+     * @param  \Jonnybarnes\IndieWeb\NotePrep $noteprep
+     * @return void
+     */
+    public function handle(Numbers $numbers, NotePrep $noteprep)
+    {
+        $noteSwappedNames = $this->swapNames($this->note->getOriginal('note'));
+        $shorturl = 'https://' . config('url.shorturl') . '/t/' . $numbers->numto60($this->note->id);
+        $tweet = $noteprep->createNote($noteSwappedNames, $shorturl, 140, true);
+        $tweetOpts = ['status' => $tweet, 'format' => 'json'];
+        if ($this->note->in_reply_to) {
+            $tweetOpts['in_reply_to_status_id'] = $noteprep->replyTweetId($this->note->in_reply_to);
+        }
+
+        /*if ($this->note->location) {
+            $explode = explode(':', $this->note->location);
+            $location = (count($explode) == 2) ? explode(',', $explode[0]) : explode(',', $explode);
+            $lat = trim($location[0]);
+            $long = trim($location[1]);
+            $jsonPlaceId = Twitter::getGeoReverse(array('lat' => $lat, 'long' => $long, 'format' => 'json'));
+            $parsePlaceId = json_decode($jsonPlaceId);
+            $placeId = $parsePlaceId->result->places[0]->id ?: null;
+            $tweetOpts['lat'] = $lat;
+            $tweetOpts['long'] = $long;
+            if ($placeId) {
+                $tweetOpts['place_id'] = $placeId;
+            }
+        }*/
+
+        $mediaItems = $this->note->getMedia();
+        if (count($mediaItems) > 0) {
+            foreach ($mediaItems as $item) {
+                $uploadedMedia = Twitter::uploadMedia(['media' => file_get_contents($item->getUrl())]);
+                $mediaIds[] = $uploadedMedia->media_id_string;
+            }
+            $tweetOpts['media_ids'] = implode(',', $mediaIds);
+        }
+
+        $responseJson = Twitter::postTweet($tweetOpts);
+        $response = json_decode($responseJson);
+        $tweetId = $response->id;
+        $this->note->tweet_id = $tweetId;
+        $this->note->save();
+    }
+
+    /**
+     * Swap @names in a note.
+     *
+     * When a note is being saved and we are posting it to twitter, we want
+     * to swap our @local_name to Twitter’s @twitter_name so the user get’s
+     * mentioned on Twitter.
+     *
+     * @param  string $note
+     * @return string $noteSwappedNames
+     */
+    private function swapNames($note)
+    {
+        $regex = '/\[.*?\](*SKIP)(*F)|@(\w+)/'; //match @alice but not [@bob](...)
+        $noteSwappedNames = preg_replace_callback(
+            $regex,
+            function ($matches) {
+                try {
+                    $contact = Contact::where('nick', '=', mb_strtolower($matches[1]))->firstOrFail();
+                } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
+                    return '@' . $matches[1];
+                }
+                $twitterHandle = $contact->twitter;
+
+                return '@' . $twitterHandle;
+            },
+            $note
+        );
+
+        return $noteSwappedNames;
+    }
+}
diff --git a/app/Listeners/.gitkeep b/app/Listeners/.gitkeep
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/app/Listeners/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/app/Note.php b/app/Note.php
new file mode 100644
index 00000000..29213e14
--- /dev/null
+++ b/app/Note.php
@@ -0,0 +1,230 @@
+belongsToMany('App\Tag');
+    }
+
+    /**
+     * Define the relationship with webmentions.
+     *
+     * @var array
+     */
+    public function webmentions()
+    {
+        return $this->morphMany('App\WebMention', 'commentable');
+    }
+
+    /**
+     * Definte the relationship with places.
+     *
+     * @var array
+     */
+    public function place()
+    {
+        return $this->belongsTo('App\Place');
+    }
+
+    /**
+     * We shall set a blacklist of non-modifiable model attributes.
+     *
+     * @var array
+     */
+    protected $guarded = ['id'];
+
+    /**
+     * The attributes that should be mutated to dates.
+     *
+     * @var array
+     */
+    protected $dates = ['deleted_at'];
+
+    /**
+     * A mutator to ensure that in-reply-to is always non-empty or null.
+     *
+     * @param  string  value
+     * @return string
+     */
+    public function setInReplyToAttribute($value)
+    {
+        $this->attributes['in_reply_to'] = empty($value) ? null : $value;
+    }
+
+    /**
+     * Normalize the note to Unicode FORM C.
+     *
+     * @param  string  $value
+     * @return string
+     */
+    public function setNoteAttribute($value)
+    {
+        $this->attributes['note'] = normalizer_normalize($value, Normalizer::FORM_C);
+    }
+
+    /**
+     * Pre-process notes for web-view.
+     *
+     * @param  string
+     * @return string
+     */
+    public function getNoteAttribute($value)
+    {
+        $unicode = new UnicodeTools();
+        $codepoints = $unicode->convertUnicodeCodepoints($value);
+        $markdown = new CommonMarkConverter();
+        $html = $markdown->convertToHtml($codepoints);
+        $hcards = $this->makeHCards($html);
+        $hashtags = $this->autoLinkHashtag($hcards);
+
+        return $hashtags;
+    }
+
+    /**
+     * Generate the NewBase60 ID from primary ID.
+     *
+     * @return string
+     */
+    public function getNb60idAttribute()
+    {
+        $numbers = new Numbers();
+
+        return $numbers->numto60($this->id);
+    }
+
+    /**
+     * The Long URL for a note.
+     *
+     * @return string
+     */
+    public function getLongurlAttribute()
+    {
+        return config('app.url') . '/notes/' . $this->nb60id;
+    }
+
+    /**
+     * The Short URL for a note.
+     *
+     * @return string
+     */
+    public function getShorturlAttribute()
+    {
+        return config('app.shorturl') . '/notes/' . $this->nb60id;
+    }
+
+    /**
+     * Get the relavent client name assocaited with the client id.
+     *
+     * @return string|null
+     */
+    public function getClientNameAttribute()
+    {
+        if ($this->client_id == null) {
+            return;
+        }
+        $name = Client::where('client_url', $this->client_id)->value('client_name');
+        if ($name == null) {
+            $url = parse_url($this->client_id);
+            if (isset($url['path'])) {
+                return $url['host'] . $url['path'];
+            }
+
+            return $url['host'];
+        }
+
+        return $name;
+    }
+
+    /**
+     * Take note that this method does two things, given @username (NOT [@username](URL)!)
+     * we try to create a fancy hcard from our contact info. If this is not possible
+     * due to lack of contact info, we assume @username is a twitter handle and link it
+     * as such.
+     *
+     * @param  string  The note’s text
+     * @return string
+     */
+    private function makeHCards($text)
+    {
+        $regex = '/\[.*?\](*SKIP)(*F)|@(\w+)/'; //match @alice but not [@bob](...)
+        $hcards = preg_replace_callback(
+            $regex,
+            function ($matches) {
+                try {
+                    $contact = Contact::where('nick', '=', mb_strtolower($matches[1]))->firstOrFail();
+                } catch (ModelNotFoundException $e) {
+                    return '' . $matches[0] . '';
+                }
+                $path = parse_url($contact->homepage)['host'];
+                $contact->photo = (file_exists(public_path() . '/assets/profile-images/' . $path . '/image')) ?
+                    '/assets/profile-images/' . $path . '/image'
+                :
+                    '/assets/profile-images/default-image';
+
+                return trim(view('mini-hcard-template', ['contact' => $contact])->render());
+            },
+            $text
+        );
+
+        return $hcards;
+    }
+
+    /**
+     * Given a string and section, finds all hashtags matching
+     * `#[\-_a-zA-Z0-9]+` and wraps them in an `a` element with
+     * `rel=tag` set and a `href` of 'section/tagged/' + tagname without the #.
+     *
+     * @param  string  The note
+     * @return string
+     */
+    private function autoLinkHashtag($text)
+    {
+        // $replacements = ["#tag" => "]
+        $replacements = [];
+        $matches = [];
+
+        if (preg_match_all('/(?<=^|\s)\#([a-zA-Z0-9\-\_]+)/i', $text, $matches, PREG_PATTERN_ORDER)) {
+            // Look up #tags, get Full name and URL
+            foreach ($matches[0] as $name) {
+                $name = str_replace('#', '', $name);
+                $replacements[$name] =
+                  '';
+            }
+
+            // Replace #tags with valid microformat-enabled link
+            foreach ($replacements as $name => $replacement) {
+                $text = str_replace('#' . $name, $replacement, $text);
+            }
+        }
+
+        return $text;
+    }
+}
diff --git a/app/Place.php b/app/Place.php
new file mode 100644
index 00000000..8cadf966
--- /dev/null
+++ b/app/Place.php
@@ -0,0 +1,133 @@
+hasMany('App\Note');
+    }
+
+    /**
+     * Get all places within a specified distance.
+     *
+     * @param  float latitude
+     * @param  float longitude
+     * @param  int maximum distance
+     * @todo Check this shit.
+     */
+    public static function near(float $lat, float $lng, int $distance)
+    {
+        $point = $lng . ' ' . $lat;
+        $distace = $distance ?? 1000;
+        $places = DB::select(DB::raw("select
+            name,
+            slug,
+            ST_AsText(location) AS location,
+            ST_Distance(
+                ST_GeogFromText('SRID=4326;POINT($point)'),
+                location
+            ) AS distance
+        from places
+        where ST_DWithin(
+            ST_GeogFromText('SRID=4326;POINT($point)'),
+            location,
+            $distance
+        ) ORDER BY distance"));
+
+        return $places;
+    }
+
+    /**
+     * Convert location to text.
+     *
+     * @param  text $value
+     * @return text
+     */
+    public function getLocationAttribute($value)
+    {
+        $result = DB::select(DB::raw("SELECT ST_AsText('$value')"));
+
+        return $result[0]->st_astext;
+    }
+
+    /**
+     * Get the latitude from the `location` property.
+     *
+     * @return string latitude
+     */
+    public function getLatitudeAttribute()
+    {
+        preg_match('/\((.*)\)/', $this->location, $latlng);
+
+        return explode(' ', $latlng[1])[1];
+    }
+
+    /**
+     * Get the longitude from the `location` property.
+     *
+     * @return string longitude
+     */
+    public function getLongitudeAttribute()
+    {
+        preg_match('/\((.*)\)/', $this->location, $latlng);
+
+        return explode(' ', $latlng[1])[0];
+    }
+
+    /**
+     * The Long URL for a place.
+     *
+     * @return string
+     */
+    public function getLongurlAttribute()
+    {
+        return config('app.url') . '/places/' . $this->slug;
+    }
+
+    /**
+     * The Short URL for a place.
+     *
+     * @return string
+     */
+    public function getShorturlAttribute()
+    {
+        return config('app.shorturl') . '/places/' . $this->slug;
+    }
+}
diff --git a/app/Policies/.gitkeep b/app/Policies/.gitkeep
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/app/Policies/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
new file mode 100644
index 00000000..76b7af57
--- /dev/null
+++ b/app/Providers/AppServiceProvider.php
@@ -0,0 +1,57 @@
+getSize() > 5000000) {
+                        return false;
+                    }
+                }
+            }
+
+            return true;
+        });
+
+        //Add tags for notes
+        Note::created(function ($note) {
+            $noteprep = new NotePrep();
+            $tagsToAdd = [];
+            $tags = $noteprep->getTags($note->note);
+            foreach ($tags as $text) {
+                $tag = Tag::firstOrCreate(['tag' => $text]);
+                $tagsToAdd[] = $tag->id;
+            }
+            if (count($tagsToAdd > 0)) {
+                $note->tags()->attach($tagsToAdd);
+            }
+        });
+    }
+
+    /**
+     * Register any application services.
+     *
+     * @return void
+     */
+    public function register()
+    {
+        //
+    }
+}
diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php
new file mode 100644
index 00000000..57d88ea3
--- /dev/null
+++ b/app/Providers/AuthServiceProvider.php
@@ -0,0 +1,31 @@
+ 'App\Policies\ModelPolicy',
+    ];
+
+    /**
+     * Register any application authentication / authorization services.
+     *
+     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate
+     * @return void
+     */
+    public function boot(GateContract $gate)
+    {
+        $this->registerPolicies($gate);
+
+        //
+    }
+}
diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
new file mode 100644
index 00000000..58ce9624
--- /dev/null
+++ b/app/Providers/EventServiceProvider.php
@@ -0,0 +1,33 @@
+ [
+            'App\Listeners\EventListener',
+        ],
+    ];
+
+    /**
+     * Register any other events for your application.
+     *
+     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
+     * @return void
+     */
+    public function boot(DispatcherContract $events)
+    {
+        parent::boot($events);
+
+        //
+    }
+}
diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php
new file mode 100644
index 00000000..bde08819
--- /dev/null
+++ b/app/Providers/RouteServiceProvider.php
@@ -0,0 +1,61 @@
+mapWebRoutes($router);
+
+        //
+    }
+
+    /**
+     * Define the "web" routes for the application.
+     *
+     * These routes all receive session state, CSRF protection, etc.
+     *
+     * @param  \Illuminate\Routing\Router  $router
+     * @return void
+     */
+    protected function mapWebRoutes(Router $router)
+    {
+        $router->group([
+            'namespace' => $this->namespace, 'middleware' => 'web',
+        ], function ($router) {
+            require app_path('Http/routes.php');
+        });
+    }
+}
diff --git a/app/Services/IndieAuthService.php b/app/Services/IndieAuthService.php
new file mode 100644
index 00000000..cc7c775c
--- /dev/null
+++ b/app/Services/IndieAuthService.php
@@ -0,0 +1,113 @@
+discoverAuthorizationEndpoint($client->normalizeMeURL($domain));
+    }
+
+    /**
+     * Given an authorization endpoint, build the appropriate authorization URL.
+     *
+     * @param  string $authEndpoint
+     * @param  string $domain
+     * @param  \IndieAuth\Client $client
+     * @return string
+     */
+    public function buildAuthorizationURL($authEndpoint, $domain, $client)
+    {
+        $domain = $client->normalizeMeURL($domain);
+        $state = bin2hex(openssl_random_pseudo_bytes(16));
+        session(['state' => $state]);
+        $redirectURL = config('app.url') . '/indieauth';
+        $clientId = config('app.url') . '/notes/new';
+        $scope = 'post';
+        $authorizationURL = $client->buildAuthorizationURL(
+            $authEndpoint,
+            $domain,
+            $redirectURL,
+            $clientId,
+            $state,
+            $scope
+        );
+
+        return $authorizationURL;
+    }
+
+    /**
+     * Discover the token endpoint for a given domain.
+     *
+     * @param  string The domain
+     * @param  \IndieAuth\Client $client
+     * @return string|null
+     */
+    public function getTokenEndpoint($domain, $client)
+    {
+        return $client->discoverTokenEndpoint($domain);
+    }
+
+    /**
+     * Retrieve a token from the token endpoint.
+     *
+     * @param  array The relavent data
+     * @param  \IndieAuth\Client $client
+     * @return array
+     */
+    public function getAccessToken(array $data, $client)
+    {
+        return $client->getAccessToken(
+            $data['endpoint'],
+            $data['code'],
+            $data['me'],
+            $data['redirect_url'],
+            $data['client_id'],
+            $data['state']
+        );
+    }
+
+    /**
+     * Determine the Authorization endpoint, then verify the suplied code is
+     * valid.
+     *
+     * @param  array The data.
+     * @param  \IndieAuth\Client $client
+     * @return array|null
+     */
+    public function verifyIndieAuthCode(array $data, $client)
+    {
+        $authEndpoint = $client->discoverAuthorizationEndpoint($data['me']);
+        if ($authEndpoint) {
+            return $client->verifyIndieAuthCode(
+                $authEndpoint,
+                $data['code'],
+                $data['me'],
+                $data['redirect_url'],
+                $data['client_id'],
+                $data['state']
+            );
+        }
+    }
+
+    /**
+     * Determine the micropub endpoint.
+     *
+     * @param  string $domain
+     * @param  \IndieAuth\Client $client
+     * @return string The endpoint
+     */
+    public function discoverMicropubEndpoint($domain, $client)
+    {
+        return $client->discoverMicropubEndpoint($client->normalizeMeURL($domain));
+    }
+}
diff --git a/app/Services/NoteService.php b/app/Services/NoteService.php
new file mode 100644
index 00000000..61b970e0
--- /dev/null
+++ b/app/Services/NoteService.php
@@ -0,0 +1,67 @@
+ $request->input('content'),
+                'in_reply_to' => $request->input('in-reply-to'),
+                'client_id' => $clientId,
+            ]
+        );
+
+        $placeSlug = $request->input('location');
+        if ($placeSlug !== null && $placeSlug !== 'no-location') {
+            $place = Place::where('slug', '=', $placeSlug)->first();
+            $note->place()->associate($place);
+            $note->save();
+        }
+
+        //add images to media library
+        if ($request->hasFile('photo')) {
+            $files = $request->file('photo');
+            foreach ($files as $file) {
+                $note->addMedia($file)->toMediaLibraryOnDisk('images', 's3');
+            }
+        }
+
+        if ($request->input('webmentions')) {
+            $wmc = new WebMentionsController();
+            $wmc->send($note);
+        }
+
+        if (//micropub request, syndication sent as array
+            (is_array($request->input('mp-syndicate-to'))
+                &&
+            (in_array('twitter.com/jonnybarnes', $request->input('mp-syndicate-to')))
+            || //micropub request, syndication sent as string
+            ($request->input('mp-syndicate-to') == 'twitter.com/jonnybarnes')
+            || //local admin cp request
+            ($request->input('twitter') == true))
+        ) {
+            $this->dispatch(new SyndicateToTwitter($note));
+        }
+
+        return $note;
+    }
+}
diff --git a/app/Services/PlaceService.php b/app/Services/PlaceService.php
new file mode 100644
index 00000000..b4f737af
--- /dev/null
+++ b/app/Services/PlaceService.php
@@ -0,0 +1,39 @@
+input('geo') !== null) {
+            $parts = explode(':', $request->input('geo'));
+            $latlng = explode(',', $parts[1]);
+            $latitude = $latlng[0];
+            $longitude = $latlng[1];
+        }
+        if ($request->input('latitude') !== null) {
+            $latitude = $request->input('latitude');
+            $longitude = $request->input('longitude');
+        }
+        $place = new Place();
+        $place->name = $request->input('name');
+        $place->description = $request->input('description');
+        $place->location = new Point((float) $latitude, (float) $longitude);
+        $place->save();
+
+        return $place;
+    }
+}
diff --git a/app/Services/TokenService.php b/app/Services/TokenService.php
new file mode 100644
index 00000000..4652d30b
--- /dev/null
+++ b/app/Services/TokenService.php
@@ -0,0 +1,54 @@
+set('me', $data['me'])
+            ->set('client_id', $data['client_id'])
+            ->set('scope', $data['scope'])
+            ->set('date_issued', time())
+            ->set('nonce', bin2hex(random_bytes(8)))
+            ->sign($signer, env('APP_KEY'))
+            ->getToken();
+
+        return $token;
+    }
+
+    /**
+     * Check the token signature is valid.
+     *
+     * @param  string The token
+     * @return mixed
+     */
+    public function validateToken($token)
+    {
+        $signer = new Sha256();
+        try {
+            $token = (new Parser())->parse((string) $token);
+        } catch (InvalidArgumentException $e) {
+            return;
+        } catch (RuntimeException $e) {
+            return;
+        }
+        if ($token->verify($signer, env('APP_KEY'))) {
+            //signuture valid
+            return $token;
+        }
+    }
+}
diff --git a/app/Tag.php b/app/Tag.php
new file mode 100644
index 00000000..fb55663a
--- /dev/null
+++ b/app/Tag.php
@@ -0,0 +1,39 @@
+belongsToMany('App\Note');
+    }
+
+    /**
+     * The attributes excluded from the model's JSON form.
+     *
+     * @var array
+     */
+    protected $hidden = ['deleted'];
+
+    /**
+     * We shall set a blacklist of non-modifiable model attributes.
+     *
+     * @var array
+     */
+    protected $guarded = ['id'];
+}
diff --git a/app/User.php b/app/User.php
new file mode 100644
index 00000000..75741ae4
--- /dev/null
+++ b/app/User.php
@@ -0,0 +1,26 @@
+morphTo();
+    }
+
+    /**
+     * We shall set a blacklist of non-modifiable model attributes.
+     *
+     * @var array
+     */
+    protected $guarded = ['id'];
+}
diff --git a/artisan b/artisan
new file mode 100755
index 00000000..df630d0d
--- /dev/null
+++ b/artisan
@@ -0,0 +1,51 @@
+#!/usr/bin/env php
+make(Illuminate\Contracts\Console\Kernel::class);
+
+$status = $kernel->handle(
+    $input = new Symfony\Component\Console\Input\ArgvInput,
+    new Symfony\Component\Console\Output\ConsoleOutput
+);
+
+/*
+|--------------------------------------------------------------------------
+| Shutdown The Application
+|--------------------------------------------------------------------------
+|
+| Once Artisan has finished running. We will fire off the shutdown events
+| so that any final work may be done by the application before we shut
+| down the process. This is the last thing to happen to the request.
+|
+*/
+
+$kernel->terminate($input, $status);
+
+exit($status);
diff --git a/bootstrap/app.php b/bootstrap/app.php
new file mode 100644
index 00000000..f2801adf
--- /dev/null
+++ b/bootstrap/app.php
@@ -0,0 +1,55 @@
+singleton(
+    Illuminate\Contracts\Http\Kernel::class,
+    App\Http\Kernel::class
+);
+
+$app->singleton(
+    Illuminate\Contracts\Console\Kernel::class,
+    App\Console\Kernel::class
+);
+
+$app->singleton(
+    Illuminate\Contracts\Debug\ExceptionHandler::class,
+    App\Exceptions\Handler::class
+);
+
+/*
+|--------------------------------------------------------------------------
+| Return The Application
+|--------------------------------------------------------------------------
+|
+| This script returns the application instance. The instance is given to
+| the calling script so we can separate the building of the instances
+| from the actual running of the application and sending responses.
+|
+*/
+
+return $app;
diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php
new file mode 100644
index 00000000..38301379
--- /dev/null
+++ b/bootstrap/autoload.php
@@ -0,0 +1,34 @@
+"
+  ],
+  "license": "CC0-1.0",
+  "homepage": "https://github.com/jonnybarnes/jbl5",
+  "moduleType": [],
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "fetch": "~0.11.0",
+    "alertify.js": "alertifyjs#~1.0.5",
+    "store2": "~2.3.2",
+    "Autolinker.js": "~0.24.0",
+    "marked": "~0.3.5",
+    "sanitize-css": "^3.2.0"
+  }
+}
diff --git a/composer.json b/composer.json
new file mode 100644
index 00000000..6e9e5aa5
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,68 @@
+{
+    "name": "jonnybarnes/jbl5",
+    "description": "The code for jonnybanres.uk, based on Laravel 5.2",
+    "keywords": ["framework", "laravel", "indieweb"],
+    "license": "CC0-1.0",
+    "type": "project",
+    "require": {
+        "ext-intl": "*",
+        "php": ">=7.0.0",
+        "laravel/framework": "5.2.*",
+        "jonnybarnes/unicode-tools": "dev-master",
+        "jonnybarnes/indieweb": "dev-master",
+        "jonnybarnes/webmentions-parser": "dev-master",
+        "guzzlehttp/guzzle": "~6.0",
+        "predis/predis": "~1.0",
+        "thujohn/twitter": "~2.0",
+        "mf2/mf2": "~0.3",
+        "martinbean/laravel-sluggable-trait": "0.2.*",
+        "indieauth/client": "~0.1",
+        "ezyang/htmlpurifier": "~4.6",
+        "league/commonmark": "^0.13.0",
+        "spatie/laravel-medialibrary": "^3.5",
+        "league/flysystem-aws-s3-v3": "^1.0",
+        "phaza/laravel-postgis": "dev-master",
+        "lcobucci/jwt": "^3.1"
+    },
+    "require-dev": {
+        "fzaninotto/faker": "~1.4",
+        "mockery/mockery": "0.9.*",
+        "phpunit/phpunit": "~4.0",
+        "symfony/css-selector": "2.8.*|3.0.*",
+        "symfony/dom-crawler": "2.8.*|3.0.*",
+        "barryvdh/laravel-debugbar": "~2.0",
+        "filp/whoops": "~2.0"
+    },
+    "autoload": {
+        "classmap": [
+            "database"
+        ],
+        "psr-4": {
+            "App\\": "app/"
+        }
+    },
+    "autoload-dev": {
+        "classmap": [
+            "tests/TestCase.php"
+        ]
+    },
+    "scripts": {
+        "post-root-package-install": [
+            "php -r \"copy('.env.example', '.env');\""
+        ],
+        "post-create-project-cmd": [
+            "php artisan key:generate"
+        ],
+        "post-install-cmd": [
+            "Illuminate\\Foundation\\ComposerScripts::postInstall",
+            "php artisan optimize"
+        ],
+        "post-update-cmd": [
+            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
+            "php artisan optimize"
+        ]
+    },
+    "config": {
+        "preferred-install": "dist"
+    }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 00000000..a7fac400
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,5025 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+        "This file is @generated automatically"
+    ],
+    "hash": "6303f502566131a9770f488130aab593",
+    "content-hash": "8acf6b6b6db3ef7f0418631e6d15eace",
+    "packages": [
+        {
+            "name": "anahkiasen/underscore-php",
+            "version": "2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Anahkiasen/underscore-php.git",
+                "reference": "48f97b295c82d99c1fe10d8b0684c43f051b5580"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Anahkiasen/underscore-php/zipball/48f97b295c82d99c1fe10d8b0684c43f051b5580",
+                "reference": "48f97b295c82d99c1fe10d8b0684c43f051b5580",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/inflector": "^1.0",
+                "patchwork/utf8": "^1.2",
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "fabpot/php-cs-fixer": "2.0.*@dev",
+                "phpunit/phpunit": "^4.6"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Underscore\\": [
+                        "src",
+                        "tests"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Maxime Fabre",
+                    "email": "ehtnam6@gmail.com"
+                }
+            ],
+            "description": "A redacted port of Underscore.js for PHP",
+            "keywords": [
+                "internals",
+                "laravel",
+                "toolkit"
+            ],
+            "time": "2015-05-16 19:24:58"
+        },
+        {
+            "name": "aws/aws-sdk-php",
+            "version": "3.18.10",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/aws/aws-sdk-php.git",
+                "reference": "483e21b602fc5c9993437e6e04e44d936392c344"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/483e21b602fc5c9993437e6e04e44d936392c344",
+                "reference": "483e21b602fc5c9993437e6e04e44d936392c344",
+                "shasum": ""
+            },
+            "require": {
+                "guzzlehttp/guzzle": "~5.3|~6.0.1|~6.1",
+                "guzzlehttp/promises": "~1.0",
+                "guzzlehttp/psr7": "~1.0",
+                "mtdowling/jmespath.php": "~2.2",
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "andrewsville/php-token-reflection": "^1.4",
+                "aws/aws-php-sns-message-validator": "~1.0",
+                "behat/behat": "~3.0",
+                "doctrine/cache": "~1.4",
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-openssl": "*",
+                "ext-pcre": "*",
+                "ext-simplexml": "*",
+                "ext-spl": "*",
+                "nette/neon": "^2.3",
+                "phpunit/phpunit": "~4.0|~5.0",
+                "psr/cache": "^1.0"
+            },
+            "suggest": {
+                "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
+                "doctrine/cache": "To use the DoctrineCacheAdapter",
+                "ext-curl": "To send requests using cURL",
+                "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Aws\\": "src/"
+                },
+                "files": [
+                    "src/functions.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Amazon Web Services",
+                    "homepage": "http://aws.amazon.com"
+                }
+            ],
+            "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
+            "homepage": "http://aws.amazon.com/sdkforphp",
+            "keywords": [
+                "amazon",
+                "aws",
+                "cloud",
+                "dynamodb",
+                "ec2",
+                "glacier",
+                "s3",
+                "sdk"
+            ],
+            "time": "2016-05-18 20:23:24"
+        },
+        {
+            "name": "barnabywalters/mf-cleaner",
+            "version": "v0.1.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/barnabywalters/php-mf-cleaner.git",
+                "reference": "ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/barnabywalters/php-mf-cleaner/zipball/ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4",
+                "reference": "ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4",
+                "shasum": ""
+            },
+            "require-dev": {
+                "php": ">=5.3",
+                "phpunit/phpunit": "*"
+            },
+            "suggest": {
+                "mf2/mf2": "To parse microformats2 structures from (X)HTML"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/BarnabyWalters/Mf2/Functions.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Barnaby Walters",
+                    "email": "barnaby@waterpigs.co.uk"
+                }
+            ],
+            "description": "Cleans up microformats2 array structures",
+            "time": "2014-10-06 23:11:15"
+        },
+        {
+            "name": "bosnadev/database",
+            "version": "0.16",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Bosnadev/Database.git",
+                "reference": "c2748d118415d30ce69b792448689285d01ffdb9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Bosnadev/Database/zipball/c2748d118415d30ce69b792448689285d01ffdb9",
+                "reference": "c2748d118415d30ce69b792448689285d01ffdb9",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/database": "~5.0",
+                "php": ">=5.4",
+                "ramsey/uuid": "~3.0"
+            },
+            "require-dev": {
+                "doctrine/dbal": "~2.5",
+                "mockery/mockery": "0.9.*",
+                "php": ">=5.4",
+                "phpunit/phpunit": "~4.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Bosnadev\\Database\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "authors": [
+                {
+                    "name": "Mirza Pasic",
+                    "email": "mirza.pasic@edu.fit.ba"
+                },
+                {
+                    "name": "Peter Haza",
+                    "email": "peter.haza@gmail.com"
+                }
+            ],
+            "description": "Eloquent Extended, added some PostgreSql features",
+            "keywords": [
+                "database",
+                "eloquent",
+                "laravel",
+                "mysql",
+                "postgresql"
+            ],
+            "time": "2016-04-27 15:18:36"
+        },
+        {
+            "name": "classpreloader/classpreloader",
+            "version": "3.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ClassPreloader/ClassPreloader.git",
+                "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/9b10b913c2bdf90c3d2e0d726b454fb7f77c552a",
+                "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a",
+                "shasum": ""
+            },
+            "require": {
+                "nikic/php-parser": "^1.0|^2.0",
+                "php": ">=5.5.9"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8|^5.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "ClassPreloader\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com"
+                },
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com"
+                }
+            ],
+            "description": "Helps class loading performance by generating a single PHP file containing all of the autoloaded files for a specific use case",
+            "keywords": [
+                "autoload",
+                "class",
+                "preload"
+            ],
+            "time": "2015-11-09 22:51:51"
+        },
+        {
+            "name": "dnoegel/php-xdg-base-dir",
+            "version": "0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/dnoegel/php-xdg-base-dir.git",
+                "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a",
+                "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "@stable"
+            },
+            "type": "project",
+            "autoload": {
+                "psr-4": {
+                    "XdgBaseDir\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "implementation of xdg base directory specification for php",
+            "time": "2014-10-24 07:27:01"
+        },
+        {
+            "name": "doctrine/inflector",
+            "version": "v1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/inflector.git",
+                "reference": "90b2128806bfde671b6952ab8bea493942c1fdae"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae",
+                "reference": "90b2128806bfde671b6952ab8bea493942c1fdae",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Inflector\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                }
+            ],
+            "description": "Common String Manipulations with regard to casing and singular/plural rules.",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "inflection",
+                "pluralize",
+                "singularize",
+                "string"
+            ],
+            "time": "2015-11-06 14:35:42"
+        },
+        {
+            "name": "ezyang/htmlpurifier",
+            "version": "v4.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ezyang/htmlpurifier.git",
+                "reference": "ae1828d955112356f7677c465f94f7deb7d27a40"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/ae1828d955112356f7677c465f94f7deb7d27a40",
+                "reference": "ae1828d955112356f7677c465f94f7deb7d27a40",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "HTMLPurifier": "library/"
+                },
+                "files": [
+                    "library/HTMLPurifier.composer.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL"
+            ],
+            "authors": [
+                {
+                    "name": "Edward Z. Yang",
+                    "email": "admin@htmlpurifier.org",
+                    "homepage": "http://ezyang.com"
+                }
+            ],
+            "description": "Standards compliant HTML filter written in PHP",
+            "homepage": "http://htmlpurifier.org/",
+            "keywords": [
+                "html"
+            ],
+            "time": "2015-08-05 01:03:42"
+        },
+        {
+            "name": "geo-io/interface",
+            "version": "v1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/geo-io/interface.git",
+                "reference": "cdbb55801e3f8d5485227c2031cc7a3c16ccd06a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/geo-io/interface/zipball/cdbb55801e3f8d5485227c2031cc7a3c16ccd06a",
+                "reference": "cdbb55801e3f8d5485227c2031cc7a3c16ccd06a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GeoIO\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jan Sorgalla",
+                    "email": "jsorgalla@gmail.com"
+                }
+            ],
+            "description": "Geo I/O base interfaces.",
+            "keywords": [
+                "geo",
+                "geometry",
+                "io"
+            ],
+            "time": "2015-04-17 18:52:52"
+        },
+        {
+            "name": "geo-io/wkb-parser",
+            "version": "v1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/geo-io/wkb-parser.git",
+                "reference": "cceee8f4e8b2058f3f1a0372c930140f23fe1ee1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/geo-io/wkb-parser/zipball/cceee8f4e8b2058f3f1a0372c930140f23fe1ee1",
+                "reference": "cceee8f4e8b2058f3f1a0372c930140f23fe1ee1",
+                "shasum": ""
+            },
+            "require": {
+                "geo-io/interface": "~1.0",
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "mockery/mockery": "~0.9.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GeoIO\\WKB\\Parser\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jan Sorgalla",
+                    "email": "jsorgalla@gmail.com"
+                }
+            ],
+            "description": "Well-known binary (WKB) Parser.",
+            "keywords": [
+                "geo",
+                "geometry",
+                "io",
+                "parser",
+                "wkb"
+            ],
+            "time": "2015-06-30 04:19:13"
+        },
+        {
+            "name": "guzzlehttp/guzzle",
+            "version": "6.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/guzzle.git",
+                "reference": "d094e337976dff9d8e2424e8485872194e768662"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d094e337976dff9d8e2424e8485872194e768662",
+                "reference": "d094e337976dff9d8e2424e8485872194e768662",
+                "shasum": ""
+            },
+            "require": {
+                "guzzlehttp/promises": "~1.0",
+                "guzzlehttp/psr7": "~1.1",
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "ext-curl": "*",
+                "phpunit/phpunit": "~4.0",
+                "psr/log": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "6.2-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/functions_include.php"
+                ],
+                "psr-4": {
+                    "GuzzleHttp\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "Guzzle is a PHP HTTP client library",
+            "homepage": "http://guzzlephp.org/",
+            "keywords": [
+                "client",
+                "curl",
+                "framework",
+                "http",
+                "http client",
+                "rest",
+                "web service"
+            ],
+            "time": "2016-03-21 20:02:09"
+        },
+        {
+            "name": "guzzlehttp/promises",
+            "version": "1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/promises.git",
+                "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579",
+                "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Promise\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "Guzzle promises library",
+            "keywords": [
+                "promise"
+            ],
+            "time": "2016-05-18 16:56:05"
+        },
+        {
+            "name": "guzzlehttp/psr7",
+            "version": "1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/psr7.git",
+                "reference": "31382fef2889136415751badebbd1cb022a4ed72"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/31382fef2889136415751badebbd1cb022a4ed72",
+                "reference": "31382fef2889136415751badebbd1cb022a4ed72",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0",
+                "psr/http-message": "~1.0"
+            },
+            "provide": {
+                "psr/http-message-implementation": "1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Psr7\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "PSR-7 message implementation",
+            "keywords": [
+                "http",
+                "message",
+                "stream",
+                "uri"
+            ],
+            "time": "2016-04-13 19:56:01"
+        },
+        {
+            "name": "indieauth/client",
+            "version": "0.1.14",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/indieweb/indieauth-client-php.git",
+                "reference": "504ba095ee10ffaabc570682f3a93b462ba21c77"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/504ba095ee10ffaabc570682f3a93b462ba21c77",
+                "reference": "504ba095ee10ffaabc570682f3a93b462ba21c77",
+                "shasum": ""
+            },
+            "require": {
+                "barnabywalters/mf-cleaner": "0.*",
+                "indieweb/link-rel-parser": "0.1.1",
+                "mf2/mf2": "~0.3",
+                "php": ">5.3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "IndieAuth": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache 2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Parecki",
+                    "homepage": "http://aaronparecki.com"
+                }
+            ],
+            "description": "IndieAuth Client Library",
+            "time": "2016-04-04 14:57:04"
+        },
+        {
+            "name": "indieweb/link-rel-parser",
+            "version": "0.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/indieweb/link-rel-parser-php.git",
+                "reference": "9e0e635fd301a8b1da7bc181f651f029c531dbb6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/indieweb/link-rel-parser-php/zipball/9e0e635fd301a8b1da7bc181f651f029c531dbb6",
+                "reference": "9e0e635fd301a8b1da7bc181f651f029c531dbb6",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/IndieWeb/link_rel_parser.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Parecki",
+                    "homepage": "http://aaronparecki.com"
+                },
+                {
+                    "name": "Tantek Çelik",
+                    "homepage": "http://tantek.com"
+                }
+            ],
+            "description": "Parse rel values from HTTP headers",
+            "homepage": "https://github.com/indieweb/link-rel-parser-php",
+            "keywords": [
+                "http",
+                "indieweb",
+                "microformats2"
+            ],
+            "time": "2013-12-23 00:14:58"
+        },
+        {
+            "name": "intervention/image",
+            "version": "2.3.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Intervention/image.git",
+                "reference": "22088b04728a039bd1fc32f7e79a89a118b78698"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Intervention/image/zipball/22088b04728a039bd1fc32f7e79a89a118b78698",
+                "reference": "22088b04728a039bd1fc32f7e79a89a118b78698",
+                "shasum": ""
+            },
+            "require": {
+                "ext-fileinfo": "*",
+                "guzzlehttp/psr7": "~1.1",
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "~0.9.2",
+                "phpunit/phpunit": "3.*"
+            },
+            "suggest": {
+                "ext-gd": "to use GD library based image processing.",
+                "ext-imagick": "to use Imagick based image processing.",
+                "intervention/imagecache": "Caching extension for the Intervention Image library"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Intervention\\Image\\": "src/Intervention/Image"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Oliver Vogel",
+                    "email": "oliver@olivervogel.net",
+                    "homepage": "http://olivervogel.net/"
+                }
+            ],
+            "description": "Image handling and manipulation library with support for Laravel integration",
+            "homepage": "http://image.intervention.io/",
+            "keywords": [
+                "gd",
+                "image",
+                "imagick",
+                "laravel",
+                "thumbnail",
+                "watermark"
+            ],
+            "time": "2016-04-26 14:08:40"
+        },
+        {
+            "name": "jakub-onderka/php-console-color",
+            "version": "0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/JakubOnderka/PHP-Console-Color.git",
+                "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1",
+                "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "jakub-onderka/php-code-style": "1.0",
+                "jakub-onderka/php-parallel-lint": "0.*",
+                "jakub-onderka/php-var-dump-check": "0.*",
+                "phpunit/phpunit": "3.7.*",
+                "squizlabs/php_codesniffer": "1.*"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "JakubOnderka\\PhpConsoleColor": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-2-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Jakub Onderka",
+                    "email": "jakub.onderka@gmail.com",
+                    "homepage": "http://www.acci.cz"
+                }
+            ],
+            "time": "2014-04-08 15:00:19"
+        },
+        {
+            "name": "jakub-onderka/php-console-highlighter",
+            "version": "v0.3.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git",
+                "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5",
+                "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5",
+                "shasum": ""
+            },
+            "require": {
+                "jakub-onderka/php-console-color": "~0.1",
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "jakub-onderka/php-code-style": "~1.0",
+                "jakub-onderka/php-parallel-lint": "~0.5",
+                "jakub-onderka/php-var-dump-check": "~0.1",
+                "phpunit/phpunit": "~4.0",
+                "squizlabs/php_codesniffer": "~1.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "JakubOnderka\\PhpConsoleHighlighter": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jakub Onderka",
+                    "email": "acci@acci.cz",
+                    "homepage": "http://www.acci.cz/"
+                }
+            ],
+            "time": "2015-04-20 18:58:01"
+        },
+        {
+            "name": "jeremeamia/SuperClosure",
+            "version": "2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/jeremeamia/super_closure.git",
+                "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/29a88be2a4846d27c1613aed0c9071dfad7b5938",
+                "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938",
+                "shasum": ""
+            },
+            "require": {
+                "nikic/php-parser": "^1.2|^2.0",
+                "php": ">=5.4",
+                "symfony/polyfill-php56": "^1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.0|^5.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "SuperClosure\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jeremy Lindblom",
+                    "email": "jeremeamia@gmail.com",
+                    "homepage": "https://github.com/jeremeamia",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Serialize Closure objects, including their context and binding",
+            "homepage": "https://github.com/jeremeamia/super_closure",
+            "keywords": [
+                "closure",
+                "function",
+                "lambda",
+                "parser",
+                "serializable",
+                "serialize",
+                "tokenizer"
+            ],
+            "time": "2015-12-05 17:17:57"
+        },
+        {
+            "name": "jmikola/geojson",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/jmikola/geojson.git",
+                "reference": "6ec3016cc0215667b7775f6ead7bd0337ad66eee"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/jmikola/geojson/zipball/6ec3016cc0215667b7775f6ead7bd0337ad66eee",
+                "reference": "6ec3016cc0215667b7775f6ead7bd0337ad66eee",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~3.7"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "GeoJson\\": "src/"
+                },
+                "classmap": [
+                    "stubs/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jeremy Mikola",
+                    "email": "jmikola@gmail.com"
+                }
+            ],
+            "description": "GeoJSON implementation for PHP",
+            "homepage": "https://github.com/jmikola/geojson",
+            "keywords": [
+                "geo",
+                "geojson",
+                "geospatial"
+            ],
+            "time": "2015-09-27 15:35:21"
+        },
+        {
+            "name": "jonnybarnes/indieweb",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/jonnybarnes/indieweb.git",
+                "reference": "a1de61e99dddd4a5800565bff3802a892a693b35"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/jonnybarnes/indieweb/zipball/a1de61e99dddd4a5800565bff3802a892a693b35",
+                "reference": "a1de61e99dddd4a5800565bff3802a892a693b35",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~5.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Jonnybarnes\\IndieWeb\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "CC0-1.0"
+            ],
+            "authors": [
+                {
+                    "name": "Jonny Barnes",
+                    "email": "jonny@jonnybarnes.uk"
+                }
+            ],
+            "description": "IndieWeb helper functions",
+            "homepage": "https://github.com/jonnybarnes/indieweb",
+            "keywords": [
+                "indieweb",
+                "posse"
+            ],
+            "time": "2016-01-14 15:10:20"
+        },
+        {
+            "name": "jonnybarnes/unicode-tools",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/jonnybarnes/unicode-tools.git",
+                "reference": "0f469c30cb9a40a1cb578f893b3af1abc1a6ff53"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/jonnybarnes/unicode-tools/zipball/0f469c30cb9a40a1cb578f893b3af1abc1a6ff53",
+                "reference": "0f469c30cb9a40a1cb578f893b3af1abc1a6ff53",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "3.7.*"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Jonnybarnes\\UnicodeTools": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonny Barnes",
+                    "email": "jonny@jonnybarnes.net"
+                }
+            ],
+            "description": "Turns Unicode codepoints into raw utf-8 multibyte characters",
+            "homepage": "https://github.com/jonnybarnes/unicode-tools",
+            "keywords": [
+                "unicode",
+                "utf-8"
+            ],
+            "time": "2013-07-18 15:32:42"
+        },
+        {
+            "name": "jonnybarnes/webmentions-parser",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/jonnybarnes/webmentions-parser.git",
+                "reference": "00ccf313a8c19bf795fc16ec71f2408ea23dd8d6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/jonnybarnes/webmentions-parser/zipball/00ccf313a8c19bf795fc16ec71f2408ea23dd8d6",
+                "reference": "00ccf313a8c19bf795fc16ec71f2408ea23dd8d6",
+                "shasum": ""
+            },
+            "require": {
+                "guzzlehttp/guzzle": "~6.0",
+                "mf2/mf2": "~0.3",
+                "php": ">=5.6"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~5.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Jonnybarnes\\WebmentionsParser\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "authors": [
+                {
+                    "name": "Jonny Barnes",
+                    "homepage": "https://jonnybarnes.uk"
+                }
+            ],
+            "description": "A PHP library to parse webmentions from HTML",
+            "keywords": [
+                "html",
+                "indieweb",
+                "microformats",
+                "webmentions"
+            ],
+            "time": "2016-04-03 19:57:20"
+        },
+        {
+            "name": "laravel/framework",
+            "version": "v5.2.32",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/laravel/framework.git",
+                "reference": "f688217113f70b01d0e127da9035195415812bef"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/f688217113f70b01d0e127da9035195415812bef",
+                "reference": "f688217113f70b01d0e127da9035195415812bef",
+                "shasum": ""
+            },
+            "require": {
+                "classpreloader/classpreloader": "~3.0",
+                "doctrine/inflector": "~1.0",
+                "ext-mbstring": "*",
+                "ext-openssl": "*",
+                "jeremeamia/superclosure": "~2.2",
+                "league/flysystem": "~1.0",
+                "monolog/monolog": "~1.11",
+                "mtdowling/cron-expression": "~1.0",
+                "nesbot/carbon": "~1.20",
+                "paragonie/random_compat": "~1.4",
+                "php": ">=5.5.9",
+                "psy/psysh": "0.7.*",
+                "swiftmailer/swiftmailer": "~5.1",
+                "symfony/console": "2.8.*|3.0.*",
+                "symfony/debug": "2.8.*|3.0.*",
+                "symfony/finder": "2.8.*|3.0.*",
+                "symfony/http-foundation": "2.8.*|3.0.*",
+                "symfony/http-kernel": "2.8.*|3.0.*",
+                "symfony/polyfill-php56": "~1.0",
+                "symfony/process": "2.8.*|3.0.*",
+                "symfony/routing": "2.8.*|3.0.*",
+                "symfony/translation": "2.8.*|3.0.*",
+                "symfony/var-dumper": "2.8.*|3.0.*",
+                "vlucas/phpdotenv": "~2.2"
+            },
+            "replace": {
+                "illuminate/auth": "self.version",
+                "illuminate/broadcasting": "self.version",
+                "illuminate/bus": "self.version",
+                "illuminate/cache": "self.version",
+                "illuminate/config": "self.version",
+                "illuminate/console": "self.version",
+                "illuminate/container": "self.version",
+                "illuminate/contracts": "self.version",
+                "illuminate/cookie": "self.version",
+                "illuminate/database": "self.version",
+                "illuminate/encryption": "self.version",
+                "illuminate/events": "self.version",
+                "illuminate/exception": "self.version",
+                "illuminate/filesystem": "self.version",
+                "illuminate/hashing": "self.version",
+                "illuminate/http": "self.version",
+                "illuminate/log": "self.version",
+                "illuminate/mail": "self.version",
+                "illuminate/pagination": "self.version",
+                "illuminate/pipeline": "self.version",
+                "illuminate/queue": "self.version",
+                "illuminate/redis": "self.version",
+                "illuminate/routing": "self.version",
+                "illuminate/session": "self.version",
+                "illuminate/support": "self.version",
+                "illuminate/translation": "self.version",
+                "illuminate/validation": "self.version",
+                "illuminate/view": "self.version"
+            },
+            "require-dev": {
+                "aws/aws-sdk-php": "~3.0",
+                "mockery/mockery": "~0.9.4",
+                "pda/pheanstalk": "~3.0",
+                "phpunit/phpunit": "~4.1",
+                "predis/predis": "~1.0",
+                "symfony/css-selector": "2.8.*|3.0.*",
+                "symfony/dom-crawler": "2.8.*|3.0.*"
+            },
+            "suggest": {
+                "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).",
+                "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).",
+                "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).",
+                "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~5.3|~6.0).",
+                "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
+                "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
+                "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).",
+                "predis/predis": "Required to use the redis cache and queue drivers (~1.0).",
+                "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).",
+                "symfony/css-selector": "Required to use some of the crawler integration testing tools (2.8.*|3.0.*).",
+                "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (2.8.*|3.0.*).",
+                "symfony/psr-http-message-bridge": "Required to psr7 bridging features (0.2.*)."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.2-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/Illuminate/Queue/IlluminateQueueClosure.php"
+                ],
+                "files": [
+                    "src/Illuminate/Foundation/helpers.php",
+                    "src/Illuminate/Support/helpers.php"
+                ],
+                "psr-4": {
+                    "Illuminate\\": "src/Illuminate/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylorotwell@gmail.com"
+                }
+            ],
+            "description": "The Laravel Framework.",
+            "homepage": "http://laravel.com",
+            "keywords": [
+                "framework",
+                "laravel"
+            ],
+            "time": "2016-05-17 13:24:40"
+        },
+        {
+            "name": "lcobucci/jwt",
+            "version": "3.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/lcobucci/jwt.git",
+                "reference": "afea8e682e911a21574fd8519321b32522fa25b5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/lcobucci/jwt/zipball/afea8e682e911a21574fd8519321b32522fa25b5",
+                "reference": "afea8e682e911a21574fd8519321b32522fa25b5",
+                "shasum": ""
+            },
+            "require": {
+                "ext-openssl": "*",
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "mdanter/ecc": "~0.3",
+                "mikey179/vfsstream": "~1.5",
+                "phpmd/phpmd": "~2.2",
+                "phpunit/php-invoker": "~1.1",
+                "phpunit/phpunit": "~4.5",
+                "squizlabs/php_codesniffer": "~2.3"
+            },
+            "suggest": {
+                "mdanter/ecc": "Required to use Elliptic Curves based algorithms."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Lcobucci\\JWT\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Luís Otávio Cobucci Oblonczyk",
+                    "email": "lcobucci@gmail.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A simple library to work with JSON Web Token and JSON Web Signature",
+            "keywords": [
+                "JWS",
+                "jwt"
+            ],
+            "time": "2016-03-24 22:46:13"
+        },
+        {
+            "name": "league/commonmark",
+            "version": "0.13.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/commonmark.git",
+                "reference": "35ac362082ca983a8123df2ee2cdfcf456ab6295"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/35ac362082ca983a8123df2ee2cdfcf456ab6295",
+                "reference": "35ac362082ca983a8123df2ee2cdfcf456ab6295",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "php": ">=5.4.8"
+            },
+            "replace": {
+                "colinodell/commonmark-php": "*"
+            },
+            "require-dev": {
+                "erusev/parsedown": "~1.0",
+                "jgm/commonmark": "0.25",
+                "michelf/php-markdown": "~1.4",
+                "mikehaertl/php-shellcommand": "~1.2.0",
+                "phpunit/phpunit": "~4.3|~5.0",
+                "scrutinizer/ocular": "~1.1",
+                "symfony/finder": "~2.3|~3.0"
+            },
+            "suggest": {
+                "league/commonmark-extras": "Library of useful extensions including smart punctuation"
+            },
+            "bin": [
+                "bin/commonmark"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "0.14-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "League\\CommonMark\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Colin O'Dell",
+                    "email": "colinodell@gmail.com",
+                    "homepage": "https://www.colinodell.com",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "Markdown parser for PHP based on the CommonMark spec",
+            "homepage": "https://github.com/thephpleague/commonmark",
+            "keywords": [
+                "commonmark",
+                "markdown",
+                "parser"
+            ],
+            "time": "2016-03-27 19:10:13"
+        },
+        {
+            "name": "league/flysystem",
+            "version": "1.0.22",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/flysystem.git",
+                "reference": "bd73a91703969a2d20ab4bfbf971d6c2cbe36612"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/bd73a91703969a2d20ab4bfbf971d6c2cbe36612",
+                "reference": "bd73a91703969a2d20ab4bfbf971d6c2cbe36612",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "conflict": {
+                "league/flysystem-sftp": "<1.0.6"
+            },
+            "require-dev": {
+                "ext-fileinfo": "*",
+                "mockery/mockery": "~0.9",
+                "phpspec/phpspec": "^2.2",
+                "phpunit/phpunit": "~4.8 || ~5.0"
+            },
+            "suggest": {
+                "ext-fileinfo": "Required for MimeType",
+                "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
+                "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
+                "league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
+                "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
+                "league/flysystem-copy": "Allows you to use Copy.com storage",
+                "league/flysystem-dropbox": "Allows you to use Dropbox storage",
+                "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
+                "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
+                "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
+                "league/flysystem-webdav": "Allows you to use WebDAV storage",
+                "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "League\\Flysystem\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Frank de Jonge",
+                    "email": "info@frenky.net"
+                }
+            ],
+            "description": "Filesystem abstraction: Many filesystems, one API.",
+            "keywords": [
+                "Cloud Files",
+                "WebDAV",
+                "abstraction",
+                "aws",
+                "cloud",
+                "copy.com",
+                "dropbox",
+                "file systems",
+                "files",
+                "filesystem",
+                "filesystems",
+                "ftp",
+                "rackspace",
+                "remote",
+                "s3",
+                "sftp",
+                "storage"
+            ],
+            "time": "2016-04-28 06:53:12"
+        },
+        {
+            "name": "league/flysystem-aws-s3-v3",
+            "version": "1.0.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
+                "reference": "1f7ae4e3cc178686c49a9d23cab43ed1e955368c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/1f7ae4e3cc178686c49a9d23cab43ed1e955368c",
+                "reference": "1f7ae4e3cc178686c49a9d23cab43ed1e955368c",
+                "shasum": ""
+            },
+            "require": {
+                "aws/aws-sdk-php": "^3.0.0",
+                "league/flysystem": "~1.0",
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "henrikbjorn/phpspec-code-coverage": "~1.0.1",
+                "phpspec/phpspec": "^2.0.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "League\\Flysystem\\AwsS3v3\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Frank de Jonge",
+                    "email": "info@frenky.net"
+                }
+            ],
+            "description": "Flysystem adapter for the AWS S3 SDK v3.x",
+            "time": "2016-05-03 19:35:35"
+        },
+        {
+            "name": "league/glide",
+            "version": "0.3.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/glide.git",
+                "reference": "e45a4b536924956e1b20f5d023800557d466eda7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/glide/zipball/e45a4b536924956e1b20f5d023800557d466eda7",
+                "reference": "e45a4b536924956e1b20f5d023800557d466eda7",
+                "shasum": ""
+            },
+            "require": {
+                "intervention/image": "~2.1",
+                "league/flysystem": "~1.0",
+                "php": ">=5.4",
+                "symfony/http-foundation": "~2.3|~3.0",
+                "symfony/http-kernel": "~2.3|~3.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "~0.9",
+                "phpunit/php-token-stream": ">=1.3.0",
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "0.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "League\\Glide\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Reinink",
+                    "email": "jonathan@reinink.ca",
+                    "homepage": "http://reinink.ca"
+                }
+            ],
+            "description": "Wonderfully easy on-demand image manipulation library with an HTTP based API.",
+            "homepage": "https://github.com/thephpleague/glide",
+            "keywords": [
+                "ImageMagick",
+                "editing",
+                "gd",
+                "image",
+                "imagick",
+                "league",
+                "manipulation",
+                "processing"
+            ],
+            "time": "2016-01-25 13:35:12"
+        },
+        {
+            "name": "martinbean/laravel-sluggable-trait",
+            "version": "0.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/martinbean/laravel-sluggable-trait.git",
+                "reference": "8984dc9bc2596814f79baf44aeb9a39c9c07b149"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/martinbean/laravel-sluggable-trait/zipball/8984dc9bc2596814f79baf44aeb9a39c9c07b149",
+                "reference": "8984dc9bc2596814f79baf44aeb9a39c9c07b149",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/database": ">=4.0",
+                "illuminate/support": ">=4.0",
+                "php": ">=5.4.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "MartinBean\\Database\\Eloquent\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Martin Bean",
+                    "email": "martin@martinbean.co.uk"
+                }
+            ],
+            "description": "A trait you can apply to Eloquent models to have slugs automatically generated on save.",
+            "keywords": [
+                "eloquent",
+                "laravel"
+            ],
+            "time": "2015-02-17 22:47:44"
+        },
+        {
+            "name": "mf2/mf2",
+            "version": "v0.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/indieweb/php-mf2.git",
+                "reference": "4fb2eb5365cbc0fd2e0c26ca748777d6c2539763"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/indieweb/php-mf2/zipball/4fb2eb5365cbc0fd2e0c26ca748777d6c2539763",
+                "reference": "4fb2eb5365cbc0fd2e0c26ca748777d6c2539763",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "3.7.*"
+            },
+            "suggest": {
+                "barnabywalters/mf-cleaner": "To more easily handle the canonical data php-mf2 gives you"
+            },
+            "bin": [
+                "bin/fetch-mf2",
+                "bin/parse-mf2"
+            ],
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "Mf2/Parser.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "CC0"
+            ],
+            "authors": [
+                {
+                    "name": "Barnaby Walters",
+                    "homepage": "http://waterpigs.co.uk"
+                }
+            ],
+            "description": "A pure, generic microformats2 parser — makes HTML as easy to consume as a JSON API",
+            "keywords": [
+                "html",
+                "microformats",
+                "microformats 2",
+                "parser",
+                "semantic"
+            ],
+            "time": "2016-03-14 12:13:34"
+        },
+        {
+            "name": "monolog/monolog",
+            "version": "1.19.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/monolog.git",
+                "reference": "5f56ed5212dc509c8dc8caeba2715732abb32dbf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/5f56ed5212dc509c8dc8caeba2715732abb32dbf",
+                "reference": "5f56ed5212dc509c8dc8caeba2715732abb32dbf",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0",
+                "psr/log": "~1.0"
+            },
+            "provide": {
+                "psr/log-implementation": "1.0.0"
+            },
+            "require-dev": {
+                "aws/aws-sdk-php": "^2.4.9",
+                "doctrine/couchdb": "~1.0@dev",
+                "graylog2/gelf-php": "~1.0",
+                "jakub-onderka/php-parallel-lint": "0.9",
+                "php-amqplib/php-amqplib": "~2.4",
+                "php-console/php-console": "^3.1.3",
+                "phpunit/phpunit": "~4.5",
+                "phpunit/phpunit-mock-objects": "2.3.0",
+                "raven/raven": "^0.13",
+                "ruflin/elastica": ">=0.90 <3.0",
+                "swiftmailer/swiftmailer": "~5.3"
+            },
+            "suggest": {
+                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+                "ext-mongo": "Allow sending log messages to a MongoDB server",
+                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+                "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
+                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+                "php-console/php-console": "Allow sending log messages to Google Chrome",
+                "raven/raven": "Allow sending log messages to a Sentry server",
+                "rollbar/rollbar": "Allow sending log messages to Rollbar",
+                "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Monolog\\": "src/Monolog"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+            "homepage": "http://github.com/Seldaek/monolog",
+            "keywords": [
+                "log",
+                "logging",
+                "psr-3"
+            ],
+            "time": "2016-04-12 18:29:35"
+        },
+        {
+            "name": "mtdowling/cron-expression",
+            "version": "v1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/mtdowling/cron-expression.git",
+                "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
+                "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0|~5.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Cron": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due",
+            "keywords": [
+                "cron",
+                "schedule"
+            ],
+            "time": "2016-01-26 21:23:30"
+        },
+        {
+            "name": "mtdowling/jmespath.php",
+            "version": "2.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/jmespath/jmespath.php.git",
+                "reference": "192f93e43c2c97acde7694993ab171b3de284093"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/192f93e43c2c97acde7694993ab171b3de284093",
+                "reference": "192f93e43c2c97acde7694993ab171b3de284093",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "bin": [
+                "bin/jp.php"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "JmesPath\\": "src/"
+                },
+                "files": [
+                    "src/JmesPath.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "Declaratively specify how to extract elements from a JSON document",
+            "keywords": [
+                "json",
+                "jsonpath"
+            ],
+            "time": "2016-01-05 18:25:05"
+        },
+        {
+            "name": "nesbot/carbon",
+            "version": "1.21.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/briannesbitt/Carbon.git",
+                "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7b08ec6f75791e130012f206e3f7b0e76e18e3d7",
+                "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0",
+                "symfony/translation": "~2.6|~3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0|~5.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Carbon\\": "src/Carbon/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Brian Nesbitt",
+                    "email": "brian@nesbot.com",
+                    "homepage": "http://nesbot.com"
+                }
+            ],
+            "description": "A simple API extension for DateTime.",
+            "homepage": "http://carbon.nesbot.com",
+            "keywords": [
+                "date",
+                "datetime",
+                "time"
+            ],
+            "time": "2015-11-04 20:07:17"
+        },
+        {
+            "name": "nikic/php-parser",
+            "version": "v2.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nikic/PHP-Parser.git",
+                "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/47b254ea51f1d6d5dc04b9b299e88346bf2369e3",
+                "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3",
+                "shasum": ""
+            },
+            "require": {
+                "ext-tokenizer": "*",
+                "php": ">=5.4"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "bin": [
+                "bin/php-parse"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpParser\\": "lib/PhpParser"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Nikita Popov"
+                }
+            ],
+            "description": "A PHP parser written in PHP",
+            "keywords": [
+                "parser",
+                "php"
+            ],
+            "time": "2016-04-19 13:41:41"
+        },
+        {
+            "name": "paragonie/random_compat",
+            "version": "v1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/random_compat.git",
+                "reference": "c7e26a21ba357863de030f0b9e701c7d04593774"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774",
+                "reference": "c7e26a21ba357863de030f0b9e701c7d04593774",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*|5.*"
+            },
+            "suggest": {
+                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/random.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com"
+                }
+            ],
+            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+            "keywords": [
+                "csprng",
+                "pseudorandom",
+                "random"
+            ],
+            "time": "2016-03-18 20:34:03"
+        },
+        {
+            "name": "patchwork/utf8",
+            "version": "v1.3.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/tchwork/utf8.git",
+                "reference": "30ec6451aec7d2536f0af8fe535f70c764f2c47a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/tchwork/utf8/zipball/30ec6451aec7d2536f0af8fe535f70c764f2c47a",
+                "reference": "30ec6451aec7d2536f0af8fe535f70c764f2c47a",
+                "shasum": ""
+            },
+            "require": {
+                "lib-pcre": ">=7.3",
+                "php": ">=5.3.0"
+            },
+            "suggest": {
+                "ext-iconv": "Use iconv for best performance",
+                "ext-intl": "Use Intl for best performance",
+                "ext-mbstring": "Use Mbstring for best performance",
+                "ext-wfio": "Use WFIO for UTF-8 filesystem access on Windows"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Patchwork\\": "src/Patchwork/"
+                },
+                "classmap": [
+                    "src/Normalizer.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "(Apache-2.0 or GPL-2.0)"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                }
+            ],
+            "description": "Portable and performant UTF-8, Unicode and Grapheme Clusters for PHP",
+            "homepage": "https://github.com/tchwork/utf8",
+            "keywords": [
+                "grapheme",
+                "i18n",
+                "unicode",
+                "utf-8",
+                "utf8"
+            ],
+            "time": "2016-05-18 13:57:10"
+        },
+        {
+            "name": "phaza/laravel-postgis",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/njbarrett/laravel-postgis.git",
+                "reference": "1e1a0247fdc1e3310153468a73c67a961bdb454d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/njbarrett/laravel-postgis/zipball/1e1a0247fdc1e3310153468a73c67a961bdb454d",
+                "reference": "1e1a0247fdc1e3310153468a73c67a961bdb454d",
+                "shasum": ""
+            },
+            "require": {
+                "bosnadev/database": "~0.16",
+                "geo-io/wkb-parser": "^1.0",
+                "illuminate/database": "^5.2",
+                "jmikola/geojson": "^1.0",
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "codeclimate/php-test-reporter": "~0.3",
+                "illuminate/pagination": "~5.0",
+                "mockery/mockery": "0.9.*",
+                "phpunit/phpunit": "~4.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Phaza\\LaravelPostgis\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Peter Haza",
+                    "email": "peter.haza@gmail.com"
+                }
+            ],
+            "description": "Postgis extensions for laravel. Aims to make it easy to work with geometries from laravel models",
+            "time": "2016-05-18 07:54:54"
+        },
+        {
+            "name": "predis/predis",
+            "version": "v1.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nrk/predis.git",
+                "reference": "84060b9034d756b4d79641667d7f9efe1aeb8e04"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nrk/predis/zipball/84060b9034d756b4d79641667d7f9efe1aeb8e04",
+                "reference": "84060b9034d756b4d79641667d7f9efe1aeb8e04",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "suggest": {
+                "ext-curl": "Allows access to Webdis when paired with phpiredis",
+                "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Predis\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Daniele Alessandri",
+                    "email": "suppakilla@gmail.com",
+                    "homepage": "http://clorophilla.net"
+                }
+            ],
+            "description": "Flexible and feature-complete PHP client library for Redis",
+            "homepage": "http://github.com/nrk/predis",
+            "keywords": [
+                "nosql",
+                "predis",
+                "redis"
+            ],
+            "time": "2015-07-30 18:34:15"
+        },
+        {
+            "name": "psr/http-message",
+            "version": "1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-message.git",
+                "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
+                "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP messages",
+            "keywords": [
+                "http",
+                "http-message",
+                "psr",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "time": "2015-05-04 20:22:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
+                "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Psr\\Log\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "time": "2012-12-21 11:40:51"
+        },
+        {
+            "name": "psy/psysh",
+            "version": "v0.7.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/bobthecow/psysh.git",
+                "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e64e10b20f8d229cac76399e1f3edddb57a0f280",
+                "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280",
+                "shasum": ""
+            },
+            "require": {
+                "dnoegel/php-xdg-base-dir": "0.1",
+                "jakub-onderka/php-console-highlighter": "0.3.*",
+                "nikic/php-parser": "^1.2.1|~2.0",
+                "php": ">=5.3.9",
+                "symfony/console": "~2.3.10|^2.4.2|~3.0",
+                "symfony/var-dumper": "~2.7|~3.0"
+            },
+            "require-dev": {
+                "fabpot/php-cs-fixer": "~1.5",
+                "phpunit/phpunit": "~3.7|~4.0|~5.0",
+                "squizlabs/php_codesniffer": "~2.0",
+                "symfony/finder": "~2.1|~3.0"
+            },
+            "suggest": {
+                "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
+                "ext-pdo-sqlite": "The doc command requires SQLite to work.",
+                "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.",
+                "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history."
+            },
+            "bin": [
+                "bin/psysh"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-develop": "0.8.x-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/Psy/functions.php"
+                ],
+                "psr-4": {
+                    "Psy\\": "src/Psy/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Justin Hileman",
+                    "email": "justin@justinhileman.info",
+                    "homepage": "http://justinhileman.com"
+                }
+            ],
+            "description": "An interactive shell for modern PHP.",
+            "homepage": "http://psysh.org",
+            "keywords": [
+                "REPL",
+                "console",
+                "interactive",
+                "shell"
+            ],
+            "time": "2016-03-09 05:03:14"
+        },
+        {
+            "name": "ramsey/uuid",
+            "version": "3.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ramsey/uuid.git",
+                "reference": "b4fe3b7387cb323fd15ad5837cae992422c9fa5c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/b4fe3b7387cb323fd15ad5837cae992422c9fa5c",
+                "reference": "b4fe3b7387cb323fd15ad5837cae992422c9fa5c",
+                "shasum": ""
+            },
+            "require": {
+                "paragonie/random_compat": "^1.0|^2.0",
+                "php": ">=5.4"
+            },
+            "replace": {
+                "rhumsaa/uuid": "self.version"
+            },
+            "require-dev": {
+                "apigen/apigen": "^4.1",
+                "codeception/aspect-mock": "1.0.0",
+                "goaop/framework": "1.0.0-alpha.2",
+                "ircmaxell/random-lib": "^1.1",
+                "jakub-onderka/php-parallel-lint": "^0.9.0",
+                "mockery/mockery": "^0.9.4",
+                "moontoast/math": "^1.1",
+                "phpunit/phpunit": "^4.7|^5.0",
+                "satooshi/php-coveralls": "^0.6.1",
+                "squizlabs/php_codesniffer": "^2.3"
+            },
+            "suggest": {
+                "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
+                "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
+                "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
+                "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+                "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
+                "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Ramsey\\Uuid\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marijn Huizendveld",
+                    "email": "marijn.huizendveld@gmail.com"
+                },
+                {
+                    "name": "Thibaud Fabre",
+                    "email": "thibaud@aztech.io"
+                },
+                {
+                    "name": "Ben Ramsey",
+                    "email": "ben@benramsey.com",
+                    "homepage": "https://benramsey.com"
+                }
+            ],
+            "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
+            "homepage": "https://github.com/ramsey/uuid",
+            "keywords": [
+                "guid",
+                "identifier",
+                "uuid"
+            ],
+            "time": "2016-04-24 00:30:41"
+        },
+        {
+            "name": "spatie/laravel-glide",
+            "version": "2.3.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/laravel-glide.git",
+                "reference": "06bcfb85464a1202dfaa7494d1b1600c88c418e5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/laravel-glide/zipball/06bcfb85464a1202dfaa7494d1b1600c88c418e5",
+                "reference": "06bcfb85464a1202dfaa7494d1b1600c88c418e5",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/support": "5.*",
+                "league/glide": "0.3.*",
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "codeception/codeception": "2.*",
+                "mockery/mockery": "~0.9.3"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Spatie\\Glide": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be"
+                }
+            ],
+            "description": "A Glide Service Provider for Laravel",
+            "homepage": "https://github.com/spatie/laravel-glide",
+            "time": "2016-05-13 14:56:07"
+        },
+        {
+            "name": "spatie/laravel-medialibrary",
+            "version": "3.17.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/laravel-medialibrary.git",
+                "reference": "7f96cd3c709643ab0dde977936b98a7f75396d31"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/7f96cd3c709643ab0dde977936b98a7f75396d31",
+                "reference": "7f96cd3c709643ab0dde977936b98a7f75396d31",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/bus": "~5.1.16|~5.2.0",
+                "illuminate/console": "~5.1.16|~5.2.0",
+                "illuminate/database": "~5.1.16|~5.2.0",
+                "illuminate/support": "~5.1.16|~5.2.0",
+                "php": "^5.5|^7.0",
+                "spatie/laravel-glide": "^2.2.4",
+                "spatie/pdf-to-image": "^1.0.1",
+                "spatie/string": "^2.0"
+            },
+            "require-dev": {
+                "doctrine/dbal": "^2.5.2",
+                "mockery/mockery": "^0.9.4",
+                "orchestra/testbench": "^3.0",
+                "phpunit/phpunit": "^4.0",
+                "scrutinizer/ocular": "^1.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\MediaLibrary\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://murze.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Associate files with Eloquent models",
+            "homepage": "https://github.com/spatie/laravel-medialibrary",
+            "keywords": [
+                "cms",
+                "laravel",
+                "laravel-medialibrary",
+                "media",
+                "spatie"
+            ],
+            "time": "2016-04-12 09:57:52"
+        },
+        {
+            "name": "spatie/pdf-to-image",
+            "version": "1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/pdf-to-image.git",
+                "reference": "c08dac65f0f857dd4d467d40794772be5a75d6de"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/pdf-to-image/zipball/c08dac65f0f857dd4d467d40794772be5a75d6de",
+                "reference": "c08dac65f0f857dd4d467d40794772be5a75d6de",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*",
+                "scrutinizer/ocular": "~1.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\PdfToImage\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Convert a pdf to an image",
+            "homepage": "https://github.com/spatie/pdf-to-image",
+            "keywords": [
+                "convert",
+                "image",
+                "pdf",
+                "pdf-to-image",
+                "spatie"
+            ],
+            "time": "2016-04-29 08:02:56"
+        },
+        {
+            "name": "spatie/string",
+            "version": "2.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/string.git",
+                "reference": "1843189c711be4dcf62b655824f2f17120c2dc7d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/string/zipball/1843189c711be4dcf62b655824f2f17120c2dc7d",
+                "reference": "1843189c711be4dcf62b655824f2f17120c2dc7d",
+                "shasum": ""
+            },
+            "require": {
+                "anahkiasen/underscore-php": "^2.0",
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*",
+                "scrutinizer/ocular": "~1.1"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/string_functions.php"
+                ],
+                "psr-4": {
+                    "Spatie\\String\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://murze.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "String handling evolved",
+            "homepage": "https://github.com/spatie/string",
+            "keywords": [
+                "handling",
+                "handy",
+                "spatie",
+                "string"
+            ],
+            "time": "2015-11-02 13:00:37"
+        },
+        {
+            "name": "swiftmailer/swiftmailer",
+            "version": "v5.4.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/swiftmailer/swiftmailer.git",
+                "reference": "d8db871a54619458a805229a057ea2af33c753e8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/d8db871a54619458a805229a057ea2af33c753e8",
+                "reference": "d8db871a54619458a805229a057ea2af33c753e8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "mockery/mockery": "~0.9.1,<0.9.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.4-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "lib/swift_required.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Chris Corbyn"
+                },
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "Swiftmailer, free feature-rich PHP mailer",
+            "homepage": "http://swiftmailer.org",
+            "keywords": [
+                "email",
+                "mail",
+                "mailer"
+            ],
+            "time": "2016-05-01 08:45:47"
+        },
+        {
+            "name": "symfony/console",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/console.git",
+                "reference": "34a214710e0714b6efcf40ba3cd1e31373a97820"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/console/zipball/34a214710e0714b6efcf40ba3cd1e31373a97820",
+                "reference": "34a214710e0714b6efcf40ba3cd1e31373a97820",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/event-dispatcher": "~2.8|~3.0",
+                "symfony/process": "~2.8|~3.0"
+            },
+            "suggest": {
+                "psr/log": "For using the console logger",
+                "symfony/event-dispatcher": "",
+                "symfony/process": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Console\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Console Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-04-28 09:48:42"
+        },
+        {
+            "name": "symfony/debug",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/debug.git",
+                "reference": "a06d10888a45afd97534506afb058ec38d9ba35b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/debug/zipball/a06d10888a45afd97534506afb058ec38d9ba35b",
+                "reference": "a06d10888a45afd97534506afb058ec38d9ba35b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "psr/log": "~1.0"
+            },
+            "conflict": {
+                "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
+            },
+            "require-dev": {
+                "symfony/class-loader": "~2.8|~3.0",
+                "symfony/http-kernel": "~2.8|~3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Debug\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Debug Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-03-30 10:41:14"
+        },
+        {
+            "name": "symfony/event-dispatcher",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/event-dispatcher.git",
+                "reference": "807dde98589f9b2b00624dca326740380d78dbbc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/807dde98589f9b2b00624dca326740380d78dbbc",
+                "reference": "807dde98589f9b2b00624dca326740380d78dbbc",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/config": "~2.8|~3.0",
+                "symfony/dependency-injection": "~2.8|~3.0",
+                "symfony/expression-language": "~2.8|~3.0",
+                "symfony/stopwatch": "~2.8|~3.0"
+            },
+            "suggest": {
+                "symfony/dependency-injection": "",
+                "symfony/http-kernel": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\EventDispatcher\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony EventDispatcher Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-05-05 06:56:13"
+        },
+        {
+            "name": "symfony/finder",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/finder.git",
+                "reference": "c54e407b35bc098916704e9fd090da21da4c4f52"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/c54e407b35bc098916704e9fd090da21da4c4f52",
+                "reference": "c54e407b35bc098916704e9fd090da21da4c4f52",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Finder\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Finder Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-03-10 11:13:05"
+        },
+        {
+            "name": "symfony/http-foundation",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/http-foundation.git",
+                "reference": "18b24bc32d2495ae79d76e777368786a6536fe31"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/18b24bc32d2495ae79d76e777368786a6536fe31",
+                "reference": "18b24bc32d2495ae79d76e777368786a6536fe31",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/polyfill-mbstring": "~1.1"
+            },
+            "require-dev": {
+                "symfony/expression-language": "~2.8|~3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\HttpFoundation\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony HttpFoundation Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-04-12 18:09:53"
+        },
+        {
+            "name": "symfony/http-kernel",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/http-kernel.git",
+                "reference": "6a5010978edf0a9646342232531e53bfc7abbcd3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6a5010978edf0a9646342232531e53bfc7abbcd3",
+                "reference": "6a5010978edf0a9646342232531e53bfc7abbcd3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "psr/log": "~1.0",
+                "symfony/debug": "~2.8|~3.0",
+                "symfony/event-dispatcher": "~2.8|~3.0",
+                "symfony/http-foundation": "~2.8|~3.0"
+            },
+            "conflict": {
+                "symfony/config": "<2.8"
+            },
+            "require-dev": {
+                "symfony/browser-kit": "~2.8|~3.0",
+                "symfony/class-loader": "~2.8|~3.0",
+                "symfony/config": "~2.8|~3.0",
+                "symfony/console": "~2.8|~3.0",
+                "symfony/css-selector": "~2.8|~3.0",
+                "symfony/dependency-injection": "~2.8|~3.0",
+                "symfony/dom-crawler": "~2.8|~3.0",
+                "symfony/expression-language": "~2.8|~3.0",
+                "symfony/finder": "~2.8|~3.0",
+                "symfony/process": "~2.8|~3.0",
+                "symfony/routing": "~2.8|~3.0",
+                "symfony/stopwatch": "~2.8|~3.0",
+                "symfony/templating": "~2.8|~3.0",
+                "symfony/translation": "~2.8|~3.0",
+                "symfony/var-dumper": "~2.8|~3.0"
+            },
+            "suggest": {
+                "symfony/browser-kit": "",
+                "symfony/class-loader": "",
+                "symfony/config": "",
+                "symfony/console": "",
+                "symfony/dependency-injection": "",
+                "symfony/finder": "",
+                "symfony/var-dumper": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\HttpKernel\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony HttpKernel Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-05-09 22:13:13"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "dff51f72b0706335131b00a7f49606168c582594"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
+                "reference": "dff51f72b0706335131b00a7f49606168c582594",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2016-05-18 14:26:46"
+        },
+        {
+            "name": "symfony/polyfill-php56",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php56.git",
+                "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/3edf57a8fbf9a927533344cef65ad7e1cf31030a",
+                "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "symfony/polyfill-util": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php56\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2016-05-18 14:26:46"
+        },
+        {
+            "name": "symfony/polyfill-util",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-util.git",
+                "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/ef830ce3d218e622b221d6bfad42c751d974bf99",
+                "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Util\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony utilities for portability of PHP codes",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compat",
+                "compatibility",
+                "polyfill",
+                "shim"
+            ],
+            "time": "2016-05-18 14:26:46"
+        },
+        {
+            "name": "symfony/process",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/process.git",
+                "reference": "53f9407c0bb1c5a79127db8f7bfe12f0f6f3dcdb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/process/zipball/53f9407c0bb1c5a79127db8f7bfe12f0f6f3dcdb",
+                "reference": "53f9407c0bb1c5a79127db8f7bfe12f0f6f3dcdb",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Process\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Process Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-04-14 15:30:28"
+        },
+        {
+            "name": "symfony/routing",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/routing.git",
+                "reference": "a6cd168310066176599442aa21f5da86c3f8e0b3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/routing/zipball/a6cd168310066176599442aa21f5da86c3f8e0b3",
+                "reference": "a6cd168310066176599442aa21f5da86c3f8e0b3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "conflict": {
+                "symfony/config": "<2.8"
+            },
+            "require-dev": {
+                "doctrine/annotations": "~1.0",
+                "doctrine/common": "~2.2",
+                "psr/log": "~1.0",
+                "symfony/config": "~2.8|~3.0",
+                "symfony/expression-language": "~2.8|~3.0",
+                "symfony/http-foundation": "~2.8|~3.0",
+                "symfony/yaml": "~2.8|~3.0"
+            },
+            "suggest": {
+                "doctrine/annotations": "For using the annotation loader",
+                "symfony/config": "For using the all-in-one router or any loader",
+                "symfony/dependency-injection": "For loading routes from a service",
+                "symfony/expression-language": "For using expression matching",
+                "symfony/http-foundation": "For using a Symfony Request object",
+                "symfony/yaml": "For using the YAML loader"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Routing\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Routing Component",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "router",
+                "routing",
+                "uri",
+                "url"
+            ],
+            "time": "2016-05-03 12:23:49"
+        },
+        {
+            "name": "symfony/translation",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/translation.git",
+                "reference": "f7a07af51ea067745a521dab1e3152044a2fb1f2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/translation/zipball/f7a07af51ea067745a521dab1e3152044a2fb1f2",
+                "reference": "f7a07af51ea067745a521dab1e3152044a2fb1f2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "conflict": {
+                "symfony/config": "<2.8"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/config": "~2.8|~3.0",
+                "symfony/intl": "~2.8|~3.0",
+                "symfony/yaml": "~2.8|~3.0"
+            },
+            "suggest": {
+                "psr/log": "To use logging capability in translator",
+                "symfony/config": "",
+                "symfony/yaml": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Translation\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Translation Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-03-25 01:41:20"
+        },
+        {
+            "name": "symfony/var-dumper",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/var-dumper.git",
+                "reference": "0e918c269093ba4c77fca14e9424fa74ed16f1a6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e918c269093ba4c77fca14e9424fa74ed16f1a6",
+                "reference": "0e918c269093ba4c77fca14e9424fa74ed16f1a6",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "require-dev": {
+                "twig/twig": "~1.20|~2.0"
+            },
+            "suggest": {
+                "ext-symfony_debug": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "Resources/functions/dump.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Component\\VarDumper\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony mechanism for exploring and dumping PHP variables",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "debug",
+                "dump"
+            ],
+            "time": "2016-04-25 11:17:47"
+        },
+        {
+            "name": "themattharris/tmhoauth",
+            "version": "0.8.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/themattharris/tmhOAuth.git",
+                "reference": "455552d6c57549632644b6c9ac9204766be2b5ee"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/themattharris/tmhOAuth/zipball/455552d6c57549632644b6c9ac9204766be2b5ee",
+                "reference": "455552d6c57549632644b6c9ac9204766be2b5ee",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "tmhOAuth": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "themattharris",
+                    "email": "matt@themattharris.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "An OAuth library written in PHP by @themattharris",
+            "keywords": [
+                "oauth",
+                "twitter"
+            ],
+            "time": "2014-08-06 22:29:35"
+        },
+        {
+            "name": "thujohn/twitter",
+            "version": "2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thujohn/twitter.git",
+                "reference": "137dfa006ad06b956d579ff3ce0ffa5d03506188"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thujohn/twitter/zipball/137dfa006ad06b956d579ff3ce0ffa5d03506188",
+                "reference": "137dfa006ad06b956d579ff3ce0ffa5d03506188",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/support": "4.*|5.*",
+                "php": ">=5.4.0",
+                "themattharris/tmhoauth": "0.8.4"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Thujohn\\Twitter": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "thujohn",
+                    "email": "jonathan.thuau@gmail.com"
+                }
+            ],
+            "description": "Twitter API for Laravel",
+            "keywords": [
+                "laravel",
+                "laravel4",
+                "laravel5",
+                "twitter"
+            ],
+            "time": "2016-04-08 11:43:15"
+        },
+        {
+            "name": "vlucas/phpdotenv",
+            "version": "v2.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/vlucas/phpdotenv.git",
+                "reference": "63f37b9395e8041cd4313129c08ece896d06ca8e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/63f37b9395e8041cd4313129c08ece896d06ca8e",
+                "reference": "63f37b9395e8041cd4313129c08ece896d06ca8e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8 || ^5.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Dotenv\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause-Attribution"
+            ],
+            "authors": [
+                {
+                    "name": "Vance Lucas",
+                    "email": "vance@vancelucas.com",
+                    "homepage": "http://www.vancelucas.com"
+                }
+            ],
+            "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
+            "keywords": [
+                "dotenv",
+                "env",
+                "environment"
+            ],
+            "time": "2016-04-15 10:48:49"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "barryvdh/laravel-debugbar",
+            "version": "v2.2.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/barryvdh/laravel-debugbar.git",
+                "reference": "c291e58d0a13953e0f68d99182ee77ebc693edc0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/c291e58d0a13953e0f68d99182ee77ebc693edc0",
+                "reference": "c291e58d0a13953e0f68d99182ee77ebc693edc0",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/support": "5.1.*|5.2.*",
+                "maximebf/debugbar": "~1.11.0",
+                "php": ">=5.5.9",
+                "symfony/finder": "~2.7|~3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Barryvdh\\Debugbar\\": "src/"
+                },
+                "files": [
+                    "src/helpers.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Barry vd. Heuvel",
+                    "email": "barryvdh@gmail.com"
+                }
+            ],
+            "description": "PHP Debugbar integration for Laravel",
+            "keywords": [
+                "debug",
+                "debugbar",
+                "laravel",
+                "profiler",
+                "webprofiler"
+            ],
+            "time": "2016-05-11 13:54:43"
+        },
+        {
+            "name": "doctrine/instantiator",
+            "version": "1.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/instantiator.git",
+                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
+                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3,<8.0-DEV"
+            },
+            "require-dev": {
+                "athletic/athletic": "~0.1.8",
+                "ext-pdo": "*",
+                "ext-phar": "*",
+                "phpunit/phpunit": "~4.0",
+                "squizlabs/php_codesniffer": "~2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marco Pivetta",
+                    "email": "ocramius@gmail.com",
+                    "homepage": "http://ocramius.github.com/"
+                }
+            ],
+            "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+            "homepage": "https://github.com/doctrine/instantiator",
+            "keywords": [
+                "constructor",
+                "instantiate"
+            ],
+            "time": "2015-06-14 21:17:01"
+        },
+        {
+            "name": "filp/whoops",
+            "version": "2.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/filp/whoops.git",
+                "reference": "d13505b240a6f580bc75ba591da30299d6cb0eec"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/filp/whoops/zipball/d13505b240a6f580bc75ba591da30299d6cb0eec",
+                "reference": "d13505b240a6f580bc75ba591da30299d6cb0eec",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "require-dev": {
+                "mockery/mockery": "0.9.*",
+                "phpunit/phpunit": "^4.8 || ^5.0",
+                "symfony/var-dumper": "~3.0"
+            },
+            "suggest": {
+                "symfony/var-dumper": "Pretty print complex values better with var-dumper available",
+                "whoops/soap": "Formats errors as SOAP responses"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Whoops\\": "src/Whoops/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Filipe Dobreira",
+                    "homepage": "https://github.com/filp",
+                    "role": "Developer"
+                }
+            ],
+            "description": "php error handling for cool kids",
+            "homepage": "https://github.com/filp/whoops",
+            "keywords": [
+                "error",
+                "exception",
+                "handling",
+                "library",
+                "whoops",
+                "zf2"
+            ],
+            "time": "2016-04-07 06:16:25"
+        },
+        {
+            "name": "fzaninotto/faker",
+            "version": "v1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/fzaninotto/Faker.git",
+                "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123",
+                "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.3|^7.0"
+            },
+            "require-dev": {
+                "ext-intl": "*",
+                "phpunit/phpunit": "~4.0",
+                "squizlabs/php_codesniffer": "~1.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": []
+            },
+            "autoload": {
+                "psr-4": {
+                    "Faker\\": "src/Faker/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "François Zaninotto"
+                }
+            ],
+            "description": "Faker is a PHP library that generates fake data for you.",
+            "keywords": [
+                "data",
+                "faker",
+                "fixtures"
+            ],
+            "time": "2016-04-29 12:21:54"
+        },
+        {
+            "name": "hamcrest/hamcrest-php",
+            "version": "v1.2.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/hamcrest/hamcrest-php.git",
+                "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c",
+                "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "replace": {
+                "cordoval/hamcrest-php": "*",
+                "davedevelopment/hamcrest-php": "*",
+                "kodova/hamcrest-php": "*"
+            },
+            "require-dev": {
+                "phpunit/php-file-iterator": "1.3.3",
+                "satooshi/php-coveralls": "dev-master"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "hamcrest"
+                ],
+                "files": [
+                    "hamcrest/Hamcrest.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD"
+            ],
+            "description": "This is the PHP port of Hamcrest Matchers",
+            "keywords": [
+                "test"
+            ],
+            "time": "2015-05-11 14:41:42"
+        },
+        {
+            "name": "maximebf/debugbar",
+            "version": "v1.11.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/maximebf/php-debugbar.git",
+                "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/d9302891c1f0a0ac5a4f66725163a00537c6359f",
+                "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0",
+                "psr/log": "^1.0",
+                "symfony/var-dumper": "^2.6|^3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.0|^5.0"
+            },
+            "suggest": {
+                "kriswallsmith/assetic": "The best way to manage assets",
+                "monolog/monolog": "Log using Monolog",
+                "predis/predis": "Redis storage"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.11-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "DebugBar\\": "src/DebugBar/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Maxime Bouroumeau-Fuseau",
+                    "email": "maxime.bouroumeau@gmail.com",
+                    "homepage": "http://maximebf.com"
+                },
+                {
+                    "name": "Barry vd. Heuvel",
+                    "email": "barryvdh@gmail.com"
+                }
+            ],
+            "description": "Debug bar in the browser for php application",
+            "homepage": "https://github.com/maximebf/php-debugbar",
+            "keywords": [
+                "debug",
+                "debugbar"
+            ],
+            "time": "2016-01-22 12:22:23"
+        },
+        {
+            "name": "mockery/mockery",
+            "version": "0.9.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/padraic/mockery.git",
+                "reference": "70bba85e4aabc9449626651f48b9018ede04f86b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/padraic/mockery/zipball/70bba85e4aabc9449626651f48b9018ede04f86b",
+                "reference": "70bba85e4aabc9449626651f48b9018ede04f86b",
+                "shasum": ""
+            },
+            "require": {
+                "hamcrest/hamcrest-php": "~1.1",
+                "lib-pcre": ">=7.0",
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "0.9.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Mockery": "library/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Padraic Brady",
+                    "email": "padraic.brady@gmail.com",
+                    "homepage": "http://blog.astrumfutura.com"
+                },
+                {
+                    "name": "Dave Marshall",
+                    "email": "dave.marshall@atstsolutions.co.uk",
+                    "homepage": "http://davedevelopment.co.uk"
+                }
+            ],
+            "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.",
+            "homepage": "http://github.com/padraic/mockery",
+            "keywords": [
+                "BDD",
+                "TDD",
+                "library",
+                "mock",
+                "mock objects",
+                "mockery",
+                "stub",
+                "test",
+                "test double",
+                "testing"
+            ],
+            "time": "2015-04-02 19:54:00"
+        },
+        {
+            "name": "phpdocumentor/reflection-docblock",
+            "version": "2.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+                "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
+                "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "suggest": {
+                "dflydev/markdown": "~1.0",
+                "erusev/parsedown": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "phpDocumentor": [
+                        "src/"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mike van Riel",
+                    "email": "mike.vanriel@naenius.com"
+                }
+            ],
+            "time": "2015-02-03 12:10:50"
+        },
+        {
+            "name": "phpspec/prophecy",
+            "version": "v1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpspec/prophecy.git",
+                "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
+                "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/instantiator": "^1.0.2",
+                "php": "^5.3|^7.0",
+                "phpdocumentor/reflection-docblock": "~2.0",
+                "sebastian/comparator": "~1.1",
+                "sebastian/recursion-context": "~1.0"
+            },
+            "require-dev": {
+                "phpspec/phpspec": "~2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.5.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Prophecy\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Konstantin Kudryashov",
+                    "email": "ever.zet@gmail.com",
+                    "homepage": "http://everzet.com"
+                },
+                {
+                    "name": "Marcello Duarte",
+                    "email": "marcello.duarte@gmail.com"
+                }
+            ],
+            "description": "Highly opinionated mocking framework for PHP 5.3+",
+            "homepage": "https://github.com/phpspec/prophecy",
+            "keywords": [
+                "Double",
+                "Dummy",
+                "fake",
+                "mock",
+                "spy",
+                "stub"
+            ],
+            "time": "2016-02-15 07:46:21"
+        },
+        {
+            "name": "phpunit/php-code-coverage",
+            "version": "2.2.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "phpunit/php-file-iterator": "~1.3",
+                "phpunit/php-text-template": "~1.2",
+                "phpunit/php-token-stream": "~1.3",
+                "sebastian/environment": "^1.3.2",
+                "sebastian/version": "~1.0"
+            },
+            "require-dev": {
+                "ext-xdebug": ">=2.1.4",
+                "phpunit/phpunit": "~4"
+            },
+            "suggest": {
+                "ext-dom": "*",
+                "ext-xdebug": ">=2.2.1",
+                "ext-xmlwriter": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+            "keywords": [
+                "coverage",
+                "testing",
+                "xunit"
+            ],
+            "time": "2015-10-06 15:47:00"
+        },
+        {
+            "name": "phpunit/php-file-iterator",
+            "version": "1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+                "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
+                "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+            "keywords": [
+                "filesystem",
+                "iterator"
+            ],
+            "time": "2015-06-21 13:08:43"
+        },
+        {
+            "name": "phpunit/php-text-template",
+            "version": "1.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-text-template.git",
+                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Simple template engine.",
+            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+            "keywords": [
+                "template"
+            ],
+            "time": "2015-06-21 13:50:34"
+        },
+        {
+            "name": "phpunit/php-timer",
+            "version": "1.0.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-timer.git",
+                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
+                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4|~5"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Utility class for timing",
+            "homepage": "https://github.com/sebastianbergmann/php-timer/",
+            "keywords": [
+                "timer"
+            ],
+            "time": "2016-05-12 18:03:57"
+        },
+        {
+            "name": "phpunit/php-token-stream",
+            "version": "1.4.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
+                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
+                "shasum": ""
+            },
+            "require": {
+                "ext-tokenizer": "*",
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Wrapper around PHP's tokenizer extension.",
+            "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+            "keywords": [
+                "tokenizer"
+            ],
+            "time": "2015-09-15 10:49:45"
+        },
+        {
+            "name": "phpunit/phpunit",
+            "version": "4.8.26",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/phpunit.git",
+                "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74",
+                "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-pcre": "*",
+                "ext-reflection": "*",
+                "ext-spl": "*",
+                "php": ">=5.3.3",
+                "phpspec/prophecy": "^1.3.1",
+                "phpunit/php-code-coverage": "~2.1",
+                "phpunit/php-file-iterator": "~1.4",
+                "phpunit/php-text-template": "~1.2",
+                "phpunit/php-timer": "^1.0.6",
+                "phpunit/phpunit-mock-objects": "~2.3",
+                "sebastian/comparator": "~1.1",
+                "sebastian/diff": "~1.2",
+                "sebastian/environment": "~1.3",
+                "sebastian/exporter": "~1.2",
+                "sebastian/global-state": "~1.0",
+                "sebastian/version": "~1.0",
+                "symfony/yaml": "~2.1|~3.0"
+            },
+            "suggest": {
+                "phpunit/php-invoker": "~1.1"
+            },
+            "bin": [
+                "phpunit"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.8.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "The PHP Unit Testing framework.",
+            "homepage": "https://phpunit.de/",
+            "keywords": [
+                "phpunit",
+                "testing",
+                "xunit"
+            ],
+            "time": "2016-05-17 03:09:28"
+        },
+        {
+            "name": "phpunit/phpunit-mock-objects",
+            "version": "2.3.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
+                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/instantiator": "^1.0.2",
+                "php": ">=5.3.3",
+                "phpunit/php-text-template": "~1.2",
+                "sebastian/exporter": "~1.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "suggest": {
+                "ext-soap": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.3.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Mock Object library for PHPUnit",
+            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+            "keywords": [
+                "mock",
+                "xunit"
+            ],
+            "time": "2015-10-02 06:51:40"
+        },
+        {
+            "name": "sebastian/comparator",
+            "version": "1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/comparator.git",
+                "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
+                "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "sebastian/diff": "~1.2",
+                "sebastian/exporter": "~1.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Volker Dusch",
+                    "email": "github@wallbash.com"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@2bepublished.at"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides the functionality to compare PHP values for equality",
+            "homepage": "http://www.github.com/sebastianbergmann/comparator",
+            "keywords": [
+                "comparator",
+                "compare",
+                "equality"
+            ],
+            "time": "2015-07-26 15:48:44"
+        },
+        {
+            "name": "sebastian/diff",
+            "version": "1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/diff.git",
+                "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
+                "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Kore Nordmann",
+                    "email": "mail@kore-nordmann.de"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Diff implementation",
+            "homepage": "https://github.com/sebastianbergmann/diff",
+            "keywords": [
+                "diff"
+            ],
+            "time": "2015-12-08 07:14:41"
+        },
+        {
+            "name": "sebastian/environment",
+            "version": "1.3.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/environment.git",
+                "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716",
+                "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.3.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides functionality to handle HHVM/PHP environments",
+            "homepage": "http://www.github.com/sebastianbergmann/environment",
+            "keywords": [
+                "Xdebug",
+                "environment",
+                "hhvm"
+            ],
+            "time": "2016-05-17 03:18:57"
+        },
+        {
+            "name": "sebastian/exporter",
+            "version": "1.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/exporter.git",
+                "reference": "7ae5513327cb536431847bcc0c10edba2701064e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
+                "reference": "7ae5513327cb536431847bcc0c10edba2701064e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "sebastian/recursion-context": "~1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Volker Dusch",
+                    "email": "github@wallbash.com"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@2bepublished.at"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Adam Harvey",
+                    "email": "aharvey@php.net"
+                }
+            ],
+            "description": "Provides the functionality to export PHP variables for visualization",
+            "homepage": "http://www.github.com/sebastianbergmann/exporter",
+            "keywords": [
+                "export",
+                "exporter"
+            ],
+            "time": "2015-06-21 07:55:53"
+        },
+        {
+            "name": "sebastian/global-state",
+            "version": "1.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/global-state.git",
+                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
+                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.2"
+            },
+            "suggest": {
+                "ext-uopz": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Snapshotting of global state",
+            "homepage": "http://www.github.com/sebastianbergmann/global-state",
+            "keywords": [
+                "global state"
+            ],
+            "time": "2015-10-12 03:26:01"
+        },
+        {
+            "name": "sebastian/recursion-context",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/recursion-context.git",
+                "reference": "913401df809e99e4f47b27cdd781f4a258d58791"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
+                "reference": "913401df809e99e4f47b27cdd781f4a258d58791",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Adam Harvey",
+                    "email": "aharvey@php.net"
+                }
+            ],
+            "description": "Provides functionality to recursively process PHP variables",
+            "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+            "time": "2015-11-11 19:50:13"
+        },
+        {
+            "name": "sebastian/version",
+            "version": "1.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/version.git",
+                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+            "homepage": "https://github.com/sebastianbergmann/version",
+            "time": "2015-06-21 13:59:46"
+        },
+        {
+            "name": "symfony/css-selector",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/css-selector.git",
+                "reference": "65e764f404685f2dc20c057e889b3ad04b2e2db0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/css-selector/zipball/65e764f404685f2dc20c057e889b3ad04b2e2db0",
+                "reference": "65e764f404685f2dc20c057e889b3ad04b2e2db0",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\CssSelector\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jean-François Simon",
+                    "email": "jeanfrancois.simon@sensiolabs.com"
+                },
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony CssSelector Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-03-04 07:55:57"
+        },
+        {
+            "name": "symfony/dom-crawler",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/dom-crawler.git",
+                "reference": "49b588841225b205700e5122fa01911cabada857"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/49b588841225b205700e5122fa01911cabada857",
+                "reference": "49b588841225b205700e5122fa01911cabada857",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "require-dev": {
+                "symfony/css-selector": "~2.8|~3.0"
+            },
+            "suggest": {
+                "symfony/css-selector": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\DomCrawler\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony DomCrawler Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-04-12 18:09:53"
+        },
+        {
+            "name": "symfony/yaml",
+            "version": "v3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "0047c8366744a16de7516622c5b7355336afae96"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96",
+                "reference": "0047c8366744a16de7516622c5b7355336afae96",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Yaml Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-03-04 07:55:57"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": {
+        "jonnybarnes/unicode-tools": 20,
+        "jonnybarnes/indieweb": 20,
+        "jonnybarnes/webmentions-parser": 20,
+        "phaza/laravel-postgis": 20
+    },
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "ext-intl": "*",
+        "php": ">=7.0.0"
+    },
+    "platform-dev": []
+}
diff --git a/config/app.php b/config/app.php
new file mode 100644
index 00000000..1bcc5c20
--- /dev/null
+++ b/config/app.php
@@ -0,0 +1,241 @@
+ env('APP_ENV', 'production'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Application Debug Mode
+    |--------------------------------------------------------------------------
+    |
+    | When your application is in debug mode, detailed error messages with
+    | stack traces will be shown on every error that occurs within your
+    | application. If disabled, a simple generic error page is shown.
+    |
+    */
+
+    'debug' => env('APP_DEBUG', false),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Application URL
+    |--------------------------------------------------------------------------
+    |
+    | This URL is used by the console to properly generate URLs when using
+    | the Artisan command line tool. You should set this to the root of
+    | your application so that it is used when running Artisan tasks.
+    |
+    */
+
+    'url' => env('APP_URL', 'http://localhost'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Application Short URL
+    |--------------------------------------------------------------------------
+    |
+    | The short URL for the application
+    |
+    */
+
+    'shorturl' => env('APP_SHORTURL', 'http://shorturl.local'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Application Timezone
+    |--------------------------------------------------------------------------
+    |
+    | Here you may specify the default timezone for your application, which
+    | will be used by the PHP date and date-time functions. We have gone
+    | ahead and set this to a sensible default for you out of the box.
+    |
+    */
+
+    'timezone' => env('APP_TIMEZONE', 'UTC'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Application Locale Configuration
+    |--------------------------------------------------------------------------
+    |
+    | The application locale determines the default locale that will be used
+    | by the translation service provider. You are free to set this value
+    | to any of the locales which will be supported by the application.
+    |
+    */
+
+    'locale' => env('APP_LANG', 'en'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Application Fallback Locale
+    |--------------------------------------------------------------------------
+    |
+    | The fallback locale determines the locale to use when the current one
+    | is not available. You may change the value to correspond to any of
+    | the language folders that are provided through your application.
+    |
+    */
+
+    'fallback_locale' => 'en',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Encryption Key
+    |--------------------------------------------------------------------------
+    |
+    | This key is used by the Illuminate encrypter service and should be set
+    | to a random, 32 character string, otherwise these encrypted strings
+    | will not be safe. Please do this before deploying an application!
+    |
+    */
+
+    'key' => env('APP_KEY'),
+
+    'cipher' => 'AES-256-CBC',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Logging Configuration
+    |--------------------------------------------------------------------------
+    |
+    | Here you may configure the log settings for your application. Out of
+    | the box, Laravel uses the Monolog PHP logging library. This gives
+    | you a variety of powerful log handlers / formatters to utilize.
+    |
+    | Available Settings: "single", "daily", "syslog", "errorlog"
+    |
+    */
+
+    'log' => env('APP_LOG', 'single'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Autoloaded Service Providers
+    |--------------------------------------------------------------------------
+    |
+    | The service providers listed here will be automatically loaded on the
+    | request to your application. Feel free to add your own services to
+    | this array to grant expanded functionality to your applications.
+    |
+    */
+
+    'providers' => [
+
+        /*
+         * Laravel Framework Service Providers...
+         */
+        Illuminate\Auth\AuthServiceProvider::class,
+        Illuminate\Broadcasting\BroadcastServiceProvider::class,
+        Illuminate\Bus\BusServiceProvider::class,
+        Illuminate\Cache\CacheServiceProvider::class,
+        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
+        Illuminate\Cookie\CookieServiceProvider::class,
+        Illuminate\Database\DatabaseServiceProvider::class,
+        Illuminate\Encryption\EncryptionServiceProvider::class,
+        Illuminate\Filesystem\FilesystemServiceProvider::class,
+        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
+        Illuminate\Hashing\HashServiceProvider::class,
+        Illuminate\Mail\MailServiceProvider::class,
+        Illuminate\Pagination\PaginationServiceProvider::class,
+        Illuminate\Pipeline\PipelineServiceProvider::class,
+        Illuminate\Queue\QueueServiceProvider::class,
+        Illuminate\Redis\RedisServiceProvider::class,
+        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
+        Illuminate\Session\SessionServiceProvider::class,
+        Illuminate\Translation\TranslationServiceProvider::class,
+        Illuminate\Validation\ValidationServiceProvider::class,
+        Illuminate\View\ViewServiceProvider::class,
+
+        /*
+         * Application Service Providers...
+         */
+        App\Providers\AppServiceProvider::class,
+        App\Providers\AuthServiceProvider::class,
+        App\Providers\EventServiceProvider::class,
+        App\Providers\RouteServiceProvider::class,
+
+        /*
+         * Laravel Debugbar
+         */
+        Barryvdh\Debugbar\ServiceProvider::class,
+
+        /*
+         * Thujohn’s Twitter API client
+         */
+        Thujohn\Twitter\TwitterServiceProvider::class,
+
+        /*
+         * Laravel Medialibrary
+         */
+        Spatie\MediaLibrary\MediaLibraryServiceProvider::class,
+
+        /*
+         * Phaza’s Postgis library
+         */
+        Phaza\LaravelPostgis\DatabaseServiceProvider::class,
+
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Class Aliases
+    |--------------------------------------------------------------------------
+    |
+    | This array of class aliases will be registered when this application
+    | is started. However, feel free to register as many as you wish as
+    | the aliases are "lazy" loaded so they don't hinder performance.
+    |
+    */
+
+    'aliases' => [
+
+        'App' => Illuminate\Support\Facades\App::class,
+        'Artisan' => Illuminate\Support\Facades\Artisan::class,
+        'Auth' => Illuminate\Support\Facades\Auth::class,
+        'Blade' => Illuminate\Support\Facades\Blade::class,
+        'Cache' => Illuminate\Support\Facades\Cache::class,
+        'Config' => Illuminate\Support\Facades\Config::class,
+        'Cookie' => Illuminate\Support\Facades\Cookie::class,
+        'Crypt' => Illuminate\Support\Facades\Crypt::class,
+        'DB' => Illuminate\Support\Facades\DB::class,
+        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
+        'Event' => Illuminate\Support\Facades\Event::class,
+        'File' => Illuminate\Support\Facades\File::class,
+        'Gate' => Illuminate\Support\Facades\Gate::class,
+        'Hash' => Illuminate\Support\Facades\Hash::class,
+        'Lang' => Illuminate\Support\Facades\Lang::class,
+        'Log' => Illuminate\Support\Facades\Log::class,
+        'Mail' => Illuminate\Support\Facades\Mail::class,
+        'Password' => Illuminate\Support\Facades\Password::class,
+        'Queue' => Illuminate\Support\Facades\Queue::class,
+        'Redirect' => Illuminate\Support\Facades\Redirect::class,
+        'Redis' => Illuminate\Support\Facades\Redis::class,
+        'Request' => Illuminate\Support\Facades\Request::class,
+        'Response' => Illuminate\Support\Facades\Response::class,
+        'Route' => Illuminate\Support\Facades\Route::class,
+        'Schema' => Illuminate\Support\Facades\Schema::class,
+        'Session' => Illuminate\Support\Facades\Session::class,
+        'Storage' => Illuminate\Support\Facades\Storage::class,
+        'URL' => Illuminate\Support\Facades\URL::class,
+        'Validator' => Illuminate\Support\Facades\Validator::class,
+        'View' => Illuminate\Support\Facades\View::class,
+
+        'Debugbar'  => Barryvdh\Debugbar\Facade::class,
+        'Twitter'   => Thujohn\Twitter\Facades\Twitter::class,
+
+    ],
+
+];
diff --git a/config/auth.php b/config/auth.php
new file mode 100644
index 00000000..3fa7f491
--- /dev/null
+++ b/config/auth.php
@@ -0,0 +1,107 @@
+ [
+        'guard' => 'web',
+        'passwords' => 'users',
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Authentication Guards
+    |--------------------------------------------------------------------------
+    |
+    | Next, you may define every authentication guard for your application.
+    | Of course, a great default configuration has been defined for you
+    | here which uses session storage and the Eloquent user provider.
+    |
+    | All authentication drivers have a user provider. This defines how the
+    | users are actually retrieved out of your database or other storage
+    | mechanisms used by this application to persist your user's data.
+    |
+    | Supported: "session", "token"
+    |
+    */
+
+    'guards' => [
+        'web' => [
+            'driver' => 'session',
+            'provider' => 'users',
+        ],
+
+        'api' => [
+            'driver' => 'token',
+            'provider' => 'users',
+        ],
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | User Providers
+    |--------------------------------------------------------------------------
+    |
+    | All authentication drivers have a user provider. This defines how the
+    | users are actually retrieved out of your database or other storage
+    | mechanisms used by this application to persist your user's data.
+    |
+    | If you have multiple user tables or models you may configure multiple
+    | sources which represent each model / table. These sources may then
+    | be assigned to any extra authentication guards you have defined.
+    |
+    | Supported: "database", "eloquent"
+    |
+    */
+
+    'providers' => [
+        'users' => [
+            'driver' => 'eloquent',
+            'model' => App\User::class,
+        ],
+
+        // 'users' => [
+        //     'driver' => 'database',
+        //     'table' => 'users',
+        // ],
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Resetting Passwords
+    |--------------------------------------------------------------------------
+    |
+    | Here you may set the options for resetting passwords including the view
+    | that is your password reset e-mail. You may also set the name of the
+    | table that maintains all of the reset tokens for your application.
+    |
+    | You may specify multiple password reset configurations if you have more
+    | than one user table or model in the application and you want to have
+    | separate password reset settings based on the specific user types.
+    |
+    | The expire time is the number of minutes that the reset token should be
+    | considered valid. This security feature keeps tokens short-lived so
+    | they have less time to be guessed. You may change this as needed.
+    |
+    */
+
+    'passwords' => [
+        'users' => [
+            'provider' => 'users',
+            'email' => 'auth.emails.password',
+            'table' => 'password_resets',
+            'expire' => 60,
+        ],
+    ],
+
+];
diff --git a/config/broadcasting.php b/config/broadcasting.php
new file mode 100644
index 00000000..abaaac32
--- /dev/null
+++ b/config/broadcasting.php
@@ -0,0 +1,52 @@
+ env('BROADCAST_DRIVER', 'pusher'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Broadcast Connections
+    |--------------------------------------------------------------------------
+    |
+    | Here you may define all of the broadcast connections that will be used
+    | to broadcast events to other systems or over websockets. Samples of
+    | each available type of connection are provided inside this array.
+    |
+    */
+
+    'connections' => [
+
+        'pusher' => [
+            'driver' => 'pusher',
+            'key' => env('PUSHER_KEY'),
+            'secret' => env('PUSHER_SECRET'),
+            'app_id' => env('PUSHER_APP_ID'),
+            'options' => [
+                //
+            ],
+        ],
+
+        'redis' => [
+            'driver' => 'redis',
+            'connection' => 'default',
+        ],
+
+        'log' => [
+            'driver' => 'log',
+        ],
+
+    ],
+
+];
diff --git a/config/cache.php b/config/cache.php
new file mode 100644
index 00000000..3ffa840b
--- /dev/null
+++ b/config/cache.php
@@ -0,0 +1,81 @@
+ env('CACHE_DRIVER', 'file'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Cache Stores
+    |--------------------------------------------------------------------------
+    |
+    | Here you may define all of the cache "stores" for your application as
+    | well as their drivers. You may even define multiple stores for the
+    | same cache driver to group types of items stored in your caches.
+    |
+    */
+
+    'stores' => [
+
+        'apc' => [
+            'driver' => 'apc',
+        ],
+
+        'array' => [
+            'driver' => 'array',
+        ],
+
+        'database' => [
+            'driver' => 'database',
+            'table' => 'cache',
+            'connection' => null,
+        ],
+
+        'file' => [
+            'driver' => 'file',
+            'path' => storage_path('framework/cache'),
+        ],
+
+        'memcached' => [
+            'driver' => 'memcached',
+            'servers' => [
+                [
+                    'host' => env('MEMCACHED_HOST', '127.0.0.1'),
+                    'port' => env('MEMCACHED_PORT', 11211),
+                    'weight' => 100,
+                ],
+            ],
+        ],
+
+        'redis' => [
+            'driver' => 'redis',
+            'connection' => 'default',
+        ],
+
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Cache Key Prefix
+    |--------------------------------------------------------------------------
+    |
+    | When utilizing a RAM based store such as APC or Memcached, there might
+    | be other applications utilizing the same cache. So, we'll specify a
+    | value to get prefixed to all our keys so we can avoid collisions.
+    |
+    */
+
+    'prefix' => 'laravel',
+
+];
diff --git a/config/compile.php b/config/compile.php
new file mode 100644
index 00000000..04807eac
--- /dev/null
+++ b/config/compile.php
@@ -0,0 +1,35 @@
+ [
+        //
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Compiled File Providers
+    |--------------------------------------------------------------------------
+    |
+    | Here you may list service providers which define a "compiles" function
+    | that returns additional files that should be compiled, providing an
+    | easy way to get common files from any packages you are utilizing.
+    |
+    */
+
+    'providers' => [
+        //
+    ],
+
+];
diff --git a/config/database.php b/config/database.php
new file mode 100644
index 00000000..598a7ff3
--- /dev/null
+++ b/config/database.php
@@ -0,0 +1,131 @@
+ PDO::FETCH_CLASS,
+
+    /*
+    |--------------------------------------------------------------------------
+    | Default Database Connection Name
+    |--------------------------------------------------------------------------
+    |
+    | Here you may specify which of the database connections below you wish
+    | to use as your default connection for all database work. Of course
+    | you may use many connections at once using the Database library.
+    |
+    */
+
+    'default' => env('DB_CONNECTION', 'mysql'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Database Connections
+    |--------------------------------------------------------------------------
+    |
+    | Here are each of the database connections setup for your application.
+    | Of course, examples of configuring each database platform that is
+    | supported by Laravel is shown below to make development simple.
+    |
+    |
+    | All database work in Laravel is done through the PHP PDO facilities
+    | so make sure you have the driver for your particular database of
+    | choice installed on your machine before you begin development.
+    |
+    */
+
+    'connections' => [
+
+        'sqlite' => [
+            'driver' => 'sqlite',
+            'database' => env('DB_DATABASE', database_path('database.sqlite')),
+            'prefix' => '',
+        ],
+
+        'mysql' => [
+            'driver'    => 'mysql',
+            'host'      => env('DB_HOST', 'localhost'),
+            'port'      => env('DB_PORT', '3306'),
+            'database'  => env('DB_DATABASE', 'forge'),
+            'username'  => env('DB_USERNAME', 'forge'),
+            'password'  => env('DB_PASSWORD', ''),
+            'charset'   => 'utf8mb4',
+            'collation' => 'utf8mb4_unicode_ci',
+            'prefix'    => '',
+            'strict'    => false,
+            'engine'    => null,
+        ],
+
+        'pgsql' => [
+            'driver'    => 'pgsql',
+            'host'      => env('DB_HOST', 'localhost'),
+            'port'      => env('DB_PORT', '5432'),
+            'database'  => env('DB_DATABASE', 'forge'),
+            'username'  => env('DB_USERNAME', 'forge'),
+            'password'  => env('DB_PASSWORD', ''),
+            'charset'   => 'utf8',
+            'prefix'    => '',
+            'schema'    => 'public',
+        ],
+
+        'travis' => [
+            'driver'   => 'pgsql',
+            'host'     => 'localhost',
+            'database' => 'travis_ci_test',
+            'username' => 'travis',
+            'password' => '',
+            'charset'  => 'utf8',
+            'prefix'   => '',
+            'schema'   => 'public',
+        ]
+
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Migration Repository Table
+    |--------------------------------------------------------------------------
+    |
+    | This table keeps track of all the migrations that have already run for
+    | your application. Using this information, we can determine which of
+    | the migrations on disk haven't actually been run in the database.
+    |
+    */
+
+    'migrations' => 'migrations',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Redis Databases
+    |--------------------------------------------------------------------------
+    |
+    | Redis is an open source, fast, and advanced key-value store that also
+    | provides a richer set of commands than a typical key-value systems
+    | such as APC or Memcached. Laravel makes it easy to dig right in.
+    |
+    */
+
+    'redis' => [
+
+        'cluster' => false,
+
+        'default' => [
+            'host' => env('REDIS_HOST', 'localhost'),
+            'password' => env('REDIS_PASSWORD', null),
+            'port' => env('REDIS_PORT', 6379),
+            'database' => 0,
+        ],
+
+    ],
+
+];
diff --git a/config/debugbar.php b/config/debugbar.php
new file mode 100644
index 00000000..7d46a634
--- /dev/null
+++ b/config/debugbar.php
@@ -0,0 +1,145 @@
+ null,
+
+    /*
+     |--------------------------------------------------------------------------
+     | Storage settings
+     |--------------------------------------------------------------------------
+     |
+     | DebugBar stores data for session/ajax requests.
+     | You can disable this, so the debugbar stores data in headers/session,
+     | but this can cause problems with large data collectors.
+     | By default, file storage (in the storage folder) is used. Redis and PDO
+     | can also be used. For PDO, run the package migrations first.
+     |
+     */
+    'storage' => array(
+        'enabled' => true,
+        'driver' => 'file', // redis, file, pdo
+        'path' => storage_path() . '/debugbar', // For file driver
+        'connection' => null,   // Leave null for default connection (Redis/PDO)
+    ),
+
+    /*
+     |--------------------------------------------------------------------------
+     | Vendors
+     |--------------------------------------------------------------------------
+     |
+     | Vendor files are included by default, but can be set to false.
+     | This can also be set to 'js' or 'css', to only include javascript or css vendor files.
+     | Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
+     | and for js: jquery and and highlight.js
+     | So if you want syntax highlighting, set it to true.
+     | jQuery is set to not conflict with existing jQuery scripts.
+     |
+     */
+
+    'include_vendors' => true,
+
+    /*
+     |--------------------------------------------------------------------------
+     | Capture Ajax Requests
+     |--------------------------------------------------------------------------
+     |
+     | The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
+     | you can use this option to disable sending the data through the headers.
+     |
+     */
+
+    'capture_ajax' => true,
+
+    /*
+     |--------------------------------------------------------------------------
+     | DataCollectors
+     |--------------------------------------------------------------------------
+     |
+     | Enable/disable DataCollectors
+     |
+     */
+
+    'collectors' => array(
+        'phpinfo'         => true,  // Php version
+        'messages'        => true,  // Messages
+        'time'            => true,  // Time Datalogger
+        'memory'          => true,  // Memory usage
+        'exceptions'      => true,  // Exception displayer
+        'log'             => true,  // Logs from Monolog (merged in messages if enabled)
+        'db'              => true,  // Show database (PDO) queries and bindings
+        'views'           => true,  // Views with their data
+        'route'           => true,  // Current route information
+        'laravel'         => false, // Laravel version and environment
+        'events'          => false, // All events fired
+        'default_request' => false, // Regular or special Symfony request logger
+        'symfony_request' => true,  // Only one can be enabled..
+        'mail'            => true,  // Catch mail messages
+        'logs'            => false, // Add the latest log messages
+        'files'           => false, // Show the included files
+        'config'          => false, // Display config settings
+        'auth'            => false, // Display Laravel authentication status
+        'session'         => false, // Display session data in a separate tab
+    ),
+
+    /*
+     |--------------------------------------------------------------------------
+     | Extra options
+     |--------------------------------------------------------------------------
+     |
+     | Configure some DataCollectors
+     |
+     */
+
+    'options' => array(
+        'auth' => array(
+            'show_name' => false,   // Also show the users name/email in the debugbar
+        ),
+        'db' => array(
+            'with_params'       => true,   // Render SQL with the parameters substituted
+            'timeline'          => false,  // Add the queries to the timeline
+            'backtrace'         => false,  // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files.
+            'explain' => array(            // EXPERIMENTAL: Show EXPLAIN output on queries
+                'enabled' => false,
+                'types' => array('SELECT'), // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+
+            ),
+            'hints'             => true,    // Show hints for common mistakes
+        ),
+        'mail' => array(
+            'full_log' => false
+        ),
+        'views' => array(
+            'data' => false,    //Note: Can slow down the application, because the data can be quite large..
+        ),
+        'route' => array(
+            'label' => true  // show complete route on bar
+        ),
+        'logs' => array(
+            'file' => null
+        ),
+    ),
+
+    /*
+     |--------------------------------------------------------------------------
+     | Inject Debugbar in Response
+     |--------------------------------------------------------------------------
+     |
+     | Usually, the debugbar is added just before , by listening to the
+     | Response after the App is done. If you disable this, you have to add them
+     | in your template yourself. See http://phpdebugbar.com/docs/rendering.html
+     |
+     */
+
+    'inject' => true,
+
+);
diff --git a/config/filesystems.php b/config/filesystems.php
new file mode 100644
index 00000000..1c46f7c4
--- /dev/null
+++ b/config/filesystems.php
@@ -0,0 +1,72 @@
+ 'local',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Default Cloud Filesystem Disk
+    |--------------------------------------------------------------------------
+    |
+    | Many applications store files both locally and in the cloud. For this
+    | reason, you may specify a default "cloud" driver here. This driver
+    | will be bound as the Cloud disk implementation in the container.
+    |
+    */
+
+    'cloud' => 's3',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Filesystem Disks
+    |--------------------------------------------------------------------------
+    |
+    | Here you may configure as many filesystem "disks" as you wish, and you
+    | may even configure multiple disks of the same driver. Defaults have
+    | been setup for each driver as an example of the required options.
+    |
+    */
+
+    'disks' => [
+
+        'local' => [
+            'driver' => 'local',
+            'root' => storage_path('app'),
+        ],
+
+        'public' => [
+            'driver' => 'local',
+            'root' => storage_path('app/public'),
+            'visibility' => 'public',
+        ],
+
+        's3' => [
+            'driver' => 's3',
+            'key'    => env('AWS_S3_KEY'),
+            'secret' => env('AWS_S3_SECRET'),
+            'region' => env('AWS_S3_REGION'),
+            'bucket' => env('AWS_S3_BUCKET'),
+        ],
+
+        'media' => [
+            'driver' => 'local',
+            'root'   => public_path() . '/media',
+        ],
+
+    ],
+
+];
diff --git a/config/laravel-medialibrary.php b/config/laravel-medialibrary.php
new file mode 100644
index 00000000..c6abd4c5
--- /dev/null
+++ b/config/laravel-medialibrary.php
@@ -0,0 +1,40 @@
+ 'media',
+
+    /*
+     * The maximum file size of an item in bytes. Adding a file
+     * that is larger will result in an exception.
+     */
+    'max_file_size' => 1024 * 1024 * 10,
+
+    /*
+     * This queue will used to generate derived images.
+     * Leave empty to use the default queue.
+     */
+    'queue_name' => '',
+
+    /*
+     * The class name of the media model to be used.
+     */
+    'media_model' => Spatie\MediaLibrary\Media::class,
+
+    /*
+     * When urls to files get generated this class will be called. Leave empty
+     * if your files are stored locally above the site root or on s3.
+     */
+    'custom_url_generator_class' => '',
+
+    's3' => [
+        /*
+         * The domain that should be prepended when generating urls.
+         */
+        'domain' => env('AWS_S3_URL'),
+    ],
+];
diff --git a/config/mail.php b/config/mail.php
new file mode 100644
index 00000000..a0765885
--- /dev/null
+++ b/config/mail.php
@@ -0,0 +1,112 @@
+ env('MAIL_DRIVER', 'smtp'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | SMTP Host Address
+    |--------------------------------------------------------------------------
+    |
+    | Here you may provide the host address of the SMTP server used by your
+    | applications. A default option is provided that is compatible with
+    | the Mailgun mail service which will provide reliable deliveries.
+    |
+    */
+
+    'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | SMTP Host Port
+    |--------------------------------------------------------------------------
+    |
+    | This is the SMTP port used by your application to deliver e-mails to
+    | users of the application. Like the host we have set this value to
+    | stay compatible with the Mailgun e-mail application by default.
+    |
+    */
+
+    'port' => env('MAIL_PORT', 587),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Global "From" Address
+    |--------------------------------------------------------------------------
+    |
+    | You may wish for all e-mails sent by your application to be sent from
+    | the same address. Here, you may specify a name and address that is
+    | used globally for all e-mails that are sent by your application.
+    |
+    */
+
+    'from' => ['address' => null, 'name' => null],
+
+    /*
+    |--------------------------------------------------------------------------
+    | E-Mail Encryption Protocol
+    |--------------------------------------------------------------------------
+    |
+    | Here you may specify the encryption protocol that should be used when
+    | the application send e-mail messages. A sensible default using the
+    | transport layer security protocol should provide great security.
+    |
+    */
+
+    'encryption' => env('MAIL_ENCRYPTION', 'tls'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | SMTP Server Username
+    |--------------------------------------------------------------------------
+    |
+    | If your SMTP server requires a username for authentication, you should
+    | set it here. This will get used to authenticate with your server on
+    | connection. You may also set the "password" value below this one.
+    |
+    */
+
+    'username' => env('MAIL_USERNAME'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | SMTP Server Password
+    |--------------------------------------------------------------------------
+    |
+    | Here you may set the password required by your SMTP server to send out
+    | messages from your application. This will be given to the server on
+    | connection so that the application will be able to send messages.
+    |
+    */
+
+    'password' => env('MAIL_PASSWORD'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Sendmail System Path
+    |--------------------------------------------------------------------------
+    |
+    | When using the "sendmail" driver to send e-mails, we will need to know
+    | the path to where Sendmail lives on this server. A default path has
+    | been provided here, which will work well on most of your systems.
+    |
+    */
+
+    'sendmail' => '/usr/sbin/sendmail -bs',
+
+];
diff --git a/config/queue.php b/config/queue.php
new file mode 100644
index 00000000..d0f732a6
--- /dev/null
+++ b/config/queue.php
@@ -0,0 +1,85 @@
+ env('QUEUE_DRIVER', 'sync'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Queue Connections
+    |--------------------------------------------------------------------------
+    |
+    | Here you may configure the connection information for each server that
+    | is used by your application. A default configuration has been added
+    | for each back-end shipped with Laravel. You are free to add more.
+    |
+    */
+
+    'connections' => [
+
+        'sync' => [
+            'driver' => 'sync',
+        ],
+
+        'database' => [
+            'driver' => 'database',
+            'table' => 'jobs',
+            'queue' => 'default',
+            'expire' => 60,
+        ],
+
+        'beanstalkd' => [
+            'driver' => 'beanstalkd',
+            'host' => 'localhost',
+            'queue' => 'default',
+            'ttr' => 60,
+        ],
+
+        'sqs' => [
+            'driver' => 'sqs',
+            'key' => 'your-public-key',
+            'secret' => 'your-secret-key',
+            'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id',
+            'queue' => 'your-queue-name',
+            'region' => 'us-east-1',
+        ],
+
+        'redis' => [
+            'driver' => 'redis',
+            'connection' => 'default',
+            'queue' => 'default',
+            'expire' => 60,
+        ],
+
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Failed Queue Jobs
+    |--------------------------------------------------------------------------
+    |
+    | These options configure the behavior of failed queue job logging so you
+    | can control which database and table are used to store the jobs that
+    | have failed. You may change them to any database / table you wish.
+    |
+    */
+
+    'failed' => [
+        'database' => env('DB_CONNECTION', 'mysql'),
+        'table' => 'failed_jobs',
+    ],
+
+];
diff --git a/config/services.php b/config/services.php
new file mode 100644
index 00000000..287b1186
--- /dev/null
+++ b/config/services.php
@@ -0,0 +1,38 @@
+ [
+        'domain' => env('MAILGUN_DOMAIN'),
+        'secret' => env('MAILGUN_SECRET'),
+    ],
+
+    'ses' => [
+        'key' => env('SES_KEY'),
+        'secret' => env('SES_SECRET'),
+        'region' => 'us-east-1',
+    ],
+
+    'sparkpost' => [
+        'secret' => env('SPARKPOST_SECRET'),
+    ],
+
+    'stripe' => [
+        'model' => App\User::class,
+        'key' => env('STRIPE_KEY'),
+        'secret' => env('STRIPE_SECRET'),
+    ],
+
+];
diff --git a/config/session.php b/config/session.php
new file mode 100644
index 00000000..33f62e49
--- /dev/null
+++ b/config/session.php
@@ -0,0 +1,166 @@
+ env('SESSION_DRIVER', 'file'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session Lifetime
+    |--------------------------------------------------------------------------
+    |
+    | Here you may specify the number of minutes that you wish the session
+    | to be allowed to remain idle before it expires. If you want them
+    | to immediately expire on the browser closing, set that option.
+    |
+    */
+
+    'lifetime' => 60 * 24 * 7,
+
+    'expire_on_close' => false,
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session Encryption
+    |--------------------------------------------------------------------------
+    |
+    | This option allows you to easily specify that all of your session data
+    | should be encrypted before it is stored. All encryption will be run
+    | automatically by Laravel and you can use the Session like normal.
+    |
+    */
+
+    'encrypt' => false,
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session File Location
+    |--------------------------------------------------------------------------
+    |
+    | When using the native session driver, we need a location where session
+    | files may be stored. A default has been set for you but a different
+    | location may be specified. This is only needed for file sessions.
+    |
+    */
+
+    'files' => storage_path('framework/sessions'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session Database Connection
+    |--------------------------------------------------------------------------
+    |
+    | When using the "database" or "redis" session drivers, you may specify a
+    | connection that should be used to manage these sessions. This should
+    | correspond to a connection in your database configuration options.
+    |
+    */
+
+    'connection' => null,
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session Database Table
+    |--------------------------------------------------------------------------
+    |
+    | When using the "database" session driver, you may specify the table we
+    | should use to manage the sessions. Of course, a sensible default is
+    | provided for you; however, you are free to change this as needed.
+    |
+    */
+
+    'table' => 'sessions',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session Sweeping Lottery
+    |--------------------------------------------------------------------------
+    |
+    | Some session drivers must manually sweep their storage location to get
+    | rid of old sessions from storage. Here are the chances that it will
+    | happen on a given request. By default, the odds are 2 out of 100.
+    |
+    */
+
+    'lottery' => [2, 100],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session Cookie Name
+    |--------------------------------------------------------------------------
+    |
+    | Here you may change the name of the cookie used to identify a session
+    | instance by ID. The name specified here will get used every time a
+    | new session cookie is created by the framework for every driver.
+    |
+    */
+
+    'cookie' => 'laravel_session',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session Cookie Path
+    |--------------------------------------------------------------------------
+    |
+    | The session cookie path determines the path for which the cookie will
+    | be regarded as available. Typically, this will be the root path of
+    | your application but you are free to change this when necessary.
+    |
+    */
+
+    'path' => '/',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Session Cookie Domain
+    |--------------------------------------------------------------------------
+    |
+    | Here you may change the domain of the cookie used to identify a session
+    | in your application. This will determine which domains the cookie is
+    | available to in your application. A sensible default has been set.
+    |
+    */
+
+    'domain' => null,
+
+    /*
+    |--------------------------------------------------------------------------
+    | HTTPS Only Cookies
+    |--------------------------------------------------------------------------
+    |
+    | By setting this option to true, session cookies will only be sent back
+    | to the server if the browser has a HTTPS connection. This will keep
+    | the cookie from being sent to you if it can not be done securely.
+    |
+    */
+
+    'secure' => true,
+
+    /*
+    |--------------------------------------------------------------------------
+    | HTTP Access Only
+    |--------------------------------------------------------------------------
+    |
+    | Setting this value to true will prevent JavaScript from accessing the
+    | value of the cookie and the cookie will only be accessible through
+    | the HTTP protocol. You are free to modify this option if needed.
+    |
+    */
+
+    'http_only' => true,
+
+];
diff --git a/config/ttwitter.php b/config/ttwitter.php
new file mode 100644
index 00000000..8c6e4ec2
--- /dev/null
+++ b/config/ttwitter.php
@@ -0,0 +1,18 @@
+ 'api.twitter.com',
+		'API_VERSION'         => '1.1',
+		'AUTHENTICATE_URL'    => 'https://api.twitter.com/oauth/authenticate',
+		'AUTHORIZE_URL'       => 'https://api.twitter.com/oauth/authorize',
+		'ACCESS_TOKEN_URL'    => 'oauth/access_token',
+		'REQUEST_TOKEN_URL'   => 'oauth/request_token',
+		'USE_SSL'             => true,
+
+		'CONSUMER_KEY'        => env('TWITTER_CONSUMER_KEY'),
+		'CONSUMER_SECRET'     => env('TWITTER_CONSUMER_SECRET'),
+		'ACCESS_TOKEN'        => env('TWITTER_ACCESS_TOKEN'),
+		'ACCESS_TOKEN_SECRET' => env('TWITTER_ACCESS_TOKEN_SECRET'),
+	];
diff --git a/config/url.php b/config/url.php
new file mode 100644
index 00000000..96767e3f
--- /dev/null
+++ b/config/url.php
@@ -0,0 +1,11 @@
+ env('APP_LONGURL', 'jonnybarnes.uk'),
+    'shorturl' => env('APP_SHORTURL', 'jmb.so')
+];
\ No newline at end of file
diff --git a/config/view.php b/config/view.php
new file mode 100644
index 00000000..e193ab61
--- /dev/null
+++ b/config/view.php
@@ -0,0 +1,33 @@
+ [
+        realpath(base_path('resources/views')),
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Compiled View Path
+    |--------------------------------------------------------------------------
+    |
+    | This option determines where all the compiled Blade templates will be
+    | stored for your application. Typically, this is within the storage
+    | directory. However, as usual, you are free to change this value.
+    |
+    */
+
+    'compiled' => realpath(storage_path('framework/views')),
+
+];
diff --git a/database/.gitignore b/database/.gitignore
new file mode 100644
index 00000000..9b1dffd9
--- /dev/null
+++ b/database/.gitignore
@@ -0,0 +1 @@
+*.sqlite
diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php
new file mode 100644
index 00000000..df9993c9
--- /dev/null
+++ b/database/factories/ModelFactory.php
@@ -0,0 +1,28 @@
+define(App\User::class, function (Faker\Generator $faker) {
+    return [
+        'name' => $faker->name,
+        'email' => $faker->safeEmail,
+        'password' => bcrypt(str_random(10)),
+        'remember_token' => str_random(10),
+    ];
+});
+
+$factory->define(App\Note::class, function (Faker\Generator $faker) {
+    return [
+        'note' => $faker->paragraph,
+        'tweet_id' => $faker->randomNumber(9),
+    ];
+});
diff --git a/database/migrations/.gitkeep b/database/migrations/.gitkeep
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/database/migrations/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/database/migrations/2015_02_28_132629_create_articles_table.php b/database/migrations/2015_02_28_132629_create_articles_table.php
new file mode 100644
index 00000000..43277762
--- /dev/null
+++ b/database/migrations/2015_02_28_132629_create_articles_table.php
@@ -0,0 +1,38 @@
+increments('id');
+                $table->string('titleurl', 50)->unique();
+                $table->string('url', 120)->nullable();
+                $table->string('title');
+                $table->longText('main');
+                $table->tinyInteger('published')->default(0);
+                $table->timestamps();
+                $table->softDeletes();
+            });
+        }
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('articles');
+    }
+}
diff --git a/database/migrations/2015_02_28_144939_create_notes_table.php b/database/migrations/2015_02_28_144939_create_notes_table.php
new file mode 100644
index 00000000..33e22669
--- /dev/null
+++ b/database/migrations/2015_02_28_144939_create_notes_table.php
@@ -0,0 +1,40 @@
+increments('id');
+                $table->text('note');
+                $table->string('in_reply_to')->nullable();
+                $table->string('shorturl', 20)->nullable();
+                $table->string('location')->nullable();
+                $table->tinyInteger('photo')->nullable();
+                $table->string('tweet_id')->nullable();
+                $table->string('client_id')->nullable();
+                $table->timestamps();
+                $table->softDeletes();
+            });
+        }
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('notes');
+    }
+}
diff --git a/database/migrations/2015_03_02_084342_create_tags_table.php b/database/migrations/2015_03_02_084342_create_tags_table.php
new file mode 100644
index 00000000..0e1175ea
--- /dev/null
+++ b/database/migrations/2015_03_02_084342_create_tags_table.php
@@ -0,0 +1,31 @@
+increments('id');
+            $table->string('tag');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('tags');
+    }
+}
diff --git a/database/migrations/2015_03_02_084956_create_note_tag_table.php b/database/migrations/2015_03_02_084956_create_note_tag_table.php
new file mode 100644
index 00000000..831cff30
--- /dev/null
+++ b/database/migrations/2015_03_02_084956_create_note_tag_table.php
@@ -0,0 +1,33 @@
+increments('id');
+            $table->integer('note_id')->unsigned();
+            $table->integer('tag_id')->unsigned();
+            $table->foreign('note_id')->references('id')->on('notes');
+            $table->foreign('tag_id')->references('id')->on('tags');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('note_tag');
+    }
+}
diff --git a/database/migrations/2015_03_02_105623_create_contacts_table.php b/database/migrations/2015_03_02_105623_create_contacts_table.php
new file mode 100644
index 00000000..b0b1e3ec
--- /dev/null
+++ b/database/migrations/2015_03_02_105623_create_contacts_table.php
@@ -0,0 +1,34 @@
+increments('id');
+            $table->string('nick');
+            $table->string('name');
+            $table->string('homepage')->nullable();
+            $table->string('twitter')->nullable();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('contacts');
+    }
+}
diff --git a/database/migrations/2015_03_02_114340_create_web_mentions_table.php b/database/migrations/2015_03_02_114340_create_web_mentions_table.php
new file mode 100644
index 00000000..edbbfba3
--- /dev/null
+++ b/database/migrations/2015_03_02_114340_create_web_mentions_table.php
@@ -0,0 +1,39 @@
+increments('id');
+            $table->string('source');
+            $table->string('target');
+            $table->integer('commentable_id')->nullable();
+            $table->string('commentable_type')->nullable();
+            $table->string('type')->nullable();
+            $table->text('content');
+            $table->tinyInteger('verified')->default(1);
+            $table->timestamps();
+            $table->softDeletes();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('webmentions');
+    }
+}
diff --git a/database/migrations/2015_07_17_111512_create_clients_table.php b/database/migrations/2015_07_17_111512_create_clients_table.php
new file mode 100644
index 00000000..4821d16b
--- /dev/null
+++ b/database/migrations/2015_07_17_111512_create_clients_table.php
@@ -0,0 +1,32 @@
+increments('id');
+            $table->string('client_url');
+            $table->string('client_name');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('clients');
+    }
+}
diff --git a/database/migrations/2015_07_22_084423_create_failed_jobs_table.php b/database/migrations/2015_07_22_084423_create_failed_jobs_table.php
new file mode 100644
index 00000000..c1ba41b4
--- /dev/null
+++ b/database/migrations/2015_07_22_084423_create_failed_jobs_table.php
@@ -0,0 +1,33 @@
+increments('id');
+            $table->text('connection');
+            $table->text('queue');
+            $table->longText('payload');
+            $table->timestamp('failed_at');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('failed_jobs');
+    }
+}
diff --git a/database/migrations/2015_10_08_155111_create_media_table.php b/database/migrations/2015_10_08_155111_create_media_table.php
new file mode 100644
index 00000000..15a3ce03
--- /dev/null
+++ b/database/migrations/2015_10_08_155111_create_media_table.php
@@ -0,0 +1,35 @@
+increments('id');
+            $table->morphs('model');
+            $table->string('collection_name');
+            $table->string('name');
+            $table->string('file_name');
+            $table->string('disk');
+            $table->unsignedInteger('size');
+            $table->text('manipulations');
+            $table->text('custom_properties');
+            $table->unsignedInteger('order_column')->nullable();
+            $table->timestamps();
+        });
+    }
+    /**
+     * Reverse the migrations.
+     */
+    public function down()
+    {
+        Schema::drop('media');
+    }
+}
diff --git a/database/migrations/2015_11_07_130637_create_places_table.php b/database/migrations/2015_11_07_130637_create_places_table.php
new file mode 100644
index 00000000..3d6927c0
--- /dev/null
+++ b/database/migrations/2015_11_07_130637_create_places_table.php
@@ -0,0 +1,35 @@
+increments('id');
+            $table->string('name');
+            $table->string('slug')->unique();
+            $table->text('description')->nullable();
+            $table->point('location');
+            $table->polygon('polygon')->nullable();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('places');
+    }
+}
diff --git a/database/migrations/2015_11_19_221933_add_place_relation_to_notes.php b/database/migrations/2015_11_19_221933_add_place_relation_to_notes.php
new file mode 100644
index 00000000..a999d7bd
--- /dev/null
+++ b/database/migrations/2015_11_19_221933_add_place_relation_to_notes.php
@@ -0,0 +1,33 @@
+integer('place_id')->unsigned()->nullable();
+            $table->foreign('place_id')->references('id')->on('places');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('notes', function (Blueprint $table) {
+            $table->dropForeign('notes_place_id_foreign');
+            $table->dropColumn('place_id');
+        });
+    }
+}
diff --git a/database/seeds/.gitkeep b/database/seeds/.gitkeep
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/database/seeds/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/database/seeds/ArticlesTableSeeder.php b/database/seeds/ArticlesTableSeeder.php
new file mode 100644
index 00000000..af99e3c2
--- /dev/null
+++ b/database/seeds/ArticlesTableSeeder.php
@@ -0,0 +1,23 @@
+insert([
+            'titleurl' => 'my-new-blog',
+            'title' => 'My New Blog',
+            'main' => 'This is my new blog. It uses `Markdown`.',
+            'published' => 1,
+            'created_at' => '2016-01-12 15:51:01',
+            'updated_at' => '2016-01-12 15:51:01',
+        ]);
+    }
+}
diff --git a/database/seeds/ClientsTableSeeder.php b/database/seeds/ClientsTableSeeder.php
new file mode 100644
index 00000000..5d833f82
--- /dev/null
+++ b/database/seeds/ClientsTableSeeder.php
@@ -0,0 +1,21 @@
+insert([
+            'client_url' => 'https://jbl5.dev/notes/new',
+            'client_name' => 'JBL5',
+            'created_at' => '2016-01-12 16:03:00',
+            'updated_at' => '2016-01-12 16:03:00',
+        ]);
+    }
+}
diff --git a/database/seeds/ContactsTableSeeder.php b/database/seeds/ContactsTableSeeder.php
new file mode 100644
index 00000000..8ce80a0b
--- /dev/null
+++ b/database/seeds/ContactsTableSeeder.php
@@ -0,0 +1,32 @@
+insert([
+            'nick' => 'tantek',
+            'name' => 'Tantek Çelik',
+            'homepage' => 'http://tantek.com',
+            'twitter' => 't',
+            'created_at' => '2016-01-12 16:11:00',
+            'updated_at' => '2016-01-12 16:11:00',
+        ]);
+
+        DB::table('contacts')->insert([
+            'nick' => 'aaron',
+            'name' => 'Aaron Parecki',
+            'homepage' => 'https://aaronparecki.com',
+            'twitter' => 'aaronpk',
+            'created_at' => '2016-01-12 16:12:00',
+            'updated_at' => '2016-01-12 16:12:00',
+        ]);
+    }
+}
diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php
new file mode 100644
index 00000000..802cddc6
--- /dev/null
+++ b/database/seeds/DatabaseSeeder.php
@@ -0,0 +1,20 @@
+call(ArticlesTableSeeder::class);
+        $this->call(ClientsTableSeeder::class);
+        $this->call(ContactsTableSeeder::class);
+        $this->call(PlacesTableSeeder::class);
+        $this->call(NotesTableSeeder::class);
+    }
+}
diff --git a/database/seeds/NotesTableSeeder.php b/database/seeds/NotesTableSeeder.php
new file mode 100644
index 00000000..9fa8ccd1
--- /dev/null
+++ b/database/seeds/NotesTableSeeder.php
@@ -0,0 +1,39 @@
+create();
+        $noteWithPlace = App\Note::create([
+            'note' => 'Having a #beer at the local.'
+        ]);
+        $place = App\Place::find(1);
+        $noteWithPlace->place()->associate($place);
+        $noteWithPlace->save();
+        $noteWithContact = App\Note::create([
+            'note' => 'Hi @tantek'
+        ]);
+        $noteWithContactPlusPic = App\Note::create([
+            'note' => 'Hi @aaron',
+            'client_id' => 'https://jbl5.dev/notes/new'
+        ]);
+        $noteWithoutContact = App\Note::create([
+            'note' => 'Hi @bob',
+            'client_id' => 'https://quill.p3k.io'
+        ]);
+        //copy aaron’s profile pic in place
+        $spl = new SplFileInfo(public_path() . '/assets/profile-images/aaronparecki.com');
+        if ($spl->isDir() === false) {
+            mkdir(public_path() . '/assets/profile-images/aaronparecki.com', 0755);
+            copy(base_path() . '/tests/aaron.png', public_path() . '/assets/profile-images/aaronparecki.com/image');
+        }
+    }
+}
diff --git a/database/seeds/PlacesTableSeeder.php b/database/seeds/PlacesTableSeeder.php
new file mode 100644
index 00000000..34302d50
--- /dev/null
+++ b/database/seeds/PlacesTableSeeder.php
@@ -0,0 +1,23 @@
+insert([
+            'name' => 'The Bridgewater Pub',
+            'slug' => 'the-bridgewater-pub',
+            'description' => 'A lovely local pub with a decent selection pf cask ales',
+            'location' => 'POINT(-2.3805 53.4983)',
+            'created_at' => '2016-01-12 16:19:00',
+            'updated_at' => '2016-01-12 16:19:00',
+        ]);
+    }
+}
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 00000000..6395c379
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,81 @@
+var gulp = require('gulp');
+var zopfli = require('gulp-zopfli');
+var brotli = require('gulp-brotli');
+var elixir = require('laravel-elixir');
+
+/*
+ |--------------------------------------------------------------------------
+ | Elixir Asset Management
+ |--------------------------------------------------------------------------
+ |
+ | Elixir provides a clean, fluent API for defining some basic Gulp tasks
+ | for your Laravel application. By default, we are compiling the Sass
+ | file for our application, as well as publishing vendor resources.
+ |
+ */
+
+elixir(function(mix) {
+    mix.sass('global.scss', 'public/assets/css');
+    mix.version([
+        'assets/css/global.css',
+        'assets/css/projects.css',
+        'assets/css/alertify.css',
+        'assets/css/sanitize.min.css',
+        'assets/css/prism.css',
+        'assets/js/form-save.js',
+        'assets/js/links.js',
+        'assets/js/maps.js',
+        'assets/js/newplace.js',
+        'assets/js/newnote.js',
+        'assets/js/fetch.js',
+        'assets/js/alertify.js',
+        'assets/js/store2.min.js',
+        'assets/js/Autolinker.min.js',
+        'assets/js/marked.min.js',
+        'assets/js/prism.js',
+    ]);
+});
+
+gulp.task('gzip-built-css', function() {
+    return gulp.src('public/build/assets/css/*.css')
+        .pipe(zopfli({ format: 'gzip', append: true }))
+        .pipe(gulp.dest('public/build/assets/css/'));
+});
+
+gulp.task('br-built-css', function() {
+    return gulp.src('public/build/assets/css/*.css')
+        .pipe(brotli.compress({mode: 1, quality: 11}))
+        .pipe(gulp.dest('public/build/assets/css/'));
+});
+
+gulp.task('gzip-built-js', function() {
+    return gulp.src('public/build/assets/js/*.js')
+        .pipe(zopfli({ format: 'gzip', append: true }))
+        .pipe(gulp.dest('public/build/assets/js/'));
+});
+
+gulp.task('br-built-js', function() {
+    return gulp.src('public/build/assets/js/*.js')
+        .pipe(brotli.compress({mode: 1, quality: 11}))
+        .pipe(gulp.dest('public/build/assets/js/'));
+});
+
+gulp.task('bower', function() {
+    //copy JS files
+    gulp.src([
+            'bower_components/fetch/fetch.js',
+            'bower_components/alertify.js/dist/js/alertify.js',
+            'bower_components/store2/dist/store2.min.js',
+            'bower_components/Autolinker.js/dist/Autolinker.min.js',
+            'bower_components/marked/marked.min.js',
+        ])
+        .pipe(gulp.dest('public/assets/js/'));
+    //copy CSS files
+    gulp.src([
+            'bower_components/alertify.js/dist/css/alertify.css',
+            'bower_components/sanitize-css/dist/sanitize.min.css',
+        ])
+        .pipe(gulp.dest('public/assets/css/'));
+});
+
+gulp.task('compress', ['gzip-built-css', 'br-built-css', 'gzip-built-js', 'br-built-js']);
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..d8015224
--- /dev/null
+++ b/package.json
@@ -0,0 +1,17 @@
+{
+  "name": "jbuk-frontend",
+  "version": "0.0.1",
+  "repository": "https://github.com/jonnybarnes/jbl5",
+  "license": "CC0-1.0",
+  "devDependencies": {
+    "gulp": "~3.9",
+    "gulp-brotli": "^1.0.1",
+    "gulp-zopfli": "^1.0.0",
+    "laravel-elixir": "^5.0.0"
+  },
+  "private": true,
+  "scripts": {
+    "prod": "gulp --production",
+    "dev": "gulp watch"
+  }
+}
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 00000000..3e884d17
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,30 @@
+
+
+    
+        
+            ./tests
+        
+    
+    
+        
+            ./app
+            
+                ./app/Http/routes.php
+            
+        
+    
+    
+        
+        
+        
+        
+    
+
diff --git a/public/.htaccess b/public/.htaccess
new file mode 100644
index 00000000..903f6392
--- /dev/null
+++ b/public/.htaccess
@@ -0,0 +1,20 @@
+
+    
+        Options -MultiViews
+    
+
+    RewriteEngine On
+
+    # Redirect Trailing Slashes If Not A Folder...
+    RewriteCond %{REQUEST_FILENAME} !-d
+    RewriteRule ^(.*)/$ /$1 [L,R=301]
+
+    # Handle Front Controller...
+    RewriteCond %{REQUEST_FILENAME} !-d
+    RewriteCond %{REQUEST_FILENAME} !-f
+    RewriteRule ^ index.php [L]
+
+    # Handle Authorization Header
+    RewriteCond %{HTTP:Authorization} .
+    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+
diff --git a/public/assets/css/alertify.css b/public/assets/css/alertify.css
new file mode 100644
index 00000000..ced38bdd
--- /dev/null
+++ b/public/assets/css/alertify.css
@@ -0,0 +1 @@
+.alertify-logs>*{padding:12px 24px;color:#fff;box-shadow:0 2px 5px 0 rgba(0,0,0,.2);border-radius:1px}.alertify-logs>*,.alertify-logs>.default{background:rgba(0,0,0,.8)}.alertify-logs>.error{background:rgba(244,67,54,.8)}.alertify-logs>.success{background:rgba(76,175,80,.9)}.alertify{position:fixed;background-color:rgba(0,0,0,.3);left:0;right:0;top:0;bottom:0;width:100%;height:100%;z-index:2}.alertify.hide{opacity:0;pointer-events:none}.alertify,.alertify.show{box-sizing:border-box;transition:all .33s cubic-bezier(.25,.8,.25,1)}.alertify,.alertify *{box-sizing:border-box}.alertify .dialog{padding:12px}.alertify .alert,.alertify .dialog{width:100%;margin:0 auto;position:relative;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.alertify .alert>*,.alertify .dialog>*{width:400px;max-width:95%;margin:0 auto;text-align:center;padding:12px;background:#fff;box-shadow:0 2px 4px -1px rgba(0,0,0,.14),0 4px 5px 0 rgba(0,0,0,.098),0 1px 10px 0 rgba(0,0,0,.084)}.alertify .alert .msg,.alertify .dialog .msg{padding:12px;margin-bottom:12px;margin:0;text-align:left}.alertify .alert input:not(.form-control),.alertify .dialog input:not(.form-control){margin-bottom:15px;width:100%;font-size:100%;padding:12px}.alertify .alert input:not(.form-control):focus,.alertify .dialog input:not(.form-control):focus{outline-offset:-2px}.alertify .alert nav,.alertify .dialog nav{text-align:right}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button),.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button){background:transparent;box-sizing:border-box;color:rgba(0,0,0,.87);position:relative;outline:0;border:0;display:inline-block;-webkit-align-items:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center;padding:0 6px;margin:6px 8px;line-height:36px;min-height:36px;white-space:nowrap;min-width:88px;text-align:center;text-transform:uppercase;font-size:14px;text-decoration:none;cursor:pointer;border:1px solid transparent;border-radius:2px}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover{background-color:rgba(0,0,0,.05)}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus{border:1px solid rgba(0,0,0,.1)}.alertify .alert nav button.btn,.alertify .dialog nav button.btn{margin:6px 4px}.alertify-logs{position:fixed;z-index:1}.alertify-logs.bottom,.alertify-logs:not(.top){bottom:16px}.alertify-logs.left,.alertify-logs:not(.right){left:16px}.alertify-logs.left>*,.alertify-logs:not(.right)>*{float:left;-webkit-transform:translateZ(0);transform:translateZ(0);height:auto}.alertify-logs.left>.show,.alertify-logs:not(.right)>.show{left:0}.alertify-logs.left>*,.alertify-logs.left>.hide,.alertify-logs:not(.right)>*,.alertify-logs:not(.right)>.hide{left:-110%}.alertify-logs.right{right:16px}.alertify-logs.right>*{float:right;-webkit-transform:translateZ(0);transform:translateZ(0)}.alertify-logs.right>.show{right:0;opacity:1}.alertify-logs.right>*,.alertify-logs.right>.hide{right:-110%;opacity:0}.alertify-logs.top{top:0}.alertify-logs>*{box-sizing:border-box;transition:all .4s cubic-bezier(.25,.8,.25,1);position:relative;clear:both;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000;max-height:0;margin:0;padding:0;overflow:hidden;opacity:0;pointer-events:none}.alertify-logs>.show{margin-top:12px;opacity:1;max-height:1000px;padding:12px;pointer-events:auto}
\ No newline at end of file
diff --git a/public/assets/css/global.css b/public/assets/css/global.css
new file mode 100644
index 00000000..1750d873
--- /dev/null
+++ b/public/assets/css/global.css
@@ -0,0 +1,243 @@
+html {
+  background: url("/assets/img/escheresque.png"); }
+
+.map {
+  height: 150px; }
+
+html {
+  box-sizing: border-box; }
+
+*, *:before, *:after {
+  box-sizing: inherit; }
+
+#topheader {
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-flex-flow: row;
+  -ms-flex-flow: row;
+  flex-flow: row; }
+
+#topheader a {
+  padding: 0.5em 1em; }
+
+nav {
+  padding-top: 0.5em; }
+
+.social-list {
+  padding-left: 2em; }
+
+.note {
+  background-color: #eee8d5;
+  box-shadow: 0 0 10px 2px #93a1a1;
+  padding: 0.5em 0.5em;
+  margin-top: 1em; }
+
+.note:after {
+  content: " ";
+  display: block;
+  height: 0;
+  clear: both; }
+
+.note a {
+  word-wrap: break-word; }
+
+.note .e-content p:first-child {
+  margin-top: 0; }
+
+.note-metadata {
+  width: 100%; }
+
+.social-links {
+  float: right; }
+
+.social-links a {
+  text-decoration: none; }
+
+.icon {
+  width: auto;
+  height: 1em;
+  fill: #268bd2; }
+
+.reply {
+  margin-left: 2em;
+  margin-right: 2em;
+  font-size: 0.8em;
+  padding: 0.5em 0.5em; }
+
+.reply-to {
+  margin-left: 2em;
+  margin-right: 2em;
+  font-size: 0.8em;
+  padding-top: 2em; }
+
+.reply-to + .note {
+  margin-top: 0.3em; }
+
+.mini-h-card {
+  border-radius: 2px;
+  border: 1px solid #586e75;
+  padding: 0 0.2em;
+  text-decoration: none;
+  margin-right: 5px;
+  white-space: nowrap; }
+
+.mini-h-card img {
+  height: 1.26em;
+  display: inline;
+  border-radius: 2px;
+  vertical-align: text-bottom; }
+
+.like-photo {
+  height: 1.26em; }
+
+.reply .e-content {
+  margin-top: 0.5em;
+  padding-left: 0.5em; }
+
+.notes-subtitle {
+  font-size: 1em; }
+
+.note-photo {
+  width: 100%;
+  height: auto;
+  image-orientation: from-image; }
+
+article header {
+  margin-top: 0.5em;
+  margin-bottom: 0.8em; }
+
+.post-info {
+  font-size: 0.8em;
+  font-style: italic;
+  margin-top: -0.8em; }
+
+.contact {
+  position: relative; }
+
+.contact-links {
+  list-style-type: none; }
+
+.contact img {
+  height: auto;
+  width: 2em;
+  position: absolute;
+  top: 0;
+  left: 0; }
+
+.contact-info {
+  margin-left: 2em; }
+
+#map {
+  height: 300px; }
+
+/* media queries */
+@media (min-width: 700px) {
+  main {
+    margin-left: 10em;
+    margin-right: 10em; }
+  footer {
+    margin-left: 13em;
+    margin-right: 13em; }
+  .youtube {
+    width: 640px;
+    height: 360px; } }
+
+@media (max-width: 699px) {
+  main {
+    margin-left: 10px;
+    margin-right: 10px; }
+  article {
+    word-wrap: break-word; }
+  footer {
+    margin-left: 15px;
+    margin-right: 15px; }
+  .youtube {
+    width: 100%;
+    height: auto; } }
+
+body {
+  text-rendering: optimizeLegibility;
+  -webkit-font-feature-settings: "liga";
+  font-feature-settings: "liga";
+  font-family: "leitura-news", serif;
+  font-size: 1.2em; }
+
+#topheader h1 {
+  font-family: "leitura-news", serif; }
+
+h1 {
+  font-family: "prenton", sans-serif; }
+
+#topheader a {
+  text-decoration: none; }
+
+nav {
+  -webkit-font-feature-settings: "dlig";
+  font-feature-settings: "dlig"; }
+
+article header h1 a {
+  text-decoration: none; }
+
+article div a {
+  text-decoration: none; }
+
+footer {
+  font-size: 0.8em; }
+
+.emoji {
+  width: auto;
+  height: 1em; }
+
+body {
+  color: #002b36; }
+
+header a {
+  color: #002b36; }
+
+a {
+  color: #268bd2; }
+
+form {
+  width: 100%; }
+
+fieldset {
+  min-width: 0;
+  width: 100%; }
+
+input[type="text"], input[type="file"], textarea {
+  width: 100%; }
+
+input, button, textarea {
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  background-color: #002b36;
+  color: #fdf6e3;
+  border: 1px solid #fdf6e3;
+  border-radius: 4px; }
+
+button:hover {
+  transition: 0.5s ease-in-out;
+  background-color: #fdf6e3;
+  color: #002b36; }
+
+button:disabled {
+  background-color: #93a1a1;
+  color: #002b36; }
+
+input[type="checkbox"] {
+  -webkit-appearance: checkbox;
+  -moz-appearance: checkbox; }
+
+#photo {
+  background: inherit;
+  color: inherit;
+  border: none; }
+
+.twitter-tweet-rendered {
+  margin-bottom: 0 !important; }
+
+.twitter-tweet-rendered + .note {
+  margin-top: 0; }
+
+/*# sourceMappingURL=global.css.map */
diff --git a/public/assets/css/global.css.map b/public/assets/css/global.css.map
new file mode 100644
index 00000000..fa39372b
--- /dev/null
+++ b/public/assets/css/global.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["global.scss","layout.scss","components/fonts.scss","components/colours.scss","components/forms.scss","components/twitter.scss"],"names":[],"mappings":"AAyBA;EACC,+CAAe,EACf;;AAED;EACC,cAAc,EACd;;AC5BD;EACC,uBAAuB,EACvB;;AAED;EACC,oBAAoB,EACpB;;AAED;EACC,sBAAc;EAAd,qBAAc;EAAd,cAAc;EACd,uBAAe;EAAf,mBAAe;EAAf,eAAe,EACf;;AAED;EACC,mBAAmB,EACnB;;AAED;EACC,mBAAmB,EACnB;;AAED;EACC,kBAAkB,EAClB;;AAED;EACC,0BDhBkB;ECiBlB,iCDlBkB;ECmBlB,qBAAqB;EACrB,gBAAgB,EAChB;;AAED;EACC,aAAa;EACb,eAAe;EACf,UAAU;EACV,YAAY,EACZ;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,cAAc,EACd;;AAED;EACC,YAAY,EACZ;;AAED;EACC,aAAa,EACb;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,YAAY;EACZ,YAAY;EACZ,cD7CkB,EC8ClB;;AAED;EACC,iBAAiB;EACjB,kBAAkB;EAClB,iBAAiB;EACjB,qBAAqB,EACrB;;AAED;EACC,iBAAiB;EACjB,kBAAkB;EAClB,iBAAiB;EACjB,iBAAiB,EACjB;;AAED;EACC,kBAAkB,EAClB;;AAED;EACC,mBAAmB;EACnB,0BD/EkB;ECgFlB,iBAAiB;EACjB,sBAAsB;EACtB,kBAAkB;EAClB,oBAAoB,EACpB;;AAED;EACC,eAAe;EACf,gBAAgB;EAChB,mBAAmB;EACnB,4BAA4B,EAC5B;;AAED;EACC,eAAe,EACf;;AAED;EACC,kBAAkB;EAClB,oBAAoB,EACpB;;AAED;EACC,eAAe,EACf;;AAED;EACC,YAAY;EACZ,aAAa;EACb,8BAA8B,EAC9B;;AAID;EACC,kBAAkB;EAClB,qBAAqB,EACrB;;AAED;EACC,iBAAiB;EACjB,mBAAmB;EACnB,mBAAmB,EACnB;;AAGD;EACC,mBAAmB,EACnB;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,aAAa;EACb,WAAW;EACX,mBAAmB;EACnB,OAAO;EACP,QAAQ,EACR;;AAED;EACC,iBAAiB,EACjB;;AAED;EACC,cAAc,EACd;;AAED,mBAAmB;AACnB;EACC;IACC,kBAAkB;IAClB,mBAAmB,EACnB;EAED;IACC,kBAAkB;IAClB,mBAAmB,EACnB;EAED;IACC,aAAa;IACb,cAAc,EACd,EAAA;;AAGF;EACC;IACC,kBAAkB;IAClB,mBAAmB,EACnB;EAED;IACC,sBAAsB,EACtB;EAED;IACC,kBAAkB;IAClB,mBAAmB,EACnB;EAED;IACC,YAAY;IACZ,aAAa,EACb,EAAA;;ACjMF;EACC,mCAAmC;EACnC,sCAA8B;EAA9B,8BAA8B;EAC9B,mCFFsC;EEGtC,iBAAiB,EACjB;;AAED;EACC,mCFPsC,EEQtC;;AAED;EACC,mCFVyC,EEWzC;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,sCAA8B;EAA9B,8BAA8B,EAC9B;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,iBAAiB,EACjB;;AAED;EACC,YAAY;EACZ,YAAY,EACZ;;ACvCD;EACC,eHKkB,EGJlB;;AAED;EACC,eHCkB,EGAlB;;AAED;EACC,eHUkB,EGTlB;;ACTD;EACC,YAAY,EACZ;;AAED;EACC,aAAa;EACb,YAAY,EACZ;;AAED;EACC,YAAY,EACZ;;AAED;EACC,yBAAyB;EACzB,sBAAsB;EACtB,0BJXkB;EIYlB,eJLkB;EIMlB,0BJNkB;EIOlB,mBAAmB,EACnB;;AAED;EACC,6BAA6B;EAC7B,0BJZkB;EIalB,eJpBkB,EIqBlB;;AAED;EACC,0BJnBkB;EIoBlB,eJzBkB,EI0BlB;;AAED;EACC,6BAA6B;EAC7B,0BAA0B,EAC1B;;AAED;EACC,oBAAoB;EACpB,eAAe;EACf,aAAa,EACb;;AC1CD;EACE,4BAA4B,EAC7B;;AAED;EACE,cAAc,EACf","file":"global.css","sourcesContent":["//global.scss\n\n//variables\n$font-stack-body: \"leitura-news\", serif;\n$font-stack-headers: \"prenton\", sans-serif;\n\n//solarized variables TERMCOL\n$base03:    #002b36;//brblack\n$base02:    #073642;//black\n$base01:    #586e75;//brgreen\n$base00:    #657b83;//bryellow\n$base0:     #839496;//brblue\n$base1:     #93a1a1;//brcyan\n$base2:     #eee8d5;//white\n$base3:     #fdf6e3;//brwhite\n$yellow:    #b58900;\n$orange:    #cb4b16;\n$red:       #dc322f;\n$magenta:   #d33682;\n$violet:    #6c71c4;\n$blue:      #268bd2;\n$cyan:      #2aa198;\n$green:     #859900;\n\n//global styles\nhtml {\n\tbackground: url('/assets/img/escheresque.png');\n}\n\n.map {\n\theight: 150px;\n}\n\n//layout\n@import \"layout\";\n\n//components\n@import \"components/fonts\";\n@import \"components/colours\";\n@import \"components/forms\";\n@import \"components/twitter\";\n","//layout.scss\n\n//boxes\nhtml {\n\tbox-sizing: border-box;\n}\n\n*, *:before, *:after {\n\tbox-sizing: inherit;\n}\n\n#topheader {\n\tdisplay: flex;\n\tflex-flow: row;\n}\n\n#topheader a {\n\tpadding: 0.5em 1em;\n}\n\nnav {\n\tpadding-top: 0.5em;\n}\n\n.social-list {\n\tpadding-left: 2em;\n}\n\n.note {\n\tbackground-color: $base2;\n\tbox-shadow: 0 0 10px 2px $base1;\n\tpadding: 0.5em 0.5em;\n\tmargin-top: 1em;\n}\n\n.note:after {\n\tcontent: \" \";\n\tdisplay: block;\n\theight: 0;\n\tclear: both;\n}\n\n.note a {\n\tword-wrap: break-word;\n}\n\n.note .e-content p:first-child {\n\tmargin-top: 0;\n}\n\n.note-metadata {\n\twidth: 100%;\n}\n\n.social-links {\n\tfloat: right;\n}\n\n.social-links a {\n\ttext-decoration: none;\n}\n\n.icon {\n\twidth: auto;\n\theight: 1em;\n\tfill: $blue;\n}\n\n.reply {\n\tmargin-left: 2em;\n\tmargin-right: 2em;\n\tfont-size: 0.8em;\n\tpadding: 0.5em 0.5em;\n}\n\n.reply-to {\n\tmargin-left: 2em;\n\tmargin-right: 2em;\n\tfont-size: 0.8em;\n\tpadding-top: 2em;\n}\n\n.reply-to + .note {\n\tmargin-top: 0.3em;\n}\n\n.mini-h-card {\n\tborder-radius: 2px;\n\tborder: 1px solid $base01;\n\tpadding: 0 0.2em;\n\ttext-decoration: none;\n\tmargin-right: 5px;\n\twhite-space: nowrap;\n}\n\n.mini-h-card img {\n\theight: 1.26em;\n\tdisplay: inline;\n\tborder-radius: 2px;\n\tvertical-align: text-bottom;\n}\n\n.like-photo {\n\theight: 1.26em;\n}\n\n.reply .e-content {\n\tmargin-top: 0.5em;\n\tpadding-left: 0.5em;\n}\n\n.notes-subtitle {\n\tfont-size: 1em;\n}\n\n.note-photo {\n\twidth: 100%;\n\theight: auto;\n\timage-orientation: from-image;\n}\n\n//articles\n\narticle header {\n\tmargin-top: 0.5em;\n\tmargin-bottom: 0.8em;\n}\n\n.post-info {\n\tfont-size: 0.8em;\n\tfont-style: italic;\n\tmargin-top: -0.8em;\n}\n\n//contacts\n.contact {\n\tposition: relative;\n}\n\n.contact-links {\n\tlist-style-type: none;\n}\n\n.contact img {\n\theight: auto;\n\twidth: 2em;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n}\n\n.contact-info {\n\tmargin-left: 2em;\n}\n\n#map {\n\theight: 300px;\n}\n\n/* media queries */\n@media (min-width: 700px) {\n\tmain {\n\t\tmargin-left: 10em;\n\t\tmargin-right: 10em;\n\t}\n\n\tfooter {\n\t\tmargin-left: 13em;\n\t\tmargin-right: 13em;\n\t}\n\n\t.youtube {\n\t\twidth: 640px;\n\t\theight: 360px;\n\t}\n}\n\n@media (max-width: 699px) {\n\tmain {\n\t\tmargin-left: 10px;\n\t\tmargin-right: 10px;\n\t}\n\n\tarticle {\n\t\tword-wrap: break-word;\n\t}\n\n\tfooter {\n\t\tmargin-left: 15px;\n\t\tmargin-right: 15px;\n\t}\n\n\t.youtube {\n\t\twidth: 100%;\n\t\theight: auto;\n\t}\n}\n","//fonts.scss\n\nbody {\n\ttext-rendering: optimizeLegibility;\n\tfont-feature-settings: \"liga\";\n\tfont-family: $font-stack-body;\n\tfont-size: 1.2em;\n}\n\n#topheader h1 {\n\tfont-family: $font-stack-body;\n}\n\nh1 {\n\tfont-family: $font-stack-headers;\n}\n\n#topheader a {\n\ttext-decoration: none;\n}\n\nnav {\n\tfont-feature-settings: \"dlig\";\n}\n\narticle header h1 a {\n\ttext-decoration: none;\n}\n\narticle div a {\n\ttext-decoration: none;\n}\n\nfooter {\n\tfont-size: 0.8em;\n}\n\n.emoji {\n\twidth: auto;\n\theight: 1em;\n}\n","//colours.scss\nbody {\n\tcolor: $base03;\n}\n\nheader a {\n\tcolor: $base03;\n}\n\na {\n\tcolor: $blue;\n}","//forms.scss\n\nform {\n\twidth: 100%;\n}\n\nfieldset {\n\tmin-width: 0;\n\twidth: 100%;\n}\n\ninput[type=\"text\"], input[type=\"file\"], textarea {\n\twidth: 100%;\n}\n\ninput, button, textarea {\n\t-webkit-appearance: none;\n\t-moz-appearance: none;\n\tbackground-color: $base03;\n\tcolor: $base3;\n\tborder: 1px solid $base3;\n\tborder-radius: 4px;\n}\n\nbutton:hover {\n\ttransition: 0.5s ease-in-out;\n\tbackground-color: $base3;\n\tcolor: $base03;\n}\n\nbutton:disabled {\n\tbackground-color: $base1;\n\tcolor: $base03;\n}\n\ninput[type=\"checkbox\"] {\n\t-webkit-appearance: checkbox;\n\t-moz-appearance: checkbox;\n}\n\n#photo {\n\tbackground: inherit;\n\tcolor: inherit;\n\tborder: none;\n}\n","//twitter.scss\n\n.twitter-tweet-rendered {\n  margin-bottom: 0 !important;\n}\n\n.twitter-tweet-rendered + .note {\n  margin-top: 0;\n}\n"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/public/assets/css/images/icons-000000@2x.png b/public/assets/css/images/icons-000000@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..d65438c12c6e2a626bf4afa91e17ac77ce3835d5
GIT binary patch
literal 1548
zcmcJP_d6R17{_B)ku#cFF?+4XYR#fX2^ujXh&!~-mf~p5qJ*GY9;+cnjYMmUSu19*
zimFtUw9fX_x)5B$T@dQh{tx&5^7(#$dEe*#KF|B6BM~s5po|~@006?REuA>j1pv4O
z1b8?~0&Ako0WaFz-W&jE%@I2B=Hqy-2qzd6&@>@S=NK=f9mtJEP>6Iw
zI0OD93IJ~$B(1W$ir;QK4!D>phG$AbVBB_1RCK&YKRj&%0N_)ATbiR{=5|UqpEoFq
zruqJ{uY=kltJNM&B}oOTBx}A_(g-PMD4Rx8^-N)SmPx@EvKB
zcd`0I>?kQBApB(?le;lE@HKlZu*Y~$<{bMxn+|4O_z|j2bY)R-ca>iux%n9hpR5J8
z;qD(*Aq0u~YAf)kFH7F$^2t2QL=n@+iu8z+6iqO91zuW3>asQuU-GV6L?^i)>bq(f
z(V2A(Ma_;`M2vRFU=s#wE!vhbGL;A6H9&IxBj6}#!;cdv(o#_$K>{S6mCu!8d-;Efe%mbZElr6`}n}n
zC}3A^zQyaI9BatvzFXbZ8Il2Gx~Qwi{o5m2%hBxCVQpb?igC5R?&_BTnTh-|i|er_
z+64|_Ip~_gDn`NRfbo2^0^_8wrT>`DwvX;yDuT|4pu?4GOu>IYxo*hZwJZOcMR0N0
z)M0co&bYtS0Y63F887Znyp(bYgU%VAX|}C2$t!!Of20W}`BM=+hP~T$l){|R=lKRX
v@4R)dA?TsAz)Cx1X+KUU11|vpZK)lI+DJGsJet+9=D}-ee)GPTvh_l3+

literal 0
HcmV?d00001

diff --git a/public/assets/css/normalize.css b/public/assets/css/normalize.css
new file mode 100644
index 00000000..5e5e3c89
--- /dev/null
+++ b/public/assets/css/normalize.css
@@ -0,0 +1,424 @@
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS and IE text size adjust after device orientation change,
+ *    without disabling user zoom.
+ */
+
+html {
+  font-family: sans-serif; /* 1 */
+  -ms-text-size-adjust: 100%; /* 2 */
+  -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+  margin: 0;
+}
+
+/* HTML5 display definitions
+   ========================================================================== */
+
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio,
+canvas,
+progress,
+video {
+  display: inline-block; /* 1 */
+  vertical-align: baseline; /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+  display: none;
+}
+
+/* Links
+   ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+  background-color: transparent;
+}
+
+/**
+ * Improve readability of focused elements when they are also in an
+ * active/hover state.
+ */
+
+a:active,
+a:hover {
+  outline: 0;
+}
+
+/* Text-level semantics
+   ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+
+b,
+strong {
+  font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+
+dfn {
+  font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+  background: #ff0;
+  color: #000;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+  font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+
+sup {
+  top: -0.5em;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+/* Embedded content
+   ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9/10.
+ */
+
+img {
+  border: 0;
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+
+svg:not(:root) {
+  overflow: hidden;
+}
+
+/* Grouping content
+   ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+
+figure {
+  margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+  box-sizing: content-box;
+  height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+  overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+
+/* Forms
+   ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ *    Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+  color: inherit; /* 1 */
+  font: inherit; /* 2 */
+  margin: 0; /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+
+button {
+  overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button,
+select {
+  text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ *    and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ *    `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button; /* 2 */
+  cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+  line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
+ */
+
+input[type="search"] {
+  -webkit-appearance: textfield; /* 1 */
+  box-sizing: content-box; /* 2 */
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+  border: 0; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+
+textarea {
+  overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+  font-weight: bold;
+}
+
+/* Tables
+   ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+td,
+th {
+  padding: 0;
+}
diff --git a/public/assets/css/prism.css b/public/assets/css/prism.css
new file mode 100644
index 00000000..86122e46
--- /dev/null
+++ b/public/assets/css/prism.css
@@ -0,0 +1,188 @@
+/* http://prismjs.com/download.html?themes=prism-dark&languages=markup+css+clike+javascript+git+http+markdown+php+php-extras+scss+sql&plugins=line-numbers+show-invisibles */
+/**
+ * prism.js Dark theme for JavaScript, CSS and HTML
+ * Based on the slides of the talk “/Reg(exp){2}lained/”
+ * @author Lea Verou
+ */
+
+code[class*="language-"],
+pre[class*="language-"] {
+        color: white;
+        text-shadow: 0 -.1em .2em black;
+        font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+        direction: ltr;
+        text-align: left;
+        white-space: pre;
+        word-spacing: normal;
+        word-break: normal;
+        line-height: 1.5;
+
+        -moz-tab-size: 4;
+        -o-tab-size: 4;
+        tab-size: 4;
+
+        -webkit-hyphens: none;
+        -moz-hyphens: none;
+        -ms-hyphens: none;
+        hyphens: none;
+}
+
+@media print {
+        code[class*="language-"],
+        pre[class*="language-"] {
+                text-shadow: none;
+        }
+}
+
+pre[class*="language-"],
+:not(pre) > code[class*="language-"] {
+        background: hsl(30, 20%, 25%);
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+        padding: 1em;
+        margin: .5em 0;
+        overflow: auto;
+        border: .3em solid hsl(30, 20%, 40%);
+        border-radius: .5em;
+        box-shadow: 1px 1px .5em black inset;
+}
+
+/* Inline code */
+:not(pre) > code[class*="language-"] {
+        padding: .15em .2em .05em;
+        border-radius: .3em;
+        border: .13em solid hsl(30, 20%, 40%);
+        box-shadow: 1px 1px .3em -.1em black inset;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+        color: hsl(30, 20%, 50%);
+}
+
+.token.punctuation {
+        opacity: .7;
+}
+
+.namespace {
+        opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol {
+        color: hsl(350, 40%, 70%);
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+        color: hsl(75, 70%, 60%);
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string,
+.token.variable {
+        color: hsl(40, 90%, 60%);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+        color: hsl(350, 40%, 70%);
+}
+
+.token.regex,
+.token.important {
+        color: #e90;
+}
+
+.token.important,
+.token.bold {
+        font-weight: bold;
+}
+.token.italic {
+        font-style: italic;
+}
+
+.token.entity {
+        cursor: help;
+}
+
+.token.deleted {
+        color: red;
+}
+
+pre.line-numbers {
+        position: relative;
+        padding-left: 3.8em;
+        counter-reset: linenumber;
+}
+
+pre.line-numbers > code {
+        position: relative;
+}
+
+.line-numbers .line-numbers-rows {
+        position: absolute;
+        pointer-events: none;
+        top: 0;
+        font-size: 100%;
+        left: -3.8em;
+        width: 3em; /* works for line-numbers below 1000 lines */
+        letter-spacing: -1px;
+        border-right: 1px solid #999;
+
+        -webkit-user-select: none;
+        -moz-user-select: none;
+        -ms-user-select: none;
+        user-select: none;
+
+}
+
+        .line-numbers-rows > span {
+                pointer-events: none;
+                display: block;
+                counter-increment: linenumber;
+        }
+
+                .line-numbers-rows > span:before {
+                        content: counter(linenumber);
+                        color: #999;
+                        display: block;
+                        padding-right: 0.8em;
+                        text-align: right;
+                }
+.token.tab:not(:empty):before,
+.token.cr:before,
+.token.lf:before {
+        color: hsl(24, 20%, 85%);
+}
+
+.token.tab:not(:empty):before {
+    content: '\21E5';
+}
+
+.token.cr:before {
+    content: '\240D';
+}
+
+.token.crlf:before {
+    content: '\240D\240A';
+}
+.token.lf:before {
+    content: '\240A';
+}
diff --git a/public/assets/css/projects.css b/public/assets/css/projects.css
new file mode 100644
index 00000000..d108175a
--- /dev/null
+++ b/public/assets/css/projects.css
@@ -0,0 +1,10 @@
+#projects {
+	padding-left: 33.33%;
+}
+
+h3 {
+	float: left;
+	width: 45%;
+	margin: 0 5% 0 -50%;
+	text-align: right;
+}
diff --git a/public/assets/css/sanitize.min.css b/public/assets/css/sanitize.min.css
new file mode 100644
index 00000000..9d0d9800
--- /dev/null
+++ b/public/assets/css/sanitize.min.css
@@ -0,0 +1,2 @@
+/*! sanitize.css v3.2.0 | CC0 1.0 Public Domain | github.com/10up/sanitize.css */audio:not([controls]){display:none}button{-webkit-appearance:button;overflow:visible}details{display:block}html{-ms-overflow-style:-ms-autohiding-scrollbar;overflow-y:scroll;-webkit-text-size-adjust:100%}input{-webkit-border-radius:0}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button}input[type=number]{width:auto}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}main{display:block}pre{overflow:auto}progress{display:inline-block}small{font-size:75%}summary{display:block}svg:not(:root){overflow:hidden}template{display:none}textarea{overflow:auto}[hidden]{display:none}*,:after,:before{box-sizing:inherit}*{font-size:inherit;line-height:inherit}:after,:before{text-decoration:inherit;vertical-align:inherit}*,:after,:before{border-style:solid;border-width:0}*{background-repeat:no-repeat;margin:0;padding:0}:root{background-color:#fff;box-sizing:border-box;color:#000;cursor:default;font:100%/1.5 sans-serif}a{text-decoration:none}audio,canvas,iframe,img,svg,video{vertical-align:middle}button,input,select,textarea{background-color:transparent;color:inherit;font-family:inherit;font-style:inherit;font-weight:inherit}[type=button],[type=date],[type=datetime-local],[type=datetime],[type=email],[type=month],[type=number],[type=password],[type=reset],[type=search],[type=submit],[type=tel],[type=text],[type=time],[type=url],[type=week],button,select,textarea{min-height:1.5em}code,kbd,pre,samp{font-family:monospace}nav ol,nav ul{list-style:none}select{-moz-appearance:none;-webkit-appearance:none}select::-ms-expand{display:none}select::-ms-value{color:currentColor}table{border-collapse:collapse;border-spacing:0}textarea{resize:vertical}::-moz-selection{background-color:#b3d4fc;color:#fff;text-shadow:none}::selection{background-color:#b3d4fc;color:#fff;text-shadow:none}[aria-busy=true]{cursor:progress}[aria-controls]{cursor:pointer}[aria-disabled]{cursor:default}[hidden][aria-hidden=false]{clip:rect(0 0 0 0);display:inherit;position:absolute}[hidden][aria-hidden=false]:focus{clip:auto}[tabindex],a,area,button,input,label,select,textarea{-ms-touch-action:manipulation;touch-action:manipulation}
+/*# sourceMappingURL=sanitize.min.css.map */
\ No newline at end of file
diff --git a/public/assets/img/escheresque.png b/public/assets/img/escheresque.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1a4638a48986625af5bae1477fd181f0650b991
GIT binary patch
literal 395
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

literal 0
HcmV?d00001

diff --git a/public/assets/img/jmb-bw.png b/public/assets/img/jmb-bw.png
new file mode 100644
index 0000000000000000000000000000000000000000..9db94a2fef6b3effd3d7559c12aec11e78f00368
GIT binary patch
literal 30162
zcmb?>cT`i)_U}muB|&;odce?vsPx`j2t73ENbkK!m8yVB4Tu4xCG?_5sG@)(MS7J`
z6ciK?P-#k$$M@d#Tlc=V*8A@_Yvr7M_Ut`-pP4x`pX}M^AI?{)f9q;!I2dD$v~~5h
z01yZOsJ{Uh1$^=I^$Q8Y=%~YQSy{s==K(T+17HCV0MBjb;DCQ*{-1K8`#+RqRI`e`?IC%$zT+q$`
z@Pq!XJMb_1zjQ-foiEyhEne_1g@w9a*n<7jFZaVk{?VoW=lz+T1A_jclP+i(XOG(#
zGSn|G=xhJ>|AGPlp5T8vP*+PsT1-w_T2x$A4DRG}+u0i)?0nnjpH~03%RgiF?=}%7
z06=%)Tg#YpXi(U{d60i@8C0DJ=0fGyw$a0r}$
zKp;vG4TuTE2I2wngG4~$AX$(yNDHJ7!hozmjv#lCA1D+Q4N3$(0A+)4pi)pZ=sBnz
z)B_p>O@QV>E1(U~FVHcV415X94CVq0fNy|h!D?VVuo>76><$hDM}m{U>EL{D8MqGI
z0`3972hV^%fw#a1WB?g887mntnJAeonFg5=nKhXkSrAz)SsGa$Ss7UaSqE7^*%a9)
zvhQSnAQTWL2pl2`QGlQz<`8E{AS4#@5Q2kLL0TYhAybeQ$PdV0avE|@auITQa$WLU
z~ENvf|@
zCs2AQKU5xS1a*N%Kr^6tXa{r*x&}RgF~9_2N-#5+7c3r@4{Lz+!4_eA)YQ~`)N<4&
z)SlFF)cMrUs0XN5sQ+AIyo9`@amn^l=%w^am6y6N&0pH1p`j6=QKhk_386`+sit{D
zvrO}wmWlQ{tuCz#?Ooae+7{YL+8sJ59Y38KojqM7T^`*Fx-q)%^iX;MdJX#9^s)2>
z^zHO>^al(~3}OsM489Bx8EO~?8NM-6G72ziF}g4&F_tsFVf@TQ#&nfQgUOjGkqOV#
z$F#;w!7RwE%k0JcfVrM|l=%k>Ba0-91k@E^RKyeQsK-csIC-V;7SK6AbVzDB;KtFWuGSKY2+
zul8R3f#5+HAfgeq2ogV(UzXp4|1p0*|B-;8fTh5FfmVTUf>#7}1tSG(1s8>Agj9qA
zh027cg(-w(g}sG~gvXI!q!iKvS%4f90gFhBc#0H>Ok5+sCU?#6TG_QZ(MzIgqG6)7
zqAS-~uj^k=xZZkw=LX`2^^L3>{Wt#Jl)CA26Mu6-j8P0NmLS$4_DdWo?krv)J}p5b
zp)GM&qD|tbq==-efq=Tdzq&H*`GLABZGIO%bvc|FxWe4QQ
z<<#Zw%Dt5PBQGr0A>;k1^u
z`Lx}&YqfvqNa;lBbfd^odZ;YaoGzEHvu?HS53~$A2K`p=lAfs^PH$BosUM`@VE{Hj
z8{`-)8uAQU
zT*y4syw`%x!q%eN;>c3dGTZXgtsA#uZoRi+xAL@Vv!=ARu&%H^u+g%~wOO;3vb|?J
zYbR)T$8OM`-QLH(%Yn|}w!;fYaz{(Y8pqSyMz_muA2{hc6*~QJ)^L98yyc?mf_2$&
zRdUUC{pzOVmhJY>U|;mqM@0;xsb?2OltwPM6~>9
z^=SRnX4N*)j&ASmQ0O3bUhk}Y$@{XPi=`{$73@{gtMk{9uMfHdy1)0h_k8Yk=v{bo
z>&^6AleeRNdVK@$wBNnySL=U0pfvDuP=2s|NOq|8z4ZH*VX0x_h|~yiRC=^!OlGWY
zTyDH$LUH2Nq{?K^l;+gCY2E4fGlnx0v*xoO=4|IaeQ^2kZQf`8Cn=0{vJkgOzL>T|
zzm&Jkxm@;9_+#TI=}%oNnk&PrrmG8|oj-4V3I1}rmb6Z@p7)jKYxOtrZ!b5rH^w(@
zHrKWSwobm^+h*7<+!5Mo-c{Wl{&DNa+Rvb$=f58AvF%mvOYZj`7#}Pj`W~JfrTu36
zUG+!yPyeyy@z;~^Q_9o)GvTw2zj}Wc&wbC&{|lR3zknt1|KJi$SGU`tJ|Xab0E>pd
zkAG+o+%({}vnyN_{tt-xH-PwGyZ#5KI6VP?)?@&8;qp5*0ga21Qh+2`F
z&;8>4{aidlJpKLPo__zJxBqn0|7H1q;o(1i{s%LMxZb(Il^1^c2SfyUx_gAcb^StI
zgZys)69=6yUr-xB};N-O}J
zWt^X%l%AiTUGxRn0swS}o-Y6z067^10wE*6xR8^RQ&3)_y1*)wbkx+)OAK_3j0|)P
z3{0$?mzkK^Sr{0u@Lpl(;^N`qVY{$jHDK_AUwqm<+h6WdI<&wBCjEKn<#%`t6<*d^f#s8$n0<;|WB3S4+4_JNzl-vu;lH_urja$xbUX*T
zJh;22=+I^JtTpEVgTWBCa_D86zyJHz*{E@r)5T%uEq%$Kkp3;pYuA=LZc*`=+Hnv%
zt~`)j-lQj)A;_a=YTOC?)7z&SzK`~Z{*5j_PoE1EK7BN?BjaOUV_^=u)KPwvEurCm
z%%)X8n=Xs@Co!*zDd$K%>6lnn6AA>0sEueBDQO}IT)*qJUK_oX2yQkYZ>&p0^?VRKL@^-d0#uk
zlT3e`HTw0VQ7O|7#^#2bwR^Ts1oe*2$h=PBwPi3{
z=rp<)S0^NJDNsQFZ$kX$8tp4P9&vR1(eT)=T7$_dxL7}p`PeLxt4nyNRGE=kNgQdM
z@&dVVGmFJ4DVz06Kt2oeu#uRtC?eSSEgRlAN0JnziTlZx_JesP2Lnp?ejA3T~ZVt%DyP
zbwWNvJw3YbV%}zq7FT-IJf`0?v-S0aq6`HC`ZrbNA6w7#<$3%DNNrF!k}j0zs012#WGl*xUd$yIpo?sNmwPvC>uve<6p4WmCU?ROJCBx3Gh2)<
z+z{xy>|DOn#L^iQXPu;zZ$cr@zt+@*VT851x7X^2@a5&SBhhaeonJ?$pOjulB>~Na
zUzu5t${KRM>UrrK@+Ego`d1?@@2RIG^1UEc8ou_c`cQRj;cYf$=Zjv<&R6O))wtUY
zq$HZYqMFKC?@=v&UUQv}CQ)VBt5cIjcN?_=Z1dH&6;)DFlwXXLT&3lsJ1*1RmMJ5=
zc*&VS1H~!b3QXFMT|<^lvoQjS;Z$xw5ZrPO&_u>WJ}vhnnXX6Y)|+xO2@lQmWXA8b=
zm5Q5jXo>N1HOfvydEn|IKifuO&3;-$P6v|at~qMCq2twv(&Lu;fFY}hlgca~
zUg7KA2v7=&{-zE$aa6wC-t{Zgqhnr|luaeE6PWgX^SHLvVngo{9Sa|`bWi#a&uq>0
zm2lSC-ST0VlBb3udKE9iqe6Ofg@vz^3k}AVbH;4Bmxp*?e^r}YCDf*7M*G&C$9mbL
zOTlM|kqp#TA;a9iVeRd!BpQcFu)M-iQCDsd>b+PxFk<&?5=$VU4Vji@%cx&y09-YQ
z;x*>|h1`6M*e1DDSPGxbmCtE)+s`dC1tm80+gj9(>&pUWGc+S;zvh>A?;gS8?H
zWgGQ_?Vs+O>Zk^E=#0GZ(wUAwvGk1TeI%hhK|=A1{%)YB+GA9u{O*1Zr
z*axDe*-w5*&o$O22c3!kgo6bka2fyg?=ZiKNt5I}tiOh?DIrDK+G2Rzy@lBMoJb)uM}|
zrO!q~p@t`ViQE{w&r28BSqVh(Hk*j#tb5&%PlvJ`Z>)h$P;?>PB%k9j@a=TL%
zo3E{qvrM=R2Q=;!CYs(u>^$mqSE@GmZKKy_j+*vr(er$FmBsFTP_{X@{f8>-EIKd0
z*sEdtnT7ck<(K9h4+4=$rVW8aua+J)d*iY@??j%2vSPDq7u+!_sR(-6h8xp|vDE&E
zjM9udb@y84?uUPJ{0>~hG!A>
zt=nC7e&sPE*a{g;2x!ve|0INi4s%?q`39@yR4xH}vW$eol6?^Dg%vLjmKVsZ;$u
zo}&hpxv)nx>LZyjV*+y{C*Ec5#x$nV?`e#~aGAD{LHA89RS4(Q7oR^)cce_-_GByX
zmw*w$1`vI2PiK}LPt^g4dDgFPmQ_IcUO_@cMHS2`ep{apDKT;fzf+MV(DhE3hF|FG
ze*HP{#sX8ov5>oyTZ+=<8B#aA>px1=^O3)Y!!VXqJPEbYM^P>C6ouH?QB8KlR6GtM
z2=Cv=#uW?Q#C%X52dP-ElL!MQZy$ZUcF3ak<#$-M8o*fp9`2Ii6@P8fzB&)b(|2b8
z9$o!;uP@Bu{xMUSg)grVq8JxZe9%yg_pCue(TauHQ75oz>v=y_!#B-Af_x82rJ@MX
zL&rUf>>*A1YQ)iqt-88X(4Ey>PZV}LTk8%44+6Nyh3$;~Xs<<@yUVcf+~C?|Aq>LQ
zHOIc9a@u)i7ZtSRge0!E(j!G4z4z4>Mw)yIuYvkIyMghSz)|B%>eI3x^il_hMWk?>
zMT!+41GaOSa#(uhH=f;SWOxxsbT!spLH{}jtk-0QI$&HWE=XLJU>)|PQ2_SBBAbGox4Q!8l#Ub^%Q1k{9?=`0Hx@+Xqr9GyCf^;o&RQXoHSKFR{VltRo=Cz+I}fMG`9n
zsqSWN{-yef?zI&D8x5DCgY@TtkARclw%updDf(XPqNY+|<;v&vBM->=VMva+fpmk*
zO)jUSm#X%zlu=PBoArEGtq$|WsPT9`Ve1ydMa1)7QCY|9sfRO<;Z4n|7!-6@%MCx(
zSB|9V-J7nMY3@lEiqh|RUmNi?uUchGwdgy^5MYWka(zgbxhCwdGPtLsM
z@!FqvO|Vo6!q#BaXUX^Xeh$xQ#W9f0N%lh?O;2B`&Xx(sqn$rWxrz13`0^!-X|S;U
z@w&=}^W~auK4QZpWNXHF=#8k!R!L9NQ!*z&s~HglKDm*w^z7%69|^cX(F8)%WWXJm
zvBV!TYXg>qhVnL-8pc&?pPYQ)?O*NG`Ht~Tfyu+^WcY6dXeK@Y1p
z(B+5YG_&BryXe(0{I>Fe;ddcHvOo**yVl9g)im72fs#4;u{bEYDQwM3ywa#U*RM%-J%XzuMQKP8kY2X773KI&s+7&-grG0p&r)3kAC`
zyyuJAJS=h|+HV|Di}GJa+1%z22#?Da{E(x(uVUHxp}0>Z$llXPHc{DC2%AYa&Q^C=
z-AFxaVQc-sH-V`81OceHWDs@6<%4#M=|mN=bYY$JS(VeTmlHtEJiPc{Ova*
z!gteoZ&6O2)nXQI&p7hiS45oyF*O6OWAx}$6x&g)fh6q9yGi65)m&`@{g%Nm+bp{@
z3SC-qAd_?@;WS;!Edvm*)fK$((>EI|uy?`D{S?Sff&#Edrh@h~9()p?&q6k?nTuD;
zF)np{WtvU5r9q@N`@J$CUYesk(;Lg%ToH*o0|bYSo1EuZ`j6u?C|19rOyHTSUnSY@
z>7~owcND6?@KsgkbVz*jO8lPGhM!vSv;LdQPBL8j5}u%hd@$kzXJF(j3xvU+e!>Vp
z%gjb3!^~RWd&w%AUoH?f;l78Iikh^nrn!Ten|=LL#HS#=q+{CJkMZ++MEcjjk?55g
z8ESas_`yv*J!2-YN8qt#r%5`t#eDQxFQ%wJBu+^yyz6#F!Nfj=aWoubOc!wz_G;OG
z*lgwS!$eL<0=_!Asba44bd-(k9C+k@yna@8AM@yySg#?R5uxcch{ufk1wAP
zzjl+d&Ps
z!upBqh;wRQ0!6^bC
z-|ECLUskFS$oV3q^l*w=%O-9gSGI}HfwAd+oh@5{B`!Z%$x2+1Om7KGh+t!}Sb+xk
zWk_L+g>QON;Zqtfh9xFC#^69gsd#a~FVDtPcETaJ0aYhGQQui>t;+n9H{uohM
zjoZncGt!hX;nF)A?LAjhIkL2xmN5m>bTRV-%Gb1GDLRiyNRgx=b^PH|k^E@8NzS0L
zQ{7Bf>n~B^XCn7H-5%!zsAsdRs_XC=Ez)&SM-CE~+F$uJ_b{t
z6k(`k+UCTnDl2zvZoW_%c31v(t9FoQnk!j?XL9qQWN!+7VZX6dUZOfNkGd(Q*Oc4X
zTiz$Ja+Pgn`67F+$7^4?F$c0$6p?}9nEsvBZ
z7n@xBw6{|N;xn_dDbIl$%U#pqqNSH4bNy)Q(SXPktBj3X1)o>#Te6D=(P3FzDQA72
z%A7Lt1r5T=#wEqgmf_>w25rJ7AYo1(`@3jSw~{HZMLf%m!d2aK09CJ?L=RZ?r?_*v
z5n0n@;R1#R_AM4)nIZX!N)`3K_Mb5BQohYY(NhvAb6PcSk8LBL{9NtLTrqKYqOoi)
zgTz`|os5v$07bQ(ec6XMH6(YIuvu=OYXQMy4PJw)Fpk*YRop1`RGu5LGbY{1B65eg
zN4^QmGjO3WfvQ(knnDa4oW{NuGo9}#3nJj9y70u^)JB|q)4(?+ZJP+#saTMj(usi^
z@muSwpE$CfTO_)_Pu;gQ>UJmBmitkAj>Vf^qJb5Y`;tY^6uSd->P<9wzhr-4q%7Dn
z?p$}Qf&x9n_vM!;B(~7ts5|ZxbaZ=?e#g*3EiiQs-
z#$oYBO;^-hEgMSblG
zZcJ6WIoeoR2apYNEQl??is%e{AKG5|5l+zM7tm(f5mAUhBxYi^Qr@s49j@)w=-Is4NBsOzC9h?OX6buA0e3+wwPLvJw`h
zF5uV$yE(`1lQie+jS=w@J%`n1EMjNE>gLV9yW2+bK%IUVE>l#&F+y$F;A$F23}fMX
zmF%%ac9n6lhIuA2SAF`)0VTMk&G=DwM9+3l#dl1$%v~8c+ld(+I0O4f$D>pRMjZey
zlSu7@PA{lA(wh&v^99>_ull1~t4b|fP-wqwSqgCf-Pgx+9G%xCD@FZm;uTQF14ku0
zxlJp>m2oj%UA;Ywx@irz#`Fy|+P1s0RjlQmAx`-l{5A`c2a9)-glO==sLeHg%KRm>
zBj(xwaqrPHB?ry4=PTPFb@HP%vsCm4)+rJV_r{9pbX>At>BklR?V1)pW}2m$Putvc(#jp
z>ZN02*j)#`hyf&&G-G=fKBip`b-WaTVOiMPRwceO>xHp~t4BTc=BkxWU^%_1%X6#2
zW{&IHXlcg^mf|T__j)^bwcA1Yd#AOgd}S=}C(ZO3^Lgm!4HLg@<~}wt)cn$#Y}E`e
zhDJ(n>7Z&h>Zk$0`VIH&B7tqlpX}x;I?oY@
z)(DE3qE%yNOyh0y9S*3eV??%@<4IW6jcIzKlsKTy=$_#)+u_hlY5w~hpo_f>VQW|m
z!1I9TpEwi`yTSW7r+k@fL#hfvlw6x5o)x@U9*uWQ#igg}DBS@ecl3@yIi
z0dfl2QNg&PwYeGTiM@
z{o;bdD!+pwn#W;{#x0BG&G>6ViImTnG@H8*%ie9-gk!V$MMRkqi3i-%w%;Cm`q1B-
zZrE6|I&>Y@c!DF~<#&)*FF)g3>pbE@fj&Q`XvD}~Dwn0x@g-0sDn18{7Ar}jd
zOMFTNKC>pM4d>w_icEyD*nYx!N>1TCnR7QI1}cVOLC|VwAD`xGbCLM7WIG!yzr9ks
zs^Ifliy>^=WaZysR1g45!oKmk#^H2)qm9gW5CI5{fQv53E{OUd3&?Fysg{58sL9h%y65
zsqUH+1(`|a%?Z!}DXo*k`R5pHeOn4Hk+3tdT9tw<>X)ncwiJ$0qsml;Rqfb>_@OU%
ziyhR2S&mAdJY1~w%8tH2ZC+5j&faQ;ndBwcJgXI%?h2fWlO@X*m-H`8*_3mD0+thbe5TtF
zQSA}#%IjxU#cRuErZf9Oz9J)F!1~Q~2>#clG>ScPkp#KnK5N6mcB8apL=B(L)!B-<
z<`Gf$yD3x819HFHb>Ph6=%MyMQxMob#~T=%kQsBKAkUJ-v>zs1>zR#=w4Swtxt!CQ
zk*01rIE@i_HIDM+&Jl+W;>z)mZK3!Nzn^u^st=Rb>
zgue1?hv}V!m3E{Krv33wv?ii()cgqd^rNb49DyJEM=hb5C6~ujO#Oi0{xS2E-y-Ya
zLNkhKAB-%!6_ZSuV^ete&$fz4k4_{=tV=8?|IqtWt}_TSq)7|%*B
zliuxRHDMHI0&8;M)_!S>RZPjU2WuTkD%kz5-^8hU5vip?+i+z`Bpd6)eGBr-ASlLI
zuRs-H6nzfppVf$Zn{>_GXb9!fng|RH>e}frW)ip>pAM|v2Q9KcNy69qtRshfGo$f6
z4|yVMwp=0UpEJD}vn33KDe_AxghghAt7b0Ffdz5T{S*h44?@}|JjdOG;>gatv>O_@
ztTAt*@)`ih*qUW-g+tb>KZn~o<)iAakN5seZGZpH7=2`@7{jhj_f=a|^2DW?(-3=7
z-jw$OCs8rqMufDM-zw=J{(3axBl$OH&eF**#~n|=g0j0Go<&qr8+cY6mW^rL$!Ycf
z#MrPu*U-qp;jr=QNm~|#+Ev>84};ltCcG@nuR|-3*?G(}sF~p$=);&&#EU&Uw0sB!Fe=|8E{Oz@
zzgM$&8BlhDN6jsMq&~QJV03@>vG9jn$=SYAu`gGN9(4^_cil=7htRqWGW8*&PrRq+
zYTB*Megq6n%Oc1bmGe(Gl}r`_{qnxo=i5Hy*97QhpIO%zjh0v4vnIB>qBwa?xl)g|
zQT^H<`4fnQ+zM9#mzo$Q*^1hgpJw$l!g>xvNr=p1XQeHJ@@Pe3ORM@*_o%o)4pg6a
zM=)V*H4_tE0%YrdU2aXCnjt{$n20?pLsm3&78Hb1J{8t?({dsfXf8=t%n}LDt_E^D
z3C3F~tQ!x#6bXUAQOLBB%?;H@Un<|fb)J0|W89*5omV)O9v;3Pw{O>LI%((XNQmHU
zy8Q)Dx9+?D(=F(og*m-z&!WHRGX0&te)w*?<**)Gtu#<7W3h3?nmKXH%-*q5
zSRBcSwnb-nby$R@98ZU<$`L2_`D$umV|7|mZ?W{A>5t}_dxfd0Sw?RD{MTff2nkD@
zZ4VFhI($*NA?!7=5VyTmK)<5y{zf;W$QBVUrTuQ?eQi?He70sbsQX|wLwYYStj1jr
zeT#us5#H8V`h|`_N7J%7vnuSm8i7Ogk0`dTxb!WJSB
zD5$>ANmS%foj~4w(OuK7ncxH5ro2H8u9L>P;pZAY`eCV{C&Tu>N|6WGWc~MBdY5eY
zXV{F9keaZsWXstfD|Q>Nt1nNeKhY(AGQkCb9VqC>EX$UaN(zwc&_;LFdce~&ENkwzL^%^>8B^No;mz9ffWsG_{O{ceU
zhFMwHS(*L#Fs@}Ni7}@qBXaBP>JM+5j#jU=g}e`o{8yz&9hdPPuL=9_ANVR*wFKTL
zk*p(#5$0LKO6i`F3Uz)R8daC4l+a1Jc0!`H_{JfLU;Vd7J?2cmZM>Q}Fk(jR1Yp5(
z*aWJR@Ve3Jsc_mBPL1~{U?|+3JJ)`UFkABYHEZVYcimi&Rx4vr<^H
zT@+R;(6LC$fn23{fqP&{C(9Y3>qC}Q61&g(cX=L!HoG>49JzhmBg8t2C0wNxyG2`k
zx4UUml@&`^l0reMQk6yAlzy)!?th@3<_^GfrKIZ)O1T^R!c27OX&|p!d{ujJ&={Av
zY*kVXO~CRZ(>fk~`Ya0LPjV(|en+AjFQrI+yoANYqemq7j3lS*k1cZ~a0-(=pVH>)
zO{bBs46y{?c4=MRI|5?OBAoqFrQf_I7X|IwZxcnO4+pKGH&spJ;l?zjpjh
zy;p>9RI4+hNIK6Ol1oA!W9DsJwyfFB5}}KonffsZw~k`{`K1=)ekjhYA%|{d3Bxp
z)iRJEsCrV`;|k)Ifsx*XX#M^PcC*FvN5jV(j~N2q-`yX=#HwTepsuVc%uOrZ2wJeX
z#)8NYgv1_{v!^Kv=^EL8aGTs(&!7kALrey1T#91-|e!RVb{;^
z`OepLq-C(kEEI!$^i2VZqxhwZz*QK|Fc?@VZPX~6*sJZCRVk#vKBv|Ek`~oiE|aXp
z9YkWos@ZQobL*HpRcR^MdQ~%-81=Dp7%@%C8P$rMIs1eJS@e|
zV>mL%iOMoObu`J~nyyyP_UhW+9%a4mLdIc+OkV1HTa8AiIj+$=y_nnS;LfEONKNF`
zPP9`_P9P=VYzu|$4<2se3H4&Ds@ZV*2&w)9ViAu^X1kk1PbRF89N2Hy
zb=s>Av=g(d6)G>5s~mW3V1iC0O(g9kIeAn-k8DjkoMnIo_SV!X5Cvh+43y#;{D^C$
z$m_Ci46AIFu+#a=9@^6E@GwUDY;v+dub{De$?p-Na?;vj~#M^<;X;S95#M
z(ahu*0iQ)6064o$A#(4ij!@Jx-POfJgmZpkTPIAtwZ$_KZC<^=ZQ-~|BKvX$Wd{nG
z?7U0rnb$hlx-=A|e`r%RloGxjJLFCdVel!`vSJrV>(;ZWX@+Zrx9329j>Uw3rF4CA
zi$;`pwPD$?3_CZO~j
zsGmU{)09{`{`Rc!WT)$O5uVNc%OATrO<+QlTmhm08m{NAevoVG7}dAVq>P1@XTu;w
zaJulA)T@!%MGEE|aWR&?e$0!g@vgAtT9@2=<15zE1B=8lqYgWi6e$kHg^sP
zV>nwwc@L+b>?Nl{o_>k0ToOnZSTjUV<9D_{%+%ig`cpqUAQ+?k>k~fln*^!06l$Hm
ziik3`7{$;R4i8AyH)Bvp7!!hC%tU?yiNJq;enra2LzN#XCIMMZ-XteSG*XTqogCH0
z*2MF}9rQA}%p(z>pxvt%DF^aZr}oX)w#N(W#4`nFRU#TvI#u5YsRLB%
zs$}1;9vi=(T|+#ya5mHK6Jkmma}a^`K|{cGZ!rx^u+~ghGqDM#LIdqa9Iic;c>}Jy
zYk)-P_#Hsm`uHQe?6(bdyKD1|gex)4*GhH8b7|GS$1a}LcAYxBbgtdEW2)b7pZT8k
zyBV>w5IO#1`64)Pf(egGPF!wBPm|0;?$hJxf%q-v4h&iAK(gOJe^(6KI7yr~Wud_r
z4M4JEoj16){7dFVuge59XJUo;X#y<2c}EbGOXwe)c8zLiAYx*3tDBwgfckn3)#>XD
z9MCqZf7!`mQqvC%4_cNk4xdw$Y9B;4G9jj~{mpsPIw1GRAcqi;3i2GZ)#o
z#dZ~a{9jL{W#}0>P^70(>fVhW!Zxui<<-J^RKh@2mh#jB%Ygvwl`65NgZ!C`rE)M*_yc#&NdcBLqy%x!#imMH9`t0G>D
z>g&BNWEguNTu&G`MH+u)D?KKzT6^|WViAmHcgT)oVu^b)?_O0&ukU=4ZS3C^{mt5a
z<%jP%@WjD9fD%7zvqF*0KF!h5?gM@lu~yYEr>RE;mp3J7_%6pi7{NU&&N1^Ps~NEFqWr8}`3`@KiYmM26HEW7o_Fk84-0
zugOUHz3~nnuhFzroROcZ2@OBAUJ&BffqFJYMUKZ$+UeDHu70fTMc>m)%lTtcFH`ot
zd4}JcV&#*v>qEN04GRZsy-$)5z1+6B-LDROwo*-Qw_x~w-RSG2Yx#BN^LzcTy`GY0
z49g=;+cMO&>$VjY?1o6@6k>yQEj6=qEYNiKEj8PsMN=nFrsP1>Yh0P7WbWpH&_$Bg
z8x{!>VR(WX8^e}0wXZtqpkn(#bPz-FRyiI)7r5Nq#Zf6eS~2zA!Fo}WMLf5MY>_kV
z*r8%4WPN**DP#!e%Y7ApjqCTPsHr-l(NDdDkFw9OxjvpSJ}~9?K%1iLXC;#udng4x
zNHM%zcXt218ROX=ltI}wX+7TSF4M7!0gP@dZ%ucNhKIp{5Ukw#d*Ux*vaZA3Fz}$R
z*EW>j^qYoraTnzVPcr+Fu@}$p`*qW+)I-If;rchj45#G}O=xSL%d_H#CKap9z8M*h8&Xh#_UF!}`
zEMAdyyebm7{l>$r^iS=Um7Ps_dRORY@5rw0KiOq6Np#JDxV<8-srur#c2@jHvze@0
zn<4@bP%%Nm-qsY*O^7(Q(6NnhHEOBubrsvN5^TLJn=04mb*-Q<)D&Bop}XBLrB
z{xVE13QXZaQ8Nga)d{wWO6nHdO1m!spTsjd;XWms31)Qh3q~GAS{plIx%apxF>*z5~4?ZkAAb^qg)yLP;COrKQM7zPH^@|Apwg8c2WE8DFEgj2d{p4+i`2B-=
zi;N%MbqAq{&C6(CMIM$()R}i_$lR%t=R<6x#WYXbTWmAHbkIPUDuPaN$!7iKsAyU!
zRXJdWTB%rfRaZkPR8i=N9g&C8=r+Hlm;bT$_0@c
zLdmo@L@-oPviDa6p2^q8Q$~jS<%_$FX!&d}{n0RN&Sc|2Pb&6LKAQjNWsPPe?u0E~
ztm=b2Cf1KQs;;!5!@o=Pa2idfA~%Q+t9eZegH2wZsM+K(Vl`=}kw0grNu`2<6oDgd
z4gO&B6$DE}9D?m(Sjk)?Z(js!xq$vSmu5l<6GfofPWl=Wx*(BK8g7C_)9#N+ivKcB
zw2JZNHK;1&UT>PM(rX=Q30t!p@!sE(dL5j^NYb7FYeiWR^=Nr}Nvi116x>)S^*N9t
zjJ82@q?5b&|JcmhFmG8ctP6-T<>dA!sy291jodk&tDQ>wf!ITPPNhBf$s`g4IZ}X=
z36}YKyuaYkC8I8{NRt*@4Ivsj`dR_V+&CA=>5Z@WeRi~94jIebe%NFZKa@UG5f7W%
z=!2({ZE$@{yVx)zqfD=J{`v}}yEQ3U#oBm!z{ntKBSGFWcl(G61qUc~LC199BA4UR
zZ@Qw=p6le`9~;P~UBcritKzOS>;e&ib!R
z0jFxE$YeGVGJ5!DW)b6%+yH@aR1Y)Xr=)7D?zaZ84(pboRl!yQb-RgKX3j(C?uJJ3
zF4TfA<`Gr9L|dlwmeiA(VS*;7+Y1X1o!^;@(PbTDMmGz*DQwmC>rh!~l>euK^Khj4
z`~SGT_b8bc*SJLXURTz=)^)GFl4M-2tO$`=+-%pn_P$&**G}PMRwC|IT_d9iT`HtV
z-{1ZH59fVe@7H-g9#0a_<$UQMlbNbuiH_e&eT})w@6b~^)=w353+FUvHVqK8)$Vs%
zSsesfcSh6{-)Vl;Xn`0kPF{y6A)SHpbn)+chqqlD$5OaRx#8=%QF_x`{LeS8b=K+0
zd}ea<7W^Ut?r5nQaLibjTj>otIa8ra+EzjCW>`i}FF)BoJ3x}A`2daT`Kg{u_)ZB+
zJ8$oS0ex16tX$;m*TbgwjS>k^sC}Aa9g`f&@_Vg_FgW?mOvi46nl;GkP&RO|$1RZI
zkK+S$)2s9-l6I6SZGLTdg-T6Yrr0uYV?6oQY7*k157^&}2{cXDwu@zd>rWpVBd1x^EIqP8~Y9^{VSz|oy9Y9gMNx}
z$~XIxFPfFXu3>tv4?*mfcST7J`$jjIbB?WsYX%Al=fbTQ8)1A_C)k>c8H1|7PFHg_
z3z+;lxraP~vomKqDM)sJkbZ8BU?~Z5O!G*O*|+i>f7={XINQ~BE90xp5GgX`ph0GIyA3J-rS*F+aT?V3$aSm
zOGTRA*XA<=`89c@IVo+
zf@>Bl5*a5<7M2Ok=P4`Q!g;BNZE~-1wy^OmFwtz;3NGEU-#mn!BQ^=qZ+vn{!H{9p
z>$^teaW!drU@47L(mvD_T$viKW=}}O@clV?{)9=e&(zF6_(td6w_9qC*<;_v?AUDY
zn6Is&Q)3|R@cJ*2Y58U%!_Wms;QY0nqBA>|v8;epnBJy5Lz(*gkyEi56%?C<4}p~O
z)O0Tv#J~#BG4Vmc3Q}6pwTT~KjW4vgej$e4RTpT_efd5sHajNfUWR>#=tumGD19QlD2`T4q~3bj#{T48z=qEy7|o
zKMukF)@>3Z3M}KkC1{5a)-*Z2h(8Ms6Y80iyH<0yu`*Or9)^O!
z0dW%~nSqZ9)3NYbu2;=Q1a@z0+D479(1ONTc>P=EFQ;wzr&JhxB5RfkR&Avx}s~wl3a{oj2
zXEnK)9~w?xo}DZj#db`qSXLbJ>ec-x0?>F_WU?tAFb_x3WWWiAjGFm)=pE$Z@P#4_pk44rLs
zPR8I5Aru@q%H%tAKhq^Gom)k$^*C9Q0j2hEk&}(MEcBg>C^vvx0WThn_}zb6L-H*F{`ffA_1MeE+hDzR1Lj7;`5aZ<>rVY0RPyoL`A~a$giwcuxL-n
zY<2Zzpe#PDnMXAFvq+e{`W57hek*StXA=X<5n~(pyR8)+HcUE7_j9yn0$8O}Ytz6<
zBt3c13@p*eHKLl{AA7l@Uw_Q_M}m$<&E8J|eIm
zp^NSb-AY;+rg(AJR=ZQKhC++MrLx11{wtZii2})3={T*n{l^H9Y$9)Yr4L|US~$_SE;2zT#wu@wQZl@
zrQrnYGfM)(&D%6Yl-BiI*Ee{s*lZuUbiVxWo5NpS72PanBuPbEm~lI^cMrZ@2GwVZnCMWbue8P!
zv~?DLV?eh{a=-pKd{G#4A5;$~oL>`6nqEMh&O3
z#z5+M_3jDAw`O3jAnCF#!nya0BC*+USLeNI`-^u>y%{hUbfb-3U~d(np_?EtQ1;nr
zc_<%}gcBO8+JMbP;=CVXei!nNkKlDiz-P;DexOO*hJ9RZcr%jQtGGJSM^`@}q*VEwiH}+zOn0+!C_SS0pphY8SreuBddw;~`Kxlp`y)b$;`-K~KaZ-ZAnG`dy%yZp)`O
z#twn!lJX*%b?keJk7x|H20mv^(HK>on!dIPefzbAg_cmQs)N6p?J;zeQBb+`*OUuL
zQZfa@Q422gAZRc%?)pE;@0e2Nm-pO7;$9!Q5nx)ilPG2iR;0aeK_U$Wu`*>SI}$`R
zYV?Gii^D2kr)8cTc`;u2{HLr&&Tza2Sde@AbO_=p_W!6C|%&gZmPwxH435Hk)g+p>p6#Ihg(tFf_zglkem1r}{WpUqheNo?c
zdnZ&(!LLOzq*0X}0Gws+I=ygF8M*i0$d%XCtk89aUk1~=|4!IDDYl2DKac{B+B9hv
zG}G(M7s~;4h^SxXQTr}~HaMA}oYm#S6&qs3yK>^{o%=&m0?c&5cc_ZoKU`)vXDuPS
zp)Jz+{-xCZ?2bbmZ?DBevlz7QB37UL4Ac0c3H9!02&Twk4pDEiw5pe|M4>o;Pr0k$
z(jYv&r-#~U!T*mYoq|9@GavGBaQ(q2xGZKL-q!Q6it79iz*@yn9p>A%8rT+eert0a
zF<=G1^f8aHp3_?!j=^k^l=T@J!f3Z@NGM8Gf4}cXNE$v*pKbcSMb)S~4a6F4*O-t(4Li@xWh8g<
z-lvCrh?#ttVzFS8Adk1LXS2$u3v_{b@EG%a$aMgVhO1IdqH`kHxKT3*x2!;?&TGdn
zgy#_Y*W0qEPxA2As55Ao3jS*R_#Epo7>tYo-Q=ki{G{i5I$pd&>s%wL@0PjS6MFm(#njQ^Q{c!}?DvWwgav
zdQGebT&*)A_yorcX902McN4Fyb_cia7r(8QOZ+7DM5p6)@w$iS$+;4me?y7K^0rj=
zi8z*&Uf9
z+}Pydu5$4HycgQyNav4ilVG$%J7ic~z0Y7Vh%@6$NjD{IRycxwt&%8n@NH
z_BS^GKU~^M5>-4#4d(b!{bE*JSrxo<>?DGql99|aOCH3v8a6I1$0xLG5Hh$4Q{`XU
zCFNTR&dgC@MzA#{Sqhxkyc1!@2;^~D3V!$}jGQrIRa9W%0qaOmZb75G+a~8~Lf?%#
zU4w~6w~xFk`fa*+CHspwEa5?$3!MC|&zt&(4bR9QO_pdWJnL|1)kAs1U5pS(55%{6
zu;=SqZ+|QN94G^D*|!H!WA`z9P2(pg6wn$@?!Yl&=E!UAM|eb?4MizD&cI}WMf9!ORsl%d65p0
zL%wbKNX+lYo>8rkU-Z4c3kz1vZxUZ%Zra~Q!rV4ESSaR7q~6(IGYy0BK_DTr?48~K
z&1T1u4oQ^;=)i{4YZsnhpK%3r`j^PwrLo3#KC92d{83+75ovFzP9=LWBx{PpSq>55
zxnpI7QTk&XiR~b?$Z3#l0iD7@JJisV)=R8!CPG>Q+P4xpx=n6IrORj7^4!kj0s8oN
zdpR@~S0`?QepaiX-_}bRwg}Y3BiPP>Wm~mzEDVltb9vde6Lus!H;xn<$^FCz!l-T@S+(_NOH)lG6s
zb}Ns`8GmkLgdINciB;yCR8el^8>2ra@-Y2)Z2dhdE%?xRYEo3x1-2)Si??3jZ)SMJ
zA3DC_OlKRF`}qBG3DzThcTv<&P}w(;5ZQ2ww?6acOeqiq+$fO4_E5jzkl^CElDu>!
zU~3q26SBnN)Tlhj556=v7*;CDD&xpU#mfH5E-O_a(itij_&B0Z+pNzI2@)eWI#(YD(&k!6IOw&1#Muj^qJK11
z1(Wtq?>l3Qd=d%p<&SJuc?#nmcjb^)tGc*DFIpfScVLYkc@ggvnpKLPSk<6^3TNPX
z(3-Ph--%38;FNkB^ti}?hyz*#7NxF;LLh1!$5=`=+fajAA2d$@ZgMR8K7N3hO{#a{
zs??QPz%=R?Z3B*n!wg$OKG?1$g{~n7ZYj65wXoz*`37MBJ9X+l*5Qk30vGO`wFzEW
zIKvr4NePCDk2nLW)ZMdnA^Lm~QnXcyH~j=Y8qvc2%o@t1NBFv<|E--2qrwRCKJtpm
zb_p>h+@O^wnBzi5OPv;__T@h`HJ8#9<96}xJ?8cPt1(xvdw2jc6}@eC(Sogmw*%AF
z#cmcdc?4&w{V~#
zL7r=X@cT(bm<2~3?e_V?8LIrz*Z?cMfDHCt)Rs8i%4Bbl%naW&7^CZn%ig@9Qn
zl|R*4*u4NCy7cOj(`mpR9S+v)XH)vcujc>kwSGU9(EQ!{lqa@n2jm52WnM1jLYhQ6
zD=ov@xR-kqZnShPZ%WaD#{lma61a)iJ%dn>#2`aHvF@%w#cxaj>wV7WKR>uCKYnP*
zfB_bC)>`r8Q*OqkgbKrx9dGE`Ku*u8ygbTVb`ofHsP6^DJeJ)AM5UWgD<0axEqd*JPp;{8gUwDd-i)D$>j!V&|+=LEtN^%)CI&ZiMm!`&tz1Y4*F)mU~rq^&KB$l7-ZbPRn0DxEfQ_
zDhJ?_H>#te5bX+>)IF1Xo~tk2nk0J&cybf#dJ=<;lO>kbf!%Vw=C8skj5DSFgHwzM
zT(B1c`h~+tVIMSfx^%A(>xmSK`aVa{aeuK@paohk;$PGoEXU(8&hWJPkpQg9Rl`i&
zm6g_zwk%tCByb1IfT(cr4O|{VLj7Yh(GW?*0m1n=BuuMUY3i{X-bM
zzqN-Et&ufPF>f>q|}ky*L*
zZF%>niCc1-0Y8+qqH%|7Nl50y$BQX7)z|$Nrf-EWKYRz6NTp`|i1O#$vfzy?u
zqE^~%8ZHI7v72{6a;al;Ozy^9DRqt=5QaJS;RF!8+(v+RAX8m~-sLKTNw{1zT)<}G
zOqnQT9cnlT*jR|i7m&sa2#3&T@NPwxuFS(I#J~
z6?xYdAHgBv9^n?cm##&4Bp@o`E_fe#09E630!d+gT=1k7)A;QVY{;oiprc1P{ZGUF
zs|A>5DMo)yIle~dqvE7m{c1QQ$%Z(ula#K(L|x0$44AeBW;%I-$7Cz`%bKTrn|#u6
zd^+_*@!wa1A>_I?w!KPTVyN1*2R}sz|B^ALB!fs^giDw
zwxI63l1p{E(I(0brsJoQK!vvb>mRMtL{T)Cw!C^^l%%&*bpBAn{xji0>qB`Uh=Bjk
zth5N+EYh4l2oos)Oy54T_ucy3NBEtt22G2>UkQ#7NM{7;$0+iPzg*0etlL`jgrsM+
z$cYm-L$~7>8k?kO0ch^%q)%ALu9P&kuF))?Fb{|bj6aOU2xdRG4LA)R>G;hkJ)b0v
zonO~$T3z2cskLNd8?BA2Ja=JHIBp)i{3>?P=vO&Ww*7t`_i0!XB%O02MqO50f%f8Ew$Y}IJkJiv{^=AT&smwOeTGPNalAJ4ViChfg
zs;0}mbU1YlMcB{>GLh>JAf~OUJ+7#&fSeLgI7veaMZ=>jXLkb)VC)woV{(6z59JeH
zf35-XPnkI}A70rYn@e*RJa>q{l5}kX?%huZZf)c3lWn#-YlQK_hH{lb8;@Q$Pz&&W
zSCK3>X&Oj!JYY@UouU8HWHB>go4Xl^%AQSXkXm8)wq)6~@(MFkPw~asp{PLVK*s>eTuifUYMri5Dq-Yio54u6X
zj!9wusqJ3`d8L`LnPBAv>etjssJ^8|_TF!#5sZR+Pm-ppgahsr^|;$msG
zjJuO$x%~W_nYa{gRUU$E`fI09SZ8Z$5&Yo3O8or#$nQV-hAl7Dh~ajibv4t?JS*Yb$^zBz20-?Tt2KP(&&XiY<8M9Z?FUb4&6K7}N7|_c;+H|!P-en^D
ztpBXVeR(9E&E1zXK>5hAP5z4-Biq0ryugg4IXG;fP%)$6%J$}+esC1P#_5;4NQ@%g
z^R7GCjJ$BCP=~*>qHwL9Zx-fu=sSf2-0s<5Vq431;z^bRJ1x2nSffRbzoh$*XEW9oRm4cflj2tIH|oqP|iK89)A!Lx>I)k!j>cd(a5K`u$rYmsUx
zYF>Ixy+S$uC#S#4!@W4z#s#%e^dWA
zCHG|Be$_av-4b>WIU^!spk*jcHJ9#^+oRfbSDJs-7EgU?m16FE-%nh&Se|ofTRU(k
zTmFEV!fM4ue68%e-&99>df?-{lmn5ZSHjRE<+r0wiYu4No(GOy5wG@48W{3eQq`Rn
zHcjA`O!7ze`*wW>+5+tbTDz%pQAQOciWd~#NV5Su2Hl#w#4f7e4^b8%FUd30*za0W
zl(E+(Z8^tu7-nULKtXS)Q#&wE~P$_-kk?Tdf<3I`Rs)-zyJ3eYR!@xYxN+kE}SKGhF
zX!s`JO#QS*+rBU_9@{dA)YR9yD8d5%gII|mutSR`v$`z}$2OjrbEmuZ?J784ei(?&
zw4dVw-glB~j||f{&wGWMaqV!%BwH`5G-HFcxvM@a9og>~W)RTjFjA|Dd#
zdfO8ie=(0-QyCYsvKn_N?0Yt1THg`ezQ@rbOD3kT?$DL|&8}{MNI>u1I_%$bB1`gw
z78mmus922|H^e(jbPx)vDi(>wM2v=@K?Jy(Jov;l>VkdY!^=K6X4|axhY-zY%LC8N
zUzl|8bi3kJ#k=|@qZ-y$B+@B}PkLcbi2
zwH|SM-T1)#6Q{m9VVA+TWqn^_8a~EmF;|m3hUFN(d}?J~Yc}JuYZL4Of%XsB@X=H_
z>9>1=xIor#*J*0qAJ=Ku#wVYun`nwq;m!cV2LIHd^bB2Z4p5de-c{9ZA5jt|5Yy!
ziM6*1-9wrr=}-i;TkdNSDpe2a=!j|mqhW!FV8ZyM-=ihoVej-gd#nE(E?M?U2qqd&
z=o!^f4akc+_^o>rI$(6sdR;&4^Z9%`>kx^q5|Qj+P=<4837v5O#NeukjtvF&i><>^
z{U$u&FqwXV_RkyGt|fU>zh;d;{AuqqRSTj1vCWbe4dgnb-fwaOle`*>endqfbY?{1
z#A2PJzp8CG+#laIvr`*2KVot+Hs_?S`E9x!`#cGCM59w^(e4DA5a)loykY*0PCk1LVgzT;VYwxm}$Wtf6}m0Hi~@!
z`Y?%x@54N+kU)I1hSPAw+T=JZzrM3n_*}3TRO#dQ(PNWQ9nl3P+s{zA04=Ccx8~l1
z^Yq22*CC*v>`&?cVU3AD{=Bzbi0acg0IG(5O2f#~(4&VVw%pBTjeg{xv}x7Yb(6B)
zlAP}O(jNi?BHpAm?=zS0n}@Vxl?Y}0^t=`3e!X9g4p1^8rUk{fW}F|`dJ~(LPdw#5
zyOMER)M~=slHbNo_&c^t*y!GMeMN_Eb$k*hF-HUVQdyen&wpopy
zERFb|+6rkbxO2?w)M#s2gH!aE-0oWH?lfyD-YSpTbtq>n0*jxrFTdpgXX5h4`!_@#
zYg4-O5!xY10JM{g{HVrw+h`NTp_3uyK?|IJ0-h?=89Jwe*C2cA;))X#q!siNf?uU&
z*Ym=z7p~X3EY-bH(Ip`Lg9-woOc6cR>h
zrVMj*caJ-sPZb3>eUK%wFh|%wPRquLcNyP^0~8nC_RmYod;TYB+xW=hgj1+9_~6wt
z&3v;_QD@g(7K_g*ZQ=cwt;NI9N*~~u8rHE?%H*BUP_OT+4@13A8TzV^6?y;l;=fjM
zf6o>vuk#!VD`*56EO$f5Wx4XaZilVJ{JZ`KIr0=!HVktO-y>xG_n(tfCzH2cQgMIp
zfl$#232pjsr4q=c5mpPEfYxk#Rzl^#_$=c_?+-(W
zdbek+w69D*m@);oy&$A{djydSn7=R2r#VTy(U*9evVY|nIq7q>V0l8`hMGX^1Wd_$
z{uR`O$539xM~2b`wbw9DYYyRsgD__463C_t{meJmhHc(yK_O^izBj8;w+)EK4~wkv
z6V8FCd(#va!hr$Uhyq`vy1|?G4f$A8dnA%ng;aw$a$L9+u^v^sr$gni>6V(pb7q!d
zNX^tem;{!Jp(x?Vfw1hl7Dio=
z_@YZUd>>KFP#;k5JqI1s0Kk02UNnAa7)s1uar&fs(%x7o&M&FRW0H|Pee}oiP(cXL
zE+;*>E
zEO|DJa=sB%y4nLiE_N
zHF-S#o1QGWBJPU8(!fan8gg!S)G&!MTxM-CrV&v7rqgN
z6DarpXqN4nSE>>Mm2t1y#lQD6)Bk7x}#k=}Fi1QgH+(k-f^({GAnW-83J1BGNq2*N>DGiVq9&W{d~
z1<5jMbfPRE4q|(+(_-e^UEmEwzjK8Bh{XWzH*Qs@^%#4~OF+eFn?&>qQ^z=)#=D@V
zmWJlvIZA4*+oJDp_4g{8+}2O=37vC~O@EMy0?_~`xIP>mSw!Jsuhj@*)2SLx&)R@x
zLizK{t--k>D5YtR)Mre(vfY=){$Ec2@kBF18)D8no;I&EK8{X%!}VXUy9-Tn=_LH+
zL&>@@0n5bGqOTUVr>DOL_5en^kH`K;^S2=UPnmJt3JoSxyqWi`*1cy!g8+E-qUgzp
zN6WsK7Izuggim){qBqz@vP(MmdOpR?sNP5Kzib?Y>|>$7)1xHWeh=!D{R-ABBElW3
zN=*zWW31&Mr1BqayT9%7VgQ#37OLyDMDi6%@>b)H(@%pupUVVJ|6V^v8OTXnbVKPw
zU=FAEGoI{bohHvd_+3@w5l2rRlRRW$i@f^5oCQ@kSg&>Oo?kDuIjfHICZ?zhRIL-9
z@Y^ahRky2JV*M9;=*62VBs)utdf7+@=xnnoP=iGf+JFev829sYwBr{g!r~X54>o`0
zgdTZ>Tgj;B_G_*W#l8Q2UavJ=@Zkp-K*uV=U~@b#xZHOAmx?FoxRqOX`#s@Upl|ur
zjkZGdd}?v>Q;$Br8k1w*iZBJT8>>N%YL%Lz_WNLXs&J%7LH{ysGC3=1r*y5o(Az}N
zBCoP0NyaGO!QdH}v3y&Jmv;-Ed(5LPQQ=1-n^q}6qVzIdd?BQ~XX#^q5aIEP-9kQD
z)y3Np@F!paP2Z}!S62<2w4
zzF$jyr2l?(pETg-r{(TWHLpQupq;`2Cr(R1hl$e=b;zTZpiqZpG?M`cZQ(ti0Ww5k
z@5=yHBx>dAn
z@?iZ`1bu>YZbJyZebB_uOsWG(P~zz^o4(x-?5OhyOXMzKo^*@B+~@h7SHRk&zKB@1%1*F43VdsO06q);`9pF
zN_4~i{YUY@n0g3J_)H^HHXr@xP)gn37n6}(ExSqO*F-|s2_^rwOBHoZ;B6^pM^O96g&Y61h`~$VZxFOT1i2dm|9SXESf2$%tQ()0DE|4iq
z@fEEsw5jI)csQ(3PNQfm9wA_|J7UsPf#9+WYPy3(<|5M<{XsOU-ubs~|GlD)5%$xC!R(+IfPV_Q@hXtxTa%`wE~WmLt_nVyeAXhNC0G%NPkAaUO4
z%Owx%9g%*vx4VLAxyvK(u)a}iVtu3?PeCPwT3tjU)fP2yL`dlvkPN|#yr*rH?WZ>i
zbm;8#okgf`9mH>|Vr$!3&eL|W?ENNIuq`eQEWWjL)rnR84b@5Mc!n`3N-v#0*mJ8i
zod0jNy;rPeB4Ax%r}Y`-nPYVsQ$qa0>+*%Ij3{mmKQwLop3-xHZEqLuFn#B!RjS{3
z#hY
zQ1DorUz6|cA+t~?O@~P{FP)=lVlUq+%E0e@iTxE|OF`{ftmZZT$p`crY1HOeT!phP
zj@DrA0S+4w7xHIc=C0GX7=Z$Pwu_gWm#OZLz-o@sufb4*ncUNwk~i%MJWFXI9x=BO
z18+d#I%ntuVFfykWtfpk62ELf1*tIuSa>prcrkqQ%7KgBo%`EVCzV{%v;M%UXS)BKN(PA7cD8Ly54&
z%*zA+1yiO83UBTrwh+cWIGMY9uh>8;?G=W>wD2-M+zn-;#0@gND=oL!
z_F-fYr?6U3#mPj(5OkmrxFxbVAZGBZ`*$-oe2Yvo65~>}gzwI6PZWOu
zhdX>)NDK#`Um06&GnR~GGs3}zR^qdh!&LK*W
z!Su}^tBVDZ;dEw!ngV#F*aUX$^yc)BSJp+-I6q1KUMm^s2HBvrEo=rFZnBllPK#EPIFe
zeQ>7C>OA_4Nr(Qxy{TjbETx*63}4m%B3C)Ejcwc>@AtP;ooNg3Tph#(N9*wkSjR7g
zM+!00%S&AL{A#zwMr-h8*D?553Sr|`e^THVymMU72OLqdw6m#mtixd?99db(n$<7v
zE4UNw9}3B7X6(Cg=hP3!{7`#vspwR*D)>`2FEeMxc+ydY=_~8sq-1KF&Ir6jxW=@vQHL`b2>;Kv%3@>>O
zqD_NF=tCT>=cj|f4B(lqgV
z>k1S~$)SCJPih+YS0>NJnJ4DuS(MXS&^@?tW(J!$?KGw4ZzUeP-%FQ!1m1gVYML7F
z$F=xqxnZ9f>b&h^>R1L4YTWxQgXiXz2J$3)?QPwpS{5P?aHq_UMR`WmpLU%p!fgRy
z*~r3g!MyK6@o=K1q1!iu;og4M4H-6htG`bUJp6JuHzr8>%>pS_r>qyk5^?)^m3vc5
z$-ipemnfjpP4e=SjZV0Jj1vykfHw55>p1u4jyNGTMzOs!XVgNA6o-kbc}E4j!0(r4
z8L`44_GVI*y!ki=0-R%cc^_ukZt@y0sZfDSLUNjo(y&Z24a@*YS2MZHwpxv%%f$AF
zDm{;F5l>H>exs!|KJhx(BG4Mi=AKK
+ * MIT
+ *
+ * https://github.com/gregjacobs/Autolinker.js
+ */
+!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Autolinker=b()}):"object"==typeof exports?module.exports=b():a.Autolinker=b()}(this,function(){var a=function(a){a=a||{},this.urls=this.normalizeUrlsCfg(a.urls),this.email="boolean"==typeof a.email?a.email:!0,this.twitter="boolean"==typeof a.twitter?a.twitter:!0,this.phone="boolean"==typeof a.phone?a.phone:!0,this.hashtag=a.hashtag||!1,this.newWindow="boolean"==typeof a.newWindow?a.newWindow:!0,this.stripPrefix="boolean"==typeof a.stripPrefix?a.stripPrefix:!0;var b=this.hashtag;if(b!==!1&&"twitter"!==b&&"facebook"!==b&&"instagram"!==b)throw new Error("invalid `hashtag` cfg - see docs");this.truncate=this.normalizeTruncateCfg(a.truncate),this.className=a.className||"",this.replaceFn=a.replaceFn||null,this.htmlParser=null,this.matchers=null,this.tagBuilder=null};return a.prototype={constructor:a,normalizeUrlsCfg:function(a){return null==a&&(a=!0),"boolean"==typeof a?{schemeMatches:a,wwwMatches:a,tldMatches:a}:{schemeMatches:"boolean"==typeof a.schemeMatches?a.schemeMatches:!0,wwwMatches:"boolean"==typeof a.wwwMatches?a.wwwMatches:!0,tldMatches:"boolean"==typeof a.tldMatches?a.tldMatches:!0}},normalizeTruncateCfg:function(b){return"number"==typeof b?{length:b,location:"end"}:a.Util.defaults(b||{},{length:Number.POSITIVE_INFINITY,location:"end"})},parse:function(a){for(var b=this.getHtmlParser(),c=b.parse(a),d=0,e=[],f=0,g=c.length;g>f;f++){var h=c[f],i=h.getType();if("element"===i&&"a"===h.getTagName())h.isClosing()?d=Math.max(d-1,0):d++;else if("text"===i&&0===d){var j=this.parseText(h.getText(),h.getOffset());e.push.apply(e,j)}}return e=this.compactMatches(e),this.hashtag||(e=e.filter(function(a){return"hashtag"!==a.getType()})),this.email||(e=e.filter(function(a){return"email"!==a.getType()})),this.phone||(e=e.filter(function(a){return"phone"!==a.getType()})),this.twitter||(e=e.filter(function(a){return"twitter"!==a.getType()})),this.urls.schemeMatches||(e=e.filter(function(a){return"url"!==a.getType()||"scheme"!==a.getUrlMatchType()})),this.urls.wwwMatches||(e=e.filter(function(a){return"url"!==a.getType()||"www"!==a.getUrlMatchType()})),this.urls.tldMatches||(e=e.filter(function(a){return"url"!==a.getType()||"tld"!==a.getUrlMatchType()})),e},compactMatches:function(a){a.sort(function(a,b){return a.getOffset()-b.getOffset()});for(var b=0;be;e++){for(var g=c[e].parseMatches(a),h=0,i=g.length;i>h;h++)g[h].setOffset(b+g[h].getOffset());d.push.apply(d,g)}return d},link:function(a){if(!a)return"";for(var b=this.parse(a),c=[],d=0,e=0,f=b.length;f>e;e++){var g=b[e];c.push(a.substring(d,g.getOffset())),c.push(this.createMatchReturnVal(g)),d=g.getOffset()+g.getMatchedText().length}return c.push(a.substring(d)),c.join("")},createMatchReturnVal:function(b){var c;if(this.replaceFn&&(c=this.replaceFn.call(this,this,b)),"string"==typeof c)return c;if(c===!1)return b.getMatchedText();if(c instanceof a.HtmlTag)return c.toAnchorString();var d=this.getTagBuilder(),e=d.build(b);return e.toAnchorString()},getHtmlParser:function(){var b=this.htmlParser;return b||(b=this.htmlParser=new a.htmlParser.HtmlParser),b},getMatchers:function(){if(this.matchers)return this.matchers;var b=a.matcher,c=[new b.Hashtag({serviceName:this.hashtag}),new b.Email,new b.Phone,new b.Twitter,new b.Url({stripPrefix:this.stripPrefix})];return this.matchers=c},getTagBuilder:function(){var b=this.tagBuilder;return b||(b=this.tagBuilder=new a.AnchorTagBuilder({newWindow:this.newWindow,truncate:this.truncate,className:this.className})),b}},a.link=function(b,c){var d=new a(c);return d.link(b)},a.match={},a.matcher={},a.htmlParser={},a.truncate={},a.Util={abstractMethod:function(){throw"abstract"},trimRegex:/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,assign:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},defaults:function(a,b){for(var c in b)b.hasOwnProperty(c)&&void 0===a[c]&&(a[c]=b[c]);return a},extend:function(b,c){var d=b.prototype,e=function(){};e.prototype=d;var f;f=c.hasOwnProperty("constructor")?c.constructor:function(){d.constructor.apply(this,arguments)};var g=f.prototype=new e;return g.constructor=f,g.superclass=d,delete c.constructor,a.Util.assign(g,c),f},ellipsis:function(a,b,c){return a.length>b&&(c=null==c?"..":c,a=a.substring(0,b-c.length)+c),a},indexOf:function(a,b){if(Array.prototype.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},splitAndCapture:function(a,b){if(!b.global)throw new Error("`splitRegex` must have the 'g' flag set");for(var c,d=[],e=0;c=b.exec(a);)d.push(a.substring(e,c.index)),d.push(c[0]),e=c.index+c[0].length;return d.push(a.substring(e)),d},trim:function(a){return a.replace(this.trimRegex,"")}},a.HtmlTag=a.Util.extend(Object,{whitespaceRegex:/\s+/,constructor:function(b){a.Util.assign(this,b),this.innerHtml=this.innerHtml||this.innerHTML},setTagName:function(a){return this.tagName=a,this},getTagName:function(){return this.tagName||""},setAttr:function(a,b){var c=this.getAttrs();return c[a]=b,this},getAttr:function(a){return this.getAttrs()[a]},setAttrs:function(b){var c=this.getAttrs();return a.Util.assign(c,b),this},getAttrs:function(){return this.attrs||(this.attrs={})},setClass:function(a){return this.setAttr("class",a)},addClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);c=h.shift();)-1===f(g,c)&&g.push(c);return this.getAttrs()["class"]=g.join(" "),this},removeClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);g.length&&(c=h.shift());){var i=f(g,c);-1!==i&&g.splice(i,1)}return this.getAttrs()["class"]=g.join(" "),this},getClass:function(){return this.getAttrs()["class"]||""},hasClass:function(a){return-1!==(" "+this.getClass()+" ").indexOf(" "+a+" ")},setInnerHtml:function(a){return this.innerHtml=a,this},getInnerHtml:function(){return this.innerHtml||""},toAnchorString:function(){var a=this.getTagName(),b=this.buildAttrsStr();return b=b?" "+b:"",["<",a,b,">",this.getInnerHtml(),""].join("")},buildAttrsStr:function(){if(!this.attrs)return"";var a=this.getAttrs(),b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c+'="'+a[c]+'"');return b.join(" ")}}),a.RegexLib=function(){var a="A-Za-zªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢴऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡૹଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘ-ౚౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎↃↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々〆〱-〵〻〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ",b="0-9٠-٩۰-۹߀-߉०-९০-৯੦-੯૦-૯୦-୯௦-௯౦-౯೦-೯൦-൯෦-෯๐-๙໐-໙༠-༩၀-၉႐-႙០-៩᠐-᠙᥆-᥏᧐-᧙᪀-᪉᪐-᪙᭐-᭙᮰-᮹᱀-᱉᱐-᱙꘠-꘩꣐-꣙꤀-꤉꧐-꧙꧰-꧹꩐-꩙꯰-꯹0-9",c=a+b,d=new RegExp("["+c+".\\-]*["+c+"\\-]"),e=/(?:international|construction|contractors|enterprises|photography|productions|foundation|immobilien|industries|management|properties|technology|christmas|community|directory|education|equipment|institute|marketing|solutions|vacations|bargains|boutique|builders|catering|cleaning|clothing|computer|democrat|diamonds|graphics|holdings|lighting|partners|plumbing|supplies|training|ventures|academy|careers|company|cruises|domains|exposed|flights|florist|gallery|guitars|holiday|kitchen|neustar|okinawa|recipes|rentals|reviews|shiksha|singles|support|systems|agency|berlin|camera|center|coffee|condos|dating|estate|events|expert|futbol|kaufen|luxury|maison|monash|museum|nagoya|photos|repair|report|social|supply|tattoo|tienda|travel|viajes|villas|vision|voting|voyage|actor|build|cards|cheap|codes|dance|email|glass|house|mango|ninja|parts|photo|press|shoes|solar|today|tokyo|tools|watch|works|aero|arpa|asia|best|bike|blue|buzz|camp|club|cool|coop|farm|fish|gift|guru|info|jobs|kiwi|kred|land|limo|link|menu|mobi|moda|name|pics|pink|post|qpon|rich|ruhr|sexy|tips|vote|voto|wang|wien|wiki|zone|bar|bid|biz|cab|cat|ceo|com|edu|gov|int|kim|mil|net|onl|org|pro|pub|red|tel|uno|wed|xxx|xyz|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)\b/;return{alphaNumericCharsStr:c,domainNameRegex:d,tldRegex:e}}(),a.AnchorTagBuilder=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},build:function(b){return new a.HtmlTag({tagName:"a",attrs:this.createAttrs(b.getType(),b.getAnchorHref()),innerHtml:this.processAnchorText(b.getAnchorText())})},createAttrs:function(a,b){var c={href:b},d=this.createCssClass(a);return d&&(c["class"]=d),this.newWindow&&(c.target="_blank"),c},createCssClass:function(a){var b=this.className;return b?b+" "+b+"-"+a:""},processAnchorText:function(a){return a=this.doTruncate(a)},doTruncate:function(b){var c=this.truncate;if(!c)return b;var d=c.length,e=c.location;return"smart"===e?a.truncate.TruncateSmart(b,d,".."):"middle"===e?a.truncate.TruncateMiddle(b,d,".."):a.truncate.TruncateEnd(b,d,"..")}}),a.htmlParser.HtmlParser=a.Util.extend(Object,{htmlRegex:function(){var a=/!--([\s\S]+?)--/,b=/[0-9a-zA-Z][0-9a-zA-Z:]*/,c=/[^\s\0"'>\/=\x01-\x1F\x7F]+/,d=/(?:"[^"]*?"|'[^']*?'|[^'"=<>`\s]+)/,e=c.source+"(?:\\s*=\\s*"+d.source+")?";return new RegExp(["(?:","<(!DOCTYPE)","(?:","\\s+","(?:",e,"|",d.source+")",")*",">",")","|","(?:","<(/)?","(?:",a.source,"|","(?:","("+b.source+")","(?:","\\s+",e,")*","\\s*/?",")",")",">",")"].join(""),"gi")}(),htmlCharacterEntitiesRegex:/( | |<|<|>|>|"|"|')/gi,parse:function(a){for(var b,c,d=this.htmlRegex,e=0,f=[];null!==(b=d.exec(a));){var g=b[0],h=b[3],i=b[1]||b[4],j=!!b[2],k=b.index,l=a.substring(e,k);l&&(c=this.parseTextAndEntityNodes(e,l),f.push.apply(f,c)),f.push(h?this.createCommentNode(k,g,h):this.createElementNode(k,g,i,j)),e=k+g.length}if(ef;f+=2){var h=e[f],i=e[f+1];h&&(d.push(this.createTextNode(b,h)),b+=h.length),i&&(d.push(this.createEntityNode(b,i)),b+=i.length)}return d},createCommentNode:function(b,c,d){return new a.htmlParser.CommentNode({offset:b,text:c,comment:a.Util.trim(d)})},createElementNode:function(b,c,d,e){return new a.htmlParser.ElementNode({offset:b,text:c,tagName:d.toLowerCase(),closing:e})},createEntityNode:function(b,c){return new a.htmlParser.EntityNode({offset:b,text:c})},createTextNode:function(b,c){return new a.htmlParser.TextNode({offset:b,text:c})}}),a.htmlParser.HtmlNode=a.Util.extend(Object,{offset:void 0,text:void 0,constructor:function(b){if(a.Util.assign(this,b),null==this.offset)throw new Error("`offset` cfg required");if(null==this.text)throw new Error("`text` cfg required")},getType:a.Util.abstractMethod,getOffset:function(){return this.offset},getText:function(){return this.text}}),a.htmlParser.CommentNode=a.Util.extend(a.htmlParser.HtmlNode,{comment:"",getType:function(){return"comment"},getComment:function(){return this.comment}}),a.htmlParser.ElementNode=a.Util.extend(a.htmlParser.HtmlNode,{tagName:"",closing:!1,getType:function(){return"element"},getTagName:function(){return this.tagName},isClosing:function(){return this.closing}}),a.htmlParser.EntityNode=a.Util.extend(a.htmlParser.HtmlNode,{getType:function(){return"entity"}}),a.htmlParser.TextNode=a.Util.extend(a.htmlParser.HtmlNode,{getType:function(){return"text"}}),a.match.Match=a.Util.extend(Object,{constructor:function(a,b){if(null==a)throw new Error("`matchedText` arg required");if(null==b)throw new Error("`offset` arg required");this.matchedText=a,this.offset=b},getType:a.Util.abstractMethod,getMatchedText:function(){return this.matchedText},setOffset:function(a){this.offset=a},getOffset:function(){return this.offset},getAnchorHref:a.Util.abstractMethod,getAnchorText:a.Util.abstractMethod}),a.match.Email=a.Util.extend(a.match.Match,{constructor:function(b,c,d){if(a.match.Match.prototype.constructor.call(this,b,c),!d)throw new Error("`email` arg required");this.email=d},getType:function(){return"email"},getEmail:function(){return this.email},getAnchorHref:function(){return"mailto:"+this.email},getAnchorText:function(){return this.email}}),a.match.Hashtag=a.Util.extend(a.match.Match,{constructor:function(b,c,d,e){if(a.match.Match.prototype.constructor.call(this,b,c),!e)throw new Error("`hashtag` arg required");this.serviceName=d,this.hashtag=e},getType:function(){return"hashtag"},getServiceName:function(){return this.serviceName},getHashtag:function(){return this.hashtag},getAnchorHref:function(){var a=this.serviceName,b=this.hashtag;switch(a){case"twitter":return"https://twitter.com/hashtag/"+b;case"facebook":return"https://www.facebook.com/hashtag/"+b;case"instagram":return"https://instagram.com/explore/tags/"+b;default:throw new Error("Unknown service name to point hashtag to: ",a)}},getAnchorText:function(){return"#"+this.hashtag}}),a.match.Phone=a.Util.extend(a.match.Match,{constructor:function(b,c,d,e){if(a.match.Match.prototype.constructor.call(this,b,c),!d)throw new Error("`number` arg required");if(null==e)throw new Error("`plusSign` arg required");this.number=d,this.plusSign=e},getType:function(){return"phone"},getNumber:function(){return this.number},getAnchorHref:function(){return"tel:"+(this.plusSign?"+":"")+this.number},getAnchorText:function(){return this.matchedText}}),a.match.Twitter=a.Util.extend(a.match.Match,{constructor:function(b,c,d){if(a.match.Match.prototype.constructor.call(this,b,c),!d)throw new Error("`twitterHandle` arg required");this.twitterHandle=d},getType:function(){return"twitter"},getTwitterHandle:function(){return this.twitterHandle},getAnchorHref:function(){return"https://twitter.com/"+this.twitterHandle},getAnchorText:function(){return"@"+this.twitterHandle}}),a.match.Url=a.Util.extend(a.match.Match,{constructor:function(b,c,d,e,f,g,h){if(a.match.Match.prototype.constructor.call(this,b,c),"scheme"!==e&&"www"!==e&&"tld"!==e)throw new Error('`urlMatchType` must be one of: "scheme", "www", or "tld"');if(!d)throw new Error("`url` arg required");if(null==f)throw new Error("`protocolUrlMatch` arg required");if(null==g)throw new Error("`protocolRelativeMatch` arg required");if(null==h)throw new Error("`stripPrefix` arg required");this.urlMatchType=e,this.url=d,this.protocolUrlMatch=f,this.protocolRelativeMatch=g,this.stripPrefix=h},urlPrefixRegex:/^(https?:\/\/)?(www\.)?/i,protocolRelativeRegex:/^\/\//,protocolPrepended:!1,getType:function(){return"url"},getUrlMatchType:function(){return this.urlMatchType},getUrl:function(){var a=this.url;return this.protocolRelativeMatch||this.protocolUrlMatch||this.protocolPrepended||(a=this.url="http://"+a,this.protocolPrepended=!0),a},getAnchorHref:function(){var a=this.getUrl();return a.replace(/&/g,"&")},getAnchorText:function(){var a=this.getMatchedText();return this.protocolRelativeMatch&&(a=this.stripProtocolRelativePrefix(a)),this.stripPrefix&&(a=this.stripUrlPrefix(a)),a=this.removeTrailingSlash(a)},stripUrlPrefix:function(a){return a.replace(this.urlPrefixRegex,"")},stripProtocolRelativePrefix:function(a){return a.replace(this.protocolRelativeRegex,"")},removeTrailingSlash:function(a){return"/"===a.charAt(a.length-1)&&(a=a.slice(0,-1)),a}}),a.matcher.Matcher=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},parseMatches:a.Util.abstractMethod}),a.matcher.Email=a.Util.extend(a.matcher.Matcher,{matcherRegex:function(){var b=a.RegexLib.alphaNumericCharsStr,c=new RegExp("["+b+"\\-;:&=+$.,]+@"),d=a.RegexLib.domainNameRegex,e=a.RegexLib.tldRegex;return new RegExp([c.source,d.source,"\\.",e.source].join(""),"gi")}(),parseMatches:function(b){for(var c,d=this.matcherRegex,e=[];null!==(c=d.exec(b));){var f=c[0];e.push(new a.match.Email(f,c.index,f))}return e}}),a.matcher.Hashtag=a.Util.extend(a.matcher.Matcher,{matcherRegex:new RegExp("#[_"+a.RegexLib.alphaNumericCharsStr+"]{1,139}","g"),nonWordCharRegex:new RegExp("[^"+a.RegexLib.alphaNumericCharsStr+"]"),constructor:function(){a.matcher.Matcher.prototype.constructor.apply(this,arguments)},parseMatches:function(b){for(var c,d=this.matcherRegex,e=this.nonWordCharRegex,f=this.serviceName,g=[];null!==(c=d.exec(b));){var h=c.index,i=b.charAt(h-1);if(0===h||e.test(i)){var j=c[0],k=c[0].slice(1);g.push(new a.match.Hashtag(j,h,f,k))}}return g}}),a.matcher.Phone=a.Util.extend(a.matcher.Matcher,{matcherRegex:/(?:(\+)?\d{1,3}[-\040.])?\(?\d{3}\)?[-\040.]?\d{3}[-\040.]\d{4}/g,parseMatches:function(b){for(var c,d=this.matcherRegex,e=[];null!==(c=d.exec(b));){var f=c[0],g=f.replace(/\D/g,""),h=!!c[1];e.push(new a.match.Phone(f,c.index,g,h))}return e}}),a.matcher.Twitter=a.Util.extend(a.matcher.Matcher,{matcherRegex:new RegExp("@[_"+a.RegexLib.alphaNumericCharsStr+"]{1,20}","g"),nonWordCharRegex:new RegExp("[^"+a.RegexLib.alphaNumericCharsStr+"]"),parseMatches:function(b){for(var c,d=this.matcherRegex,e=this.nonWordCharRegex,f=[];null!==(c=d.exec(b));){var g=c.index,h=b.charAt(g-1);if(0===g||e.test(h)){var i=c[0],j=c[0].slice(1);f.push(new a.match.Twitter(i,g,j))}}return f}}),a.matcher.Url=a.Util.extend(a.matcher.Matcher,{matcherRegex:function(){var b=/(?:[A-Za-z][-.+A-Za-z0-9]*:(?![A-Za-z][-.+A-Za-z0-9]*:\/\/)(?!\d+\/?)(?:\/\/)?)/,c=/(?:www\.)/,d=a.RegexLib.domainNameRegex,e=a.RegexLib.tldRegex,f=a.RegexLib.alphaNumericCharsStr,g=new RegExp("["+f+"\\-+&@#/%=~_()|'$*\\[\\]?!:,.;]*["+f+"\\-+&@#/%=~_()|'$*\\[\\]]");return new RegExp(["(?:","(",b.source,d.source,")","|","(","(//)?",c.source,d.source,")","|","(","(//)?",d.source+"\\.",e.source,")",")","(?:"+g.source+")?"].join(""),"gi")}(),wordCharRegExp:/\w/,openParensRe:/\(/g,closeParensRe:/\)/g,constructor:function(){if(a.matcher.Matcher.prototype.constructor.apply(this,arguments),null==this.stripPrefix)throw new Error("`stripPrefix` cfg required")},parseMatches:function(b){for(var c,d=this.matcherRegex,e=this.stripPrefix,f=[];null!==(c=d.exec(b));){var g=c[0],h=c[1],i=c[2],j=c[3],k=c[5],l=c.index,m=j||k,n=b.charAt(l-1);if(a.matcher.UrlMatchValidator.isValid(g,h)&&!(l>0&&"@"===n||l>0&&m&&this.wordCharRegExp.test(n))){if(this.matchHasUnbalancedClosingParen(g))g=g.substr(0,g.length-1);else{var o=this.matchHasInvalidCharAfterTld(g,h);o>-1&&(g=g.substr(0,o))}var p=h?"scheme":i?"www":"tld",q=!!h;f.push(new a.match.Url(g,l,g,p,q,!!m,e))}}return f},matchHasUnbalancedClosingParen:function(a){var b=a.charAt(a.length-1);if(")"===b){var c=a.match(this.openParensRe),d=a.match(this.closeParensRe),e=c&&c.length||0,f=d&&d.length||0;if(f>e)return!0}return!1},matchHasInvalidCharAfterTld:function(a,b){if(!a)return-1;var c=0;b&&(c=a.indexOf(":"),a=a.slice(c));var d=/^((.?\/\/)?[A-Za-z0-9\u00C0-\u017F\.\-]*[A-Za-z0-9\u00C0-\u017F\-]\.[A-Za-z]+)/,e=d.exec(a);return null===e?-1:(c+=e[1].length,a=a.slice(e[1].length),/^[^.A-Za-z:\/?#]/.test(a)?c:-1)}}),a.matcher.UrlMatchValidator={hasFullProtocolRegex:/^[A-Za-z][-.+A-Za-z0-9]*:\/\//,uriSchemeRegex:/^[A-Za-z][-.+A-Za-z0-9]*:/,hasWordCharAfterProtocolRegex:/:[^\s]*?[A-Za-z\u00C0-\u017F]/,isValid:function(a,b){return b&&!this.isValidUriScheme(b)||this.urlMatchDoesNotHaveProtocolOrDot(a,b)||this.urlMatchDoesNotHaveAtLeastOneWordChar(a,b)?!1:!0},isValidUriScheme:function(a){var b=a.match(this.uriSchemeRegex)[0].toLowerCase();return"javascript:"!==b&&"vbscript:"!==b},urlMatchDoesNotHaveProtocolOrDot:function(a,b){return!(!a||b&&this.hasFullProtocolRegex.test(b)||-1!==a.indexOf("."))},urlMatchDoesNotHaveAtLeastOneWordChar:function(a,b){return a&&b?!this.hasWordCharAfterProtocolRegex.test(a):!1}},a.truncate.TruncateEnd=function(b,c,d){return a.Util.ellipsis(b,c,d)},a.truncate.TruncateMiddle=function(a,b,c){if(a.length<=b)return a;var d=b-c.length,e="";return d>0&&(e=a.substr(-1*Math.floor(d/2))),(a.substr(0,Math.ceil(d/2))+c+e).substr(0,b)},a.truncate.TruncateSmart=function(a,b,c){var d=function(a){var b={},c=a,d=c.match(/^([a-z]+):\/\//i);return d&&(b.scheme=d[1],c=c.substr(d[0].length)),d=c.match(/^(.*?)(?=(\?|#|\/|$))/i),d&&(b.host=d[1],c=c.substr(d[0].length)),d=c.match(/^\/(.*?)(?=(\?|#|$))/i),d&&(b.path=d[1],c=c.substr(d[0].length)),d=c.match(/^\?(.*?)(?=(#|$))/i),d&&(b.query=d[1],c=c.substr(d[0].length)),d=c.match(/^#(.*?)$/i),d&&(b.fragment=d[1]),b},e=function(a){var b="";return a.scheme&&a.host&&(b+=a.scheme+"://"),a.host&&(b+=a.host),a.path&&(b+="/"+a.path),a.query&&(b+="?"+a.query),a.fragment&&(b+="#"+a.fragment),b},f=function(a,b){var d=b/2,e=Math.ceil(d),f=-1*Math.floor(d),g="";return 0>f&&(g=a.substr(f)),a.substr(0,e)+c+g};if(a.length<=b)return a;var g=b-c.length,h=d(a);if(h.query){var i=h.query.match(/^(.*?)(?=(\?|\#))(.*?)$/i);i&&(h.query=h.query.substr(0,i[1].length),a=e(h))}if(a.length<=b)return a;if(h.host&&(h.host=h.host.replace(/^www\./,""),a=e(h)),a.length<=b)return a;var j="";if(h.host&&(j+=h.host),j.length>=g)return h.host.length==b?(h.host.substr(0,b-c.length)+c).substr(0,b):f(j,g).substr(0,b);var k="";if(h.path&&(k+="/"+h.path),h.query&&(k+="?"+h.query),k){if((j+k).length>=g){if((j+k).length==b)return(j+k).substr(0,b);var l=g-j.length;return(j+f(k,l)).substr(0,b)}j+=k}if(h.fragment){var m="#"+h.fragment;if((j+m).length>=g){if((j+m).length==b)return(j+m).substr(0,b);var n=g-j.length;return(j+f(m,n)).substr(0,b)}j+=m}if(h.scheme&&h.host){var o=h.scheme+"://";if((j+o).length0&&(p=j.substr(-1*Math.floor(g/2))),(j.substr(0,Math.ceil(g/2))+c+p).substr(0,b)},a});
\ No newline at end of file
diff --git a/public/assets/js/alertify.js b/public/assets/js/alertify.js
new file mode 100644
index 00000000..d9d6a2b2
--- /dev/null
+++ b/public/assets/js/alertify.js
@@ -0,0 +1 @@
+!function(){"use strict";function t(){var t={version:"1.0.8",defaultOkLabel:"Ok",okLabel:"Ok",defaultCancelLabel:"Cancel",cancelLabel:"Cancel",defaultMaxLogItems:2,maxLogItems:2,promptValue:"",promptPlaceholder:"",closeLogOnClick:!1,closeLogOnClickDefault:!1,delay:5e3,defaultDelay:5e3,logContainerClass:"alertify-logs",logContainerDefaultClass:"alertify-logs",dialogs:{buttons:{holder:"",ok:"",cancel:""},input:"",message:"

{{message}}

",log:"
{{message}}
"},defaultDialogs:{buttons:{holder:"",ok:"",cancel:""},input:"",message:"

{{message}}

",log:"
{{message}}
"},build:function(t){var e=this.dialogs.buttons.ok,o="
"+this.dialogs.message.replace("{{message}}",t.message);return"confirm"!==t.type&&"prompt"!==t.type||(e=this.dialogs.buttons.cancel+this.dialogs.buttons.ok),"prompt"===t.type&&(o+=this.dialogs.input),o=(o+this.dialogs.buttons.holder+"
").replace("{{buttons}}",e).replace("{{ok}}",this.okLabel).replace("{{cancel}}",this.cancelLabel)},setCloseLogOnClick:function(t){this.closeLogOnClick=!!t},close:function(t,e){this.closeLogOnClick&&t.addEventListener("click",function(t){o(t.srcElement)}),e=e&&!isNaN(+e)?+e:this.delay,0>e?o(t):e>0&&setTimeout(function(){o(t)},e)},dialog:function(t,e,o,n){return this.setup({type:e,message:t,onOkay:o,onCancel:n})},log:function(t,e,o){var n=document.querySelectorAll(".alertify-logs > div");if(n){var i=n.length-this.maxLogItems;if(i>=0)for(var a=0,l=i+1;l>a;a++)this.close(n[a],-1)}this.notify(t,e,o)},setLogPosition:function(t){this.logContainerClass="alertify-logs "+t},setupLogContainer:function(){var t=document.querySelector(".alertify-logs"),e=this.logContainerClass;return t||(t=document.createElement("div"),t.className=e,document.body.appendChild(t)),t.className!==e&&(t.className=e),t},notify:function(e,o,n){var i=this.setupLogContainer(),a=document.createElement("div");a.className=o||"default",t.logTemplateMethod?a.innerHTML=t.logTemplateMethod(e):a.innerHTML=e,"function"==typeof n&&a.addEventListener("click",n),i.appendChild(a),setTimeout(function(){a.className+=" show"},10),this.close(a,this.delay)},setup:function(t){function e(e){"function"!=typeof e&&(e=function(){}),i&&i.addEventListener("click",function(i){t.onOkay&&"function"==typeof t.onOkay&&(l?t.onOkay(l.value,i):t.onOkay(i)),e(l?{buttonClicked:"ok",inputValue:l.value,event:i}:{buttonClicked:"ok",event:i}),o(n)}),a&&a.addEventListener("click",function(i){t.onCancel&&"function"==typeof t.onCancel&&t.onCancel(i),e({buttonClicked:"cancel",event:i}),o(n)})}var n=document.createElement("div");n.className="alertify hide",n.innerHTML=this.build(t);var i=n.querySelector(".ok"),a=n.querySelector(".cancel"),l=n.querySelector("input"),s=n.querySelector("label");l&&("string"==typeof this.promptPlaceholder&&(s?s.textContent=this.promptPlaceholder:l.placeholder=this.promptPlaceholder),"string"==typeof this.promptValue&&(l.value=this.promptValue));var r;return"function"==typeof Promise?r=new Promise(e):e(),document.body.appendChild(n),setTimeout(function(){n.classList.remove("hide"),l&&t.type&&"prompt"===t.type?(l.select(),l.focus()):i&&i.focus()},100),r},okBtn:function(t){return this.okLabel=t,this},setDelay:function(t){var e=parseInt(t||0,10);return this.delay=isNaN(e)?this.defultDelay:t,this},cancelBtn:function(t){return this.cancelLabel=t,this},setMaxLogItems:function(t){this.maxLogItems=parseInt(t||this.defaultMaxLogItems)},theme:function(t){switch(t.toLowerCase()){case"bootstrap":this.dialogs.buttons.ok="",this.dialogs.buttons.cancel="",this.dialogs.input="";break;case"purecss":this.dialogs.buttons.ok="",this.dialogs.buttons.cancel="";break;case"mdl":case"material-design-light":this.dialogs.buttons.ok="",this.dialogs.buttons.cancel="",this.dialogs.input="
";break;case"angular-material":this.dialogs.buttons.ok="",this.dialogs.buttons.cancel="",this.dialogs.input="
";break;case"default":default:this.dialogs.buttons.ok=this.defaultDialogs.buttons.ok,this.dialogs.buttons.cancel=this.defaultDialogs.buttons.cancel,this.dialogs.input=this.defaultDialogs.input}},reset:function(){this.theme("default"),this.okBtn(this.defaultOkLabel),this.cancelBtn(this.defaultCancelLabel),this.setMaxLogItems(),this.promptValue="",this.promptPlaceholder="",this.delay=this.defaultDelay,this.setCloseLogOnClick(this.closeLogOnClickDefault),this.setLogPosition("bottom left"),this.logTemplateMethod=null},injectCSS:function(){if(!document.querySelector("#alertifyCSS")){var t=document.getElementsByTagName("head")[0],e=document.createElement("style");e.type="text/css",e.id="alertifyCSS",e.innerHTML=".alertify-logs>*{padding:12px 24px;color:#fff;box-shadow:0 2px 5px 0 rgba(0,0,0,.2);border-radius:1px}.alertify-logs>*,.alertify-logs>.default{background:rgba(0,0,0,.8)}.alertify-logs>.error{background:rgba(244,67,54,.8)}.alertify-logs>.success{background:rgba(76,175,80,.9)}.alertify{position:fixed;background-color:rgba(0,0,0,.3);left:0;right:0;top:0;bottom:0;width:100%;height:100%;z-index:2}.alertify.hide{opacity:0;pointer-events:none}.alertify,.alertify.show{box-sizing:border-box;transition:all .33s cubic-bezier(.25,.8,.25,1)}.alertify,.alertify *{box-sizing:border-box}.alertify .dialog{padding:12px}.alertify .alert,.alertify .dialog{width:100%;margin:0 auto;position:relative;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.alertify .alert>*,.alertify .dialog>*{width:400px;max-width:95%;margin:0 auto;text-align:center;padding:12px;background:#fff;box-shadow:0 2px 4px -1px rgba(0,0,0,.14),0 4px 5px 0 rgba(0,0,0,.098),0 1px 10px 0 rgba(0,0,0,.084)}.alertify .alert .msg,.alertify .dialog .msg{padding:12px;margin-bottom:12px;margin:0;text-align:left}.alertify .alert input:not(.form-control),.alertify .dialog input:not(.form-control){margin-bottom:15px;width:100%;font-size:100%;padding:12px}.alertify .alert input:not(.form-control):focus,.alertify .dialog input:not(.form-control):focus{outline-offset:-2px}.alertify .alert nav,.alertify .dialog nav{text-align:right}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button),.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button){background:transparent;box-sizing:border-box;color:rgba(0,0,0,.87);position:relative;outline:0;border:0;display:inline-block;-webkit-align-items:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center;padding:0 6px;margin:6px 8px;line-height:36px;min-height:36px;white-space:nowrap;min-width:88px;text-align:center;text-transform:uppercase;font-size:14px;text-decoration:none;cursor:pointer;border:1px solid transparent;border-radius:2px}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover{background-color:rgba(0,0,0,.05)}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus{border:1px solid rgba(0,0,0,.1)}.alertify .alert nav button.btn,.alertify .dialog nav button.btn{margin:6px 4px}.alertify-logs{position:fixed;z-index:1}.alertify-logs.bottom,.alertify-logs:not(.top){bottom:16px}.alertify-logs.left,.alertify-logs:not(.right){left:16px}.alertify-logs.left>*,.alertify-logs:not(.right)>*{float:left;-webkit-transform:translateZ(0);transform:translateZ(0);height:auto}.alertify-logs.left>.show,.alertify-logs:not(.right)>.show{left:0}.alertify-logs.left>*,.alertify-logs.left>.hide,.alertify-logs:not(.right)>*,.alertify-logs:not(.right)>.hide{left:-110%}.alertify-logs.right{right:16px}.alertify-logs.right>*{float:right;-webkit-transform:translateZ(0);transform:translateZ(0)}.alertify-logs.right>.show{right:0;opacity:1}.alertify-logs.right>*,.alertify-logs.right>.hide{right:-110%;opacity:0}.alertify-logs.top{top:0}.alertify-logs>*{box-sizing:border-box;transition:all .4s cubic-bezier(.25,.8,.25,1);position:relative;clear:both;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000;max-height:0;margin:0;padding:0;overflow:hidden;opacity:0;pointer-events:none}.alertify-logs>.show{margin-top:12px;opacity:1;max-height:1000px;padding:12px;pointer-events:auto}",t.insertBefore(e,t.firstChild)}},removeCSS:function(){var t=document.querySelector("#alertifyCSS");t&&t.parentNode&&t.parentNode.removeChild(t)}};return t.injectCSS(),{_$$alertify:t,reset:function(){return t.reset(),this},alert:function(e,o,n){return t.dialog(e,"alert",o,n)||this},confirm:function(e,o,n){return t.dialog(e,"confirm",o,n)||this},prompt:function(e,o,n){return t.dialog(e,"prompt",o,n)||this},log:function(e,o){return t.log(e,"default",o),this},theme:function(e){return t.theme(e),this},success:function(e,o){return t.log(e,"success",o),this},error:function(e,o){return t.log(e,"error",o),this},cancelBtn:function(e){return t.cancelBtn(e),this},okBtn:function(e){return t.okBtn(e),this},delay:function(e){return t.setDelay(e),this},placeholder:function(e){return t.promptPlaceholder=e,this},defaultValue:function(e){return t.promptValue=e,this},maxLogItems:function(e){return t.setMaxLogItems(e),this},closeLogOnClick:function(e){return t.setCloseLogOnClick(!!e),this},logPosition:function(e){return t.setLogPosition(e||""),this},setLogTemplate:function(e){return t.logTemplateMethod=e,this},clearLogs:function(){return t.setupLogContainer().innerHTML="",this},version:t.version}}var e=500,o=function(t){if(t){var o=function(){t&&t.parentNode&&t.parentNode.removeChild(t)};t.classList.remove("show"),t.classList.add("hide"),t.addEventListener("transitionend",o),setTimeout(o,e)}};if("undefined"!=typeof module&&module&&module.exports){module.exports=function(){return new t};var n=new t;for(var i in n)module.exports[i]=n[i]}else"function"==typeof define&&define.amd?define(function(){return new t}):window.alertify=new t}(); \ No newline at end of file diff --git a/public/assets/js/fetch.js b/public/assets/js/fetch.js new file mode 100644 index 00000000..fac11e42 --- /dev/null +++ b/public/assets/js/fetch.js @@ -0,0 +1,389 @@ +(function(self) { + 'use strict'; + + if (self.fetch) { + return + } + + function normalizeName(name) { + if (typeof name !== 'string') { + name = String(name) + } + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name') + } + return name.toLowerCase() + } + + function normalizeValue(value) { + if (typeof value !== 'string') { + value = String(value) + } + return value + } + + function Headers(headers) { + this.map = {} + + if (headers instanceof Headers) { + headers.forEach(function(value, name) { + this.append(name, value) + }, this) + + } else if (headers) { + Object.getOwnPropertyNames(headers).forEach(function(name) { + this.append(name, headers[name]) + }, this) + } + } + + Headers.prototype.append = function(name, value) { + name = normalizeName(name) + value = normalizeValue(value) + var list = this.map[name] + if (!list) { + list = [] + this.map[name] = list + } + list.push(value) + } + + Headers.prototype['delete'] = function(name) { + delete this.map[normalizeName(name)] + } + + Headers.prototype.get = function(name) { + var values = this.map[normalizeName(name)] + return values ? values[0] : null + } + + Headers.prototype.getAll = function(name) { + return this.map[normalizeName(name)] || [] + } + + Headers.prototype.has = function(name) { + return this.map.hasOwnProperty(normalizeName(name)) + } + + Headers.prototype.set = function(name, value) { + this.map[normalizeName(name)] = [normalizeValue(value)] + } + + Headers.prototype.forEach = function(callback, thisArg) { + Object.getOwnPropertyNames(this.map).forEach(function(name) { + this.map[name].forEach(function(value) { + callback.call(thisArg, value, name, this) + }, this) + }, this) + } + + function consumed(body) { + if (body.bodyUsed) { + return Promise.reject(new TypeError('Already read')) + } + body.bodyUsed = true + } + + function fileReaderReady(reader) { + return new Promise(function(resolve, reject) { + reader.onload = function() { + resolve(reader.result) + } + reader.onerror = function() { + reject(reader.error) + } + }) + } + + function readBlobAsArrayBuffer(blob) { + var reader = new FileReader() + reader.readAsArrayBuffer(blob) + return fileReaderReady(reader) + } + + function readBlobAsText(blob) { + var reader = new FileReader() + reader.readAsText(blob) + return fileReaderReady(reader) + } + + var support = { + blob: 'FileReader' in self && 'Blob' in self && (function() { + try { + new Blob(); + return true + } catch(e) { + return false + } + })(), + formData: 'FormData' in self, + arrayBuffer: 'ArrayBuffer' in self + } + + function Body() { + this.bodyUsed = false + + + this._initBody = function(body) { + this._bodyInit = body + if (typeof body === 'string') { + this._bodyText = body + } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { + this._bodyBlob = body + } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { + this._bodyFormData = body + } else if (!body) { + this._bodyText = '' + } else if (support.arrayBuffer && ArrayBuffer.prototype.isPrototypeOf(body)) { + // Only support ArrayBuffers for POST method. + // Receiving ArrayBuffers happens via Blobs, instead. + } else { + throw new Error('unsupported BodyInit type') + } + + if (!this.headers.get('content-type')) { + if (typeof body === 'string') { + this.headers.set('content-type', 'text/plain;charset=UTF-8') + } else if (this._bodyBlob && this._bodyBlob.type) { + this.headers.set('content-type', this._bodyBlob.type) + } + } + } + + if (support.blob) { + this.blob = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return Promise.resolve(this._bodyBlob) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as blob') + } else { + return Promise.resolve(new Blob([this._bodyText])) + } + } + + this.arrayBuffer = function() { + return this.blob().then(readBlobAsArrayBuffer) + } + + this.text = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return readBlobAsText(this._bodyBlob) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as text') + } else { + return Promise.resolve(this._bodyText) + } + } + } else { + this.text = function() { + var rejected = consumed(this) + return rejected ? rejected : Promise.resolve(this._bodyText) + } + } + + if (support.formData) { + this.formData = function() { + return this.text().then(decode) + } + } + + this.json = function() { + return this.text().then(JSON.parse) + } + + return this + } + + // HTTP methods whose capitalization should be normalized + var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] + + function normalizeMethod(method) { + var upcased = method.toUpperCase() + return (methods.indexOf(upcased) > -1) ? upcased : method + } + + function Request(input, options) { + options = options || {} + var body = options.body + if (Request.prototype.isPrototypeOf(input)) { + if (input.bodyUsed) { + throw new TypeError('Already read') + } + this.url = input.url + this.credentials = input.credentials + if (!options.headers) { + this.headers = new Headers(input.headers) + } + this.method = input.method + this.mode = input.mode + if (!body) { + body = input._bodyInit + input.bodyUsed = true + } + } else { + this.url = input + } + + this.credentials = options.credentials || this.credentials || 'omit' + if (options.headers || !this.headers) { + this.headers = new Headers(options.headers) + } + this.method = normalizeMethod(options.method || this.method || 'GET') + this.mode = options.mode || this.mode || null + this.referrer = null + + if ((this.method === 'GET' || this.method === 'HEAD') && body) { + throw new TypeError('Body not allowed for GET or HEAD requests') + } + this._initBody(body) + } + + Request.prototype.clone = function() { + return new Request(this) + } + + function decode(body) { + var form = new FormData() + body.trim().split('&').forEach(function(bytes) { + if (bytes) { + var split = bytes.split('=') + var name = split.shift().replace(/\+/g, ' ') + var value = split.join('=').replace(/\+/g, ' ') + form.append(decodeURIComponent(name), decodeURIComponent(value)) + } + }) + return form + } + + function headers(xhr) { + var head = new Headers() + var pairs = xhr.getAllResponseHeaders().trim().split('\n') + pairs.forEach(function(header) { + var split = header.trim().split(':') + var key = split.shift().trim() + var value = split.join(':').trim() + head.append(key, value) + }) + return head + } + + Body.call(Request.prototype) + + function Response(bodyInit, options) { + if (!options) { + options = {} + } + + this.type = 'default' + this.status = options.status + this.ok = this.status >= 200 && this.status < 300 + this.statusText = options.statusText + this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers) + this.url = options.url || '' + this._initBody(bodyInit) + } + + Body.call(Response.prototype) + + Response.prototype.clone = function() { + return new Response(this._bodyInit, { + status: this.status, + statusText: this.statusText, + headers: new Headers(this.headers), + url: this.url + }) + } + + Response.error = function() { + var response = new Response(null, {status: 0, statusText: ''}) + response.type = 'error' + return response + } + + var redirectStatuses = [301, 302, 303, 307, 308] + + Response.redirect = function(url, status) { + if (redirectStatuses.indexOf(status) === -1) { + throw new RangeError('Invalid status code') + } + + return new Response(null, {status: status, headers: {location: url}}) + } + + self.Headers = Headers; + self.Request = Request; + self.Response = Response; + + self.fetch = function(input, init) { + return new Promise(function(resolve, reject) { + var request + if (Request.prototype.isPrototypeOf(input) && !init) { + request = input + } else { + request = new Request(input, init) + } + + var xhr = new XMLHttpRequest() + + function responseURL() { + if ('responseURL' in xhr) { + return xhr.responseURL + } + + // Avoid security warnings on getResponseHeader when not allowed by CORS + if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { + return xhr.getResponseHeader('X-Request-URL') + } + + return; + } + + xhr.onload = function() { + var status = (xhr.status === 1223) ? 204 : xhr.status + if (status < 100 || status > 599) { + reject(new TypeError('Network request failed')) + return + } + var options = { + status: status, + statusText: xhr.statusText, + headers: headers(xhr), + url: responseURL() + } + var body = 'response' in xhr ? xhr.response : xhr.responseText; + resolve(new Response(body, options)) + } + + xhr.onerror = function() { + reject(new TypeError('Network request failed')) + } + + xhr.open(request.method, request.url, true) + + if (request.credentials === 'include') { + xhr.withCredentials = true + } + + if ('responseType' in xhr && support.blob) { + xhr.responseType = 'blob' + } + + request.headers.forEach(function(value, name) { + xhr.setRequestHeader(name, value) + }) + + xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) + }) + } + self.fetch.polyfill = true +})(typeof self !== 'undefined' ? self : this); diff --git a/public/assets/js/form-save.js b/public/assets/js/form-save.js new file mode 100644 index 00000000..151d1219 --- /dev/null +++ b/public/assets/js/form-save.js @@ -0,0 +1,69 @@ +var feature = { + addEventListener : !!window.addEventListener, + querySelectorAll : !!document.querySelectorAll, +}; +if(feature.addEventListener && feature.querySelectorAll) { + this.init(); +} +function init() { + var keys = getKeys(); + for(var i = 0; i < keys.length; i++) { + if(store.get(keys[i])) { + var formId = keys[i].split("~")[1]; + document.getElementById(formId).value = store.get(keys[i]); + } + } +} +var timerId = window.setInterval(function() { + var saved = false; + var inputs = document.querySelectorAll('input[type=text], textarea'); + for(var i = 0; i < inputs.length; i++) { + var key = getFormElement(inputs[i]).id + '~' + inputs[i].id; + if(store.get(key) !== inputs[i].value && inputs[i].value !== "") { + store.set(key, inputs[i].value); + saved = true; + } + } + if(saved === true) { + alertify.logPosition('top right'); + alertify.success('Auto saved text'); + } +}, 5000); +var forms = document.querySelectorAll('form'); +for(var f = 0; f < forms.length; f++) { + var form = forms[f]; + form.addEventListener('submit', function() { + window.clearInterval(timerId); + var formId = form.id; + var storedKeys = store.keys(); + for(var i = 0; i < storedKeys.length; i++) { + if(storedKeys[i].indexOf(formId) > -1) { + store.remove(storedKeys[i]); + } + } + }); +} +function getKeys() { + var keys = []; + var formFields = document.querySelectorAll('input[type=text], textarea'); + for(var f = 0; f < formFields.length; f++) { + var parent = getFormElement(formFields[f]); + if(parent !== false) { + var key = parent.id + '~' + formFields[f].id; + keys.push(key); + } + } + return keys; +} +function getFormElement(elem) { + if(elem.nodeName.toLowerCase() !== 'body') { + var parent = elem.parentNode; + if(parent.nodeName.toLowerCase() === 'form') { + return parent; + } else { + return getFormElement(parent); + } + } else { + return false; + } +} diff --git a/public/assets/js/links.js b/public/assets/js/links.js new file mode 100644 index 00000000..b683edd5 --- /dev/null +++ b/public/assets/js/links.js @@ -0,0 +1,25 @@ +//the autlinker object +var autolinker = new Autolinker(); + +//the youtube regex +var ytidregex = /watch\?v=([A-Za-z0-9\-_]+)/; + +//grab the notes and loop through them +var notes = document.querySelectorAll('.e-content'); +for(var i = 0; i < notes.length; i++) { + //get Youtube ID + var ytid = notes[i].textContent.match(ytidregex); + if(ytid !== null) { + var id = ytid[1]; + var iframe = document.createElement('iframe'); + iframe.classList.add('youtube'); + iframe.setAttribute('src', '//www.youtube.com/embed/' + id); + iframe.setAttribute('frameborder', 0); + iframe.setAttribute('allowfullscreen', 'true'); + notes[i].appendChild(iframe); + } + //now linkify everything + var orig = notes[i].innerHTML; + var linked = autolinker.link(orig); + notes[i].innerHTML = linked; +} \ No newline at end of file diff --git a/public/assets/js/maps.js b/public/assets/js/maps.js new file mode 100644 index 00000000..4901c5da --- /dev/null +++ b/public/assets/js/maps.js @@ -0,0 +1,15 @@ +//This code runs on page load and looks for
, then adds map +var mapDivs = document.querySelectorAll('.map'); +for(var i = 0; i < mapDivs.length; i++) { + var mapDiv = mapDivs[i]; + var latitude = mapDiv.dataset.latitude; + var longitude = mapDiv.dataset.longitude; + L.mapbox.accessToken = 'pk.eyJ1Ijoiam9ubnliYXJuZXMiLCJhIjoiVlpndW1EYyJ9.aP9fxAqLKh7lj0LpFh5k1w'; + var map = L.mapbox.map(mapDiv, 'jonnybarnes.gnoihnim') + .setView([latitude, longitude], 15) + .addLayer(L.mapbox.tileLayer('jonnybarnes.gnoihnim', { + detectRetina: true, + })); + var marker = L.marker([latitude, longitude]).addTo(map); + map.scrollWheelZoom.disable(); +} diff --git a/public/assets/js/marked.min.js b/public/assets/js/marked.min.js new file mode 100644 index 00000000..555c1dc1 --- /dev/null +++ b/public/assets/js/marked.min.js @@ -0,0 +1,6 @@ +/** + * marked - a markdown parser + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) + * https://github.com/chjj/marked + */ +(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]||""});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&(cap[1]==="pre"||cap[1]==="script"||cap[1]==="style"),text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(cap[0]):escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.text(escape(this.smartypants(cap[0])));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){if(!this.options.mangle)return text;var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
"+(escaped?code:escape(code,true))+"\n
"}return'
'+(escaped?code:escape(code,true))+"\n
\n"};Renderer.prototype.blockquote=function(quote){return"
\n"+quote+"
\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};Renderer.prototype.text=function(text){return text};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,sanitizer:null,mangle:true,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file diff --git a/public/assets/js/newnote.js b/public/assets/js/newnote.js new file mode 100644 index 00000000..2a26b261 --- /dev/null +++ b/public/assets/js/newnote.js @@ -0,0 +1,284 @@ +if ('geolocation' in navigator) { + var button = document.querySelector('#locate'); + if (button.addEventListener) { + //if we have javascript, event listeners and geolocation, make the locate + //button clickable and add event + button.disabled = false; + button.addEventListener('click', getLocation); + } +} + +function getLocation() { + navigator.geolocation.getCurrentPosition(function (position) { + //the locate button has been clicked so add the places/map + addPlaces(position.coords.latitude, position.coords.longitude); + }); +} + +function addPlaces(latitude, longitude) { + //get the nearby places + fetch('/places/near/' + latitude + '/' + longitude, { + credentials: 'same-origin', + method: 'get' + }).then(function (response) { + return response.json(); + }).then(function (j) { + if (j.length > 0) { + var i; + var places = []; + for (i = 0; i < j.length; ++i) { + var latlng = parseLocation(j[i].location); + var name = j[i].name; + var slug = j[i].slug; + places.push([name, slug, latlng[0], latlng[1]]); + } + //add a map with the nearby places + addMap(latitude, longitude, places); + } else { + //add a map with just current location + addMap(latitude, longitude); + } + }).catch(function (err) { + console.log(err); + }); +} + +function addMap(latitude, longitude, places) { + //make places null if not supplied + if (arguments.length == 2) { + places = null; + } + var form = button.parentNode; + var div = document.createElement('div'); + div.setAttribute('id', 'map'); + //add the map div + form.appendChild(div); + L.mapbox.accessToken = 'pk.eyJ1Ijoiam9ubnliYXJuZXMiLCJhIjoiVlpndW1EYyJ9.aP9fxAqLKh7lj0LpFh5k1w'; + var map = L.mapbox.map('map', 'jonnybarnes.gnoihnim') + .setView([latitude, longitude], 15) + .addLayer(L.mapbox.tileLayer('jonnybarnes.gnoihnim', { + detectRetina: true, + })); + //add a marker for the current location + var marker = L.marker([latitude, longitude], { + draggable: true, + }).addTo(map); + //when the location marker is dragged, if the new place form elements exist + //update the lat/lng values + marker.on('dragend', function () { + var placeFormLatitude = document.querySelector('#place-latitude'); + if (placeFormLatitude !== null) { + placeFormLatitude.value = getLatitudeFromMapboxMarker(marker.getLatLng()); + } + var placeFormLongitude = document.querySelector('#place-longitude'); + if (placeFormLongitude !== null) { + placeFormLongitude.value = getLongitudeFromMapboxMarker(marker.getLatLng()); + } + }); + //create the + places.forEach(function (item, index, array) { + var option = document.createElement('option'); + option.setAttribute('value', item[1]); + var text = document.createTextNode(item[0]); + option.appendChild(text); + option.dataset.latitude = item[2]; + option.dataset.longitude = item[3]; + selectEl.appendChild(option); + var placeMarker = L.marker([item[2], item[3]], { + icon: L.mapbox.marker.icon({ + 'marker-size': 'large', + 'marker-symbol': 'building', + 'marker-color': '#fa0' + }) + }).addTo(map); + var name = 'Name: ' + item[0]; + placeMarker.bindPopup(name, { + closeButton: true + }); + placeMarker.on('click', function (e) { + map.panTo([item[2], item[3]]); + selectPlace(item[1]); + }); + }); + //add an event listener + selectEl.addEventListener('change', function () { + if (selectEl.value !== 'no-location') { + var placeLat = selectEl[selectEl.selectedIndex].dataset.latitude; + var placeLon = selectEl[selectEl.selectedIndex].dataset.longitude; + map.panTo([placeLat, placeLon]); + } + }); + } + //add a button to add a new place + var newLocButton = document.createElement('button'); + newLocButton.setAttribute('type', 'button'); + newLocButton.setAttribute('id', 'create-new-place'); + newLocButton.appendChild(document.createTextNode('Create New Place?')); + //the event listener + newLocButton.addEventListener('click', function() { + //add the form elements + var nameLabel = document.createElement('label'); + nameLabel.setAttribute('for', 'place-name'); + nameLabel.classList.add('place-label') + nameLabel.appendChild(document.createTextNode('Place Name:')); + var nameEl = document.createElement('input'); + nameEl.setAttribute('placeholder', 'Name'); + nameEl.setAttribute('name', 'place-name'); + nameEl.setAttribute('id', 'place-name'); + nameEl.setAttribute('type', 'text'); + var descLabel = document.createElement('label'); + descLabel.setAttribute('for', 'place-description'); + descLabel.classList.add('place-label'); + descLabel.appendChild(document.createTextNode('Place Description:')); + var descEl = document.createElement('input'); + descEl.setAttribute('placeholder', 'Description'); + descEl.setAttribute('name', 'place-description'); + descEl.setAttribute('id', 'place-description'); + descEl.setAttribute('type', 'text'); + var latLabel = document.createElement('label'); + latLabel.setAttribute('for', 'place-latitude'); + latLabel.classList.add('place-label'); + latLabel.appendChild(document.createTextNode('Place Latitude:')); + var latEl = document.createElement('input'); + latEl.setAttribute('name', 'place-latitude'); + latEl.setAttribute('id', 'place-latitude'); + latEl.setAttribute('type', 'text'); + latEl.value = getLatitudeFromMapboxMarker(marker.getLatLng()); + var lonLabel = document.createElement('label'); + lonLabel.setAttribute('for', 'place-longitude'); + lonLabel.classList.add('place-label'); + lonLabel.appendChild(document.createTextNode('Place Longitude:')); + var lonEl = document.createElement('input'); + lonEl.setAttribute('name', 'place-longitude'); + lonEl.setAttribute('id', 'place-longitude'); + lonEl.setAttribute('type', 'text'); + lonEl.value = getLongitudeFromMapboxMarker(marker.getLatLng()); + var placeSubmit = document.createElement('button'); + placeSubmit.setAttribute('id', 'place-submit'); + placeSubmit.setAttribute('value', 'Submit New Place'); + placeSubmit.setAttribute('name', 'place-submit'); + placeSubmit.setAttribute('type', 'button'); + placeSubmit.appendChild(document.createTextNode('Submit New Place')); + form.appendChild(nameLabel); + form.appendChild(nameEl); + form.appendChild(descLabel); + form.appendChild(descEl); + form.appendChild(latLabel); + form.appendChild(latEl); + form.appendChild(lonLabel); + form.appendChild(lonEl); + form.appendChild(placeSubmit); + //the event listener for the new place form + placeSubmit.addEventListener('click', function () { + //create the form data to send + var formData = new FormData(); + formData.append('place-name', document.querySelector('#place-name').value); + formData.append('place-description', document.querySelector('#place-description').value); + formData.append('place-latitude', document.querySelector('#place-latitude').value); + formData.append('place-longitude', document.querySelector('#place-longitude').value); + //post the new place + fetch('/places/new', { + //send cookies with the request + credentials: 'same-origin', + method: 'post', + body: formData + }) + .then(status) + .then(json) + .then(function (placeJson) { + //create the slug from the url + var urlParts = placeJson.split('/'); + var slug = urlParts.pop(); + //remove un-needed form elements + form.removeChild(document.querySelector('#place-name')); + form.removeChild(document.querySelector('#place-description')); + form.removeChild(document.querySelector('#place-latitude')); + form.removeChild(document.querySelector('#place-longitude')); + var labels = document.querySelectorAll('.place-label'); + for (var label of labels) { + form.removeChild(label); + } + form.removeChild(document.querySelector('#place-submit')); + form.removeChild(document.querySelector('#create-new-place')); + //remove location marker + map.removeLayer(marker); + //add place marker + var newOption = document.createElement('option'); + newOption.setAttribute('value', slug); + newOption.appendChild(document.createTextNode(placeJson['name'])); + newOption.dataset.latitude = placeJson['latitude']; + newOption.dataset.longitude = placeJson['longitude']; + selectEl.appendChild(newOption); + var newPlaceMarker = L.marker([placeJson['latitude'], placeJson['longitude']], { + icon: L.mapbox.marker.icon({ + 'marker-size': 'large', + 'marker-symbol': 'building', + 'marker-color': '#fa0' + }) + }).addTo(map); + var newName = 'Name: ' + placeJson['name']; + newPlaceMarker.bindPopup(newName, { + closeButton: true + }); + newPlaceMarker.on('click', function (e) { + map.panTo([placeJson['latitude'], placeJson['longitude']]); + selectPlace(slug); + }); + //make selected + selectPlace(slug); + }).catch(function (placeError) { + console.log(placeError); + }); + }) + }); + form.insertBefore(newLocButton, div); +} + +function parseLocation(point) { + var re = /\((.*)\)/; + var resultArray = re.exec(point); + var location = resultArray[1].split(' '); + + return [location[1], location[0]]; +} + +function selectPlace(slug) { + document.querySelector('select [value=' + slug + ']').selected = true; +} + +function getLatitudeFromMapboxMarker(latlng) { + var resultArray = /\((.*)\)/.exec(latlng); + var location = resultArray[1].split(' '); + + return location[0].replace(',', ''); +} + +function getLongitudeFromMapboxMarker(latlng) { + var resultArray = /\((.*)\)/.exec(latlng); + var location = resultArray[1].split(' '); + + return location[1]; +} + +function status(response) { + if (response.status >= 200 && response.status < 300) { + return Promise.resolve(response); + } else { + return Promise.reject(new Error(response.statusText)); + } +} + +function json(response) { + return response.json(); +} diff --git a/public/assets/js/newplace.js b/public/assets/js/newplace.js new file mode 100644 index 00000000..166031a4 --- /dev/null +++ b/public/assets/js/newplace.js @@ -0,0 +1,45 @@ +var button = document.querySelector('#locate'); + +if (button.addEventListener) { + button.addEventListener('click', getLocation); +} else { + button.attachEvent('onclick', getLocation); +} + +function getLocation() { + if ('geolocation' in navigator) { + navigator.geolocation.getCurrentPosition(function(position) { + updateForm(position.coords.latitude, position.coords.longitude); + addMap(position.coords.latitude, position.coords.longitude); + }); + } else { + console.log('I need to do something when geoloaction isn’t available.'); + } +} + +function updateForm(latitude, longitude) { + var inputLatitude = document.querySelector('#latitude'); + var inputLongitude = document.querySelector('#longitude'); + inputLatitude.value = latitude; + inputLongitude.value = longitude; +} + +function addMap(latitude, longitude) { + var form = document.querySelector('form'); + var div = document.createElement('div'); + div.setAttribute('id', 'map'); + form.appendChild(div); + L.mapbox.accessToken = 'pk.eyJ1Ijoiam9ubnliYXJuZXMiLCJhIjoiVlpndW1EYyJ9.aP9fxAqLKh7lj0LpFh5k1w'; + var map = L.mapbox.map('map', 'jonnybarnes.gnoihnim') + .setView([latitude, longitude], 15) + .addLayer(L.mapbox.tileLayer('jonnybarnes.gnoihnim', { + detectRetina: true, + })); + var marker = L.marker([latitude, longitude], { + draggable: true, + }).addTo(map); + marker.on('dragend', function () { + var markerLocation = marker.getLatLng(); + updateForm(markerLocation.lat, markerLocation.lng); + }); +} diff --git a/public/assets/js/prism.js b/public/assets/js/prism.js new file mode 100644 index 00000000..b00d099e --- /dev/null +++ b/public/assets/js/prism.js @@ -0,0 +1,15 @@ +/* http://prismjs.com/download.html?themes=prism-dark&languages=markup+css+clike+javascript+git+http+markdown+php+php-extras+scss+sql&plugins=line-numbers+show-invisibles */ +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=_self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),N=[p,1];b&&N.push(b);var O=new a(l,g?t.tokenize(m,g):m,h);N.push(O),w&&N.push(w),Array.prototype.splice.apply(r,N)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var i={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==i.type&&(i.attributes.spellcheck="true"),e.alias){var l="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,l)}t.hooks.run("wrap",i);var o="";for(var s in i.attributes)o+=s+'="'+(i.attributes[s]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+o+">"+i.content+""},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code;_self.postMessage(JSON.stringify(t.util.encode(t.tokenize(r,t.languages[a])))),_self.close()},!1),_self.Prism):_self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism);; +Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(t){"entity"===t.type&&(t.attributes.title=t.content.replace(/&/,"&"))});; +Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/i,inside:{tag:{pattern:/|<\/style>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css},alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag));; +Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};; +Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/(?!\d)[a-z0-9_$]+(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/i,inside:{tag:{pattern:/|<\/script>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript},alias:"language-javascript"}});; +Prism.languages.git={comment:/^#.*$/m,string:/("|')(\\?.)*?\1/m,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s(--|-)\w+/m}},coord:/^@@.*@@$/m,deleted:/^-(?!-).+$/m,inserted:/^\+(?!\+).+$/m,commit_sha1:/^commit \w{40}$/m};; +Prism.languages.http={"request-line":{pattern:/^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b\shttps?:\/\/\S+\sHTTP\/[0-9.]+/,inside:{property:/^\b(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b/,"attr-name":/:\w+/}},"response-status":{pattern:/^HTTP\/1.[01] [0-9]+.*/,inside:{property:/[0-9]+[A-Z\s-]+$/i}},keyword:/^[\w-]+:(?=.+)/m};var httpLanguages={"application/json":Prism.languages.javascript,"application/xml":Prism.languages.markup,"text/xml":Prism.languages.markup,"text/html":Prism.languages.markup};for(var contentType in httpLanguages)if(httpLanguages[contentType]){var options={};options[contentType]={pattern:new RegExp("(content-type:\\s*"+contentType+"[\\w\\W]*?)\\n\\n[\\w\\W]*","i"),lookbehind:!0,inside:{rest:httpLanguages[contentType]}},Prism.languages.insertBefore("http","keyword",options)}; +Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/(^|\n)>(?:[\t ]*>)*/,lookbehind:!0,alias:"punctuation"},code:[{pattern:/(^|\n)(?: {4}|\t).+/,lookbehind:!0,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*\n(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/((?:^|\n)\s*)#+.+/,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/((?:^|\n)\s*)([*-])([\t ]*\2){2,}(?=\s*(?:\n|$))/,lookbehind:!0,alias:"punctuation"},list:{pattern:/((?:^|\n)\s*)(?:[*+-]|\d+\.)(?=[\t ].)/,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:[^>]|\\>)+>)(?:[\t ]+(?:"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\((?:[^)]|\\\))*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\((?:[^)]|\\\))*\))$/,punctuation:/[[\]\(\)<>:]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:\n(?!\n)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*\s*$|__\s*$/}},italic:{pattern:/(^|[^\\])(?:\*(?:\n(?!\n)|.)+?\*|_(?:\n(?!\n)|.)+?_)/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:[^"]|\\")*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:[^"]|\\")*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold);; +Prism.languages.php=Prism.languages.extend("clike",{keyword:/\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,constant:/\b[A-Z0-9_]{2,}\b/,comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])(\/\/).*?(\r?\n|$))/,lookbehind:!0}}),Prism.languages.insertBefore("php","class-name",{"shell-comment":{pattern:/(^|[^\\])#.*?(\r?\n|$)/,lookbehind:!0,alias:"comment"}}),Prism.languages.insertBefore("php","keyword",{delimiter:/(\?>|<\?php|<\?)/i,variable:/(\$\w+)\b/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),Prism.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}}),Prism.languages.markup&&(Prism.hooks.add("before-highlight",function(e){"php"===e.language&&(e.tokenStack=[],e.backupCode=e.code,e.code=e.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/gi,function(n){return e.tokenStack.push(n),"{{{PHP"+e.tokenStack.length+"}}}"}))}),Prism.hooks.add("before-insert",function(e){"php"===e.language&&(e.code=e.backupCode,delete e.backupCode)}),Prism.hooks.add("after-highlight",function(e){if("php"===e.language){for(var n,a=0;n=e.tokenStack[a];a++)e.highlightedCode=e.highlightedCode.replace("{{{PHP"+(a+1)+"}}}",Prism.highlight(n,e.grammar,"php"));e.element.innerHTML=e.highlightedCode}}),Prism.hooks.add("wrap",function(e){"php"===e.language&&"markup"===e.type&&(e.content=e.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g,'$1'))}),Prism.languages.insertBefore("php","comment",{markup:{pattern:/<[^?]\/?(.*?)>/,inside:Prism.languages.markup},php:/\{\{\{PHP[0-9]+\}\}\}/}));; +Prism.languages.insertBefore("php","variable",{"this":/\$this/,global:/\$_?(GLOBALS|SERVER|GET|POST|FILES|REQUEST|SESSION|ENV|COOKIE|HTTP_RAW_POST_DATA|argc|argv|php_errormsg|http_response_header)/,scope:{pattern:/\b[\w\\]+::/,inside:{keyword:/(static|self|parent)/,punctuation:/(::|\\)/}}});; +Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/,lookbehind:!0},atrule:{pattern:/@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+(\{|;))/i,inside:{rule:/@[\w-]+/}},url:/([-a-z]+-)*url(?=\()/i,selector:{pattern:/([^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+)(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/m,inside:{placeholder:/%[-_\w]+/i}}}),Prism.languages.insertBefore("scss","atrule",{keyword:/@(if|else if|else|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)|(?=@for\s+\$[-_\w]+\s)+from/i}),Prism.languages.insertBefore("scss","property",{variable:/((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i}),Prism.languages.insertBefore("scss","function",{placeholder:{pattern:/%[-_\w]+/i,alias:"selector"},statement:/\B!(default|optional)\b/i,"boolean":/\b(true|false)\b/,"null":/\b(null)\b/,operator:/\s+([-+]{1,2}|={1,2}|!=|\|?\||\?|\*|\/|%)\s+/}),Prism.languages.scss.atrule.inside.rest=Prism.util.clone(Prism.languages.scss);; +Prism.languages.sql={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|((--)|(\/\/)|#).*?(\r?\n|$))/,lookbehind:!0},string:{pattern:/(^|[^@])("|')(\\?[\s\S])*?\2/,lookbehind:!0},variable:/@[\w.$]+|@("|'|`)(\\?[\s\S])+?\1/,"function":/\b(?:COUNT|SUM|AVG|MIN|MAX|FIRST|LAST|UCASE|LCASE|MID|LEN|ROUND|NOW|FORMAT)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALTER|ANALYZE|APPLY|AS|ASC|AUTHORIZATION|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADE|CASCADED|CASE|CHAIN|CHAR VARYING|CHARACTER VARYING|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATA|DATABASE|DATABASES|DATETIME|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DOUBLE PRECISION|DROP|DUMMY|DUMP|DUMPFILE|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE|ESCAPED BY|EXCEPT|EXEC|EXECUTE|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR|FOR EACH ROW|FORCE|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GEOMETRY|GEOMETRYCOLLECTION|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEY|KEYS|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONGBLOB|LONGTEXT|MATCH|MATCHED|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTILINESTRING|MULTIPOINT|MULTIPOLYGON|NATIONAL|NATIONAL CHAR VARYING|NATIONAL CHARACTER|NATIONAL CHARACTER VARYING|NATIONAL VARCHAR|NATURAL|NCHAR|NCHAR VARCHAR|NEXT|NO|NO SQL|NOCHECK|NOCYCLE|NONCLUSTERED|NULLIF|NUMERIC|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUT|OUTER|OUTFILE|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC|PROCEDURE|PUBLIC|PURGE|QUICK|RAISERROR|READ|READS SQL DATA|READTEXT|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURN|RETURNS|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROWCOUNT|ROWGUIDCOL|ROWS?|RTREE|RULE|SAVE|SAVEPOINT|SCHEMA|SELECT|SERIAL|SERIALIZABLE|SESSION|SESSION_USER|SET|SETUSER|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START|STARTING BY|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLE|TABLES|TABLESPACE|TEMP(?:ORARY)?|TEMPTABLE|TERMINATED BY|TEXT|TEXTSIZE|THEN|TIMESTAMP|TINYBLOB|TINYINT|TINYTEXT|TO|TOP|TRAN|TRANSACTION|TRANSACTIONS|TRIGGER|TRUNCATE|TSEQUAL|TYPE|TYPES|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH|WITH ROLLUP|WITHIN|WORK|WRITE|WRITETEXT)\b/i,"boolean":/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b-?(0x)?\d*\.?[\da-f]+\b/,operator:/\b(?:ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|IS|UNIQUE|CHARACTER SET|COLLATE|DIV|OFFSET|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b|[-+]|!|[=<>]{1,2}|(&){1,2}|\|?\||\?|\*|\//i,punctuation:/[;[\]()`,.]/};; +Prism.hooks.add("complete",function(e){if(e.code){var t=e.element.parentNode,s=/\s*\bline-numbers\b\s*/;if(t&&/pre/i.test(t.nodeName)&&(s.test(t.className)||s.test(e.element.className))&&!e.element.querySelector(".line-numbers-rows")){s.test(e.element.className)&&(e.element.className=e.element.className.replace(s,"")),s.test(t.className)||(t.className+=" line-numbers");var a,n=e.code.match(/\n(?!$)/g).length+1,l=new Array(n+1);l=l.join(""),a=document.createElement("span"),a.className="line-numbers-rows",a.innerHTML=l,t.hasAttribute("data-start")&&(t.style.counterReset="linenumber "+(parseInt(t.getAttribute("data-start"),10)-1)),e.element.appendChild(a)}}});; +!function(){if(window.Prism)for(var r in Prism.languages){var g=Prism.languages[r];g.tab=/\t/g,g.crlf=/\r\n/g,g.lf=/\n/g,g.cr=/\r/g}}();; diff --git a/public/assets/js/store2.min.js b/public/assets/js/store2.min.js new file mode 100644 index 00000000..72aff0ab --- /dev/null +++ b/public/assets/js/store2.min.js @@ -0,0 +1,5 @@ +/*! store2 - v2.3.2 - 2015-10-27 +* Copyright (c) 2015 Nathan Bubna; Licensed MIT, GPL */ + +!function(a,b){var c={version:"2.3.2",areas:{},apis:{},inherit:function(a,b){for(var c in a)b.hasOwnProperty(c)||(b[c]=a[c]);return b},stringify:function(a){return void 0===a||"function"==typeof a?a+"":JSON.stringify(a)},parse:function(a){try{return JSON.parse(a)}catch(b){return a}},fn:function(a,b){c.storeAPI[a]=b;for(var d in c.apis)c.apis[d][a]=b},get:function(a,b){return a.getItem(b)},set:function(a,b,c){a.setItem(b,c)},remove:function(a,b){a.removeItem(b)},key:function(a,b){return a.key(b)},length:function(a){return a.length},clear:function(a){a.clear()},Store:function(a,b,d){var e=c.inherit(c.storeAPI,function(a,b,c){return 0===arguments.length?e.getAll():void 0!==b?e.set(a,b,c):"string"==typeof a||"number"==typeof a?e.get(a):a?e.setAll(a,b):e.clear()});e._id=a;try{var f="_safariPrivate_";b.setItem(f,"sucks"),e._area=b,b.removeItem(f)}catch(g){}return e._area||(e._area=c.inherit(c.storageAPI,{items:{},name:"fake"})),e._ns=d||"",c.areas[a]||(c.areas[a]=e._area),c.apis[e._ns+e._id]||(c.apis[e._ns+e._id]=e),e},storeAPI:{area:function(a,b){var d=this[a];return d&&d.area||(d=c.Store(a,b,this._ns),this[a]||(this[a]=d)),d},namespace:function(a,b){if(!a)return this._ns?this._ns.substring(0,this._ns.length-1):"";var d=a,e=this[d];return e&&e.namespace||(e=c.Store(this._id,this._area,this._ns+d+"."),this[d]||(this[d]=e),b||e.area("session",c.areas.session)),e},isFake:function(){return"fake"===this._area.name},toString:function(){return"store"+(this._ns?"."+this.namespace():"")+"["+this._id+"]"},has:function(a){return this._area.has?this._area.has(this._in(a)):!!(this._in(a)in this._area)},size:function(){return this.keys().length},each:function(a,b){for(var d=0,e=c.length(this._area);e>d;d++){var f=this._out(c.key(this._area,d));if(void 0!==f&&a.call(this,f,b||this.get(f))===!1)break;e>c.length(this._area)&&(e--,d--)}return b||this},keys:function(){return this.each(function(a,b){b.push(a)},[])},get:function(a,b){var d=c.get(this._area,this._in(a));return null!==d?c.parse(d):b||d},getAll:function(){return this.each(function(a,b){b[a]=this.get(a)},{})},set:function(a,b,d){var e=this.get(a);return null!=e&&d===!1?b:c.set(this._area,this._in(a),c.stringify(b),d)||e},setAll:function(a,b){var c,d;for(var e in a)d=a[e],this.set(e,d,b)!==d&&(c=!0);return c},remove:function(a){var b=this.get(a);return c.remove(this._area,this._in(a)),b},clear:function(){return this._ns?this.each(function(a){c.remove(this._area,this._in(a))},1):c.clear(this._area),this},clearAll:function(){var a=this._area;for(var b in c.areas)c.areas.hasOwnProperty(b)&&(this._area=c.areas[b],this.clear());return this._area=a,this},_in:function(a){return"string"!=typeof a&&(a=c.stringify(a)),this._ns?this._ns+a:a},_out:function(a){return this._ns?a&&0===a.indexOf(this._ns)?a.substring(this._ns.length):void 0:a}},storageAPI:{length:0,has:function(a){return this.items.hasOwnProperty(a)},key:function(a){var b=0;for(var c in this.items)if(this.has(c)&&a===b++)return c},setItem:function(a,b){this.has(a)||this.length++,this.items[a]=b},removeItem:function(a){this.has(a)&&(delete this.items[a],this.length--)},getItem:function(a){return this.has(a)?this.items[a]:null},clear:function(){for(var a in this.list)this.removeItem(a)},toString:function(){return this.length+" items in "+this.name+"Storage"}}};a.store&&(c.conflict=a.store);var d=c.Store("local",function(){try{return localStorage}catch(a){}}());d.local=d,d._=c,d.area("session",function(){try{return sessionStorage}catch(a){}}()),a.store=d,"function"==typeof b&&void 0!==b.amd?b(function(){return d}):"undefined"!=typeof module&&module.exports&&(module.exports=d)}(this,this.define); +//# sourceMappingURL=store2.min.js.map \ No newline at end of file diff --git a/public/assets/old-shorturls.json b/public/assets/old-shorturls.json new file mode 100644 index 00000000..26b0e4c4 --- /dev/null +++ b/public/assets/old-shorturls.json @@ -0,0 +1,19 @@ +{ + "RbrS": "https://jonnybarnes.net/note/1", + "pfua": "https://jonnybarnes.net/note/2", + "HQ8X": "https://jonnybarnes.net/note/3", + "7Duc": "https://jonnybarnes.net/note/4", + "m0vZ": "https://jonnybarnes.net/note/5", + "uB95": "https://jonnybarnes.net/note/6", + "yUx8": "https://jonnybarnes.net/note/7", + "tMLB": "https://jonnybarnes.net/note/8", + "a1HU": "https://jonnybarnes.net/note/9", + "rx3e": "https://jonnybarnes.net/note/10", + "dW3p": "https://jonnybarnes.net/note/11", + "_6za": "https://jonnybarnes.net/note/12", + "eTvB": "https://jonnybarnes.net/note/13", + "6kMh": "https://jonnybarnes.net/note/14", + "T72f": "https://jonnybarnes.net/note/15", + "enot": "https://jonnybarnes.net/note/16", + "QCDv": "https://jonnybarnes.net/note/17" +} \ No newline at end of file diff --git a/public/assets/profile-images/.gitignore b/public/assets/profile-images/.gitignore new file mode 100644 index 00000000..dd9ea438 --- /dev/null +++ b/public/assets/profile-images/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!default-image diff --git a/public/assets/profile-images/default-image b/public/assets/profile-images/default-image new file mode 100644 index 0000000000000000000000000000000000000000..2a0d3ed7b8e299d3ee13eb4422096009be98ad69 GIT binary patch literal 8867 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:12px 24px;color:#fff;box-shadow:0 2px 5px 0 rgba(0,0,0,.2);border-radius:1px}.alertify-logs>*,.alertify-logs>.default{background:rgba(0,0,0,.8)}.alertify-logs>.error{background:rgba(244,67,54,.8)}.alertify-logs>.success{background:rgba(76,175,80,.9)}.alertify{position:fixed;background-color:rgba(0,0,0,.3);left:0;right:0;top:0;bottom:0;width:100%;height:100%;z-index:2}.alertify.hide{opacity:0;pointer-events:none}.alertify,.alertify.show{box-sizing:border-box;transition:all .33s cubic-bezier(.25,.8,.25,1)}.alertify,.alertify *{box-sizing:border-box}.alertify .dialog{padding:12px}.alertify .alert,.alertify .dialog{width:100%;margin:0 auto;position:relative;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.alertify .alert>*,.alertify .dialog>*{width:400px;max-width:95%;margin:0 auto;text-align:center;padding:12px;background:#fff;box-shadow:0 2px 4px -1px rgba(0,0,0,.14),0 4px 5px 0 rgba(0,0,0,.098),0 1px 10px 0 rgba(0,0,0,.084)}.alertify .alert .msg,.alertify .dialog .msg{padding:12px;margin-bottom:12px;margin:0;text-align:left}.alertify .alert input:not(.form-control),.alertify .dialog input:not(.form-control){margin-bottom:15px;width:100%;font-size:100%;padding:12px}.alertify .alert input:not(.form-control):focus,.alertify .dialog input:not(.form-control):focus{outline-offset:-2px}.alertify .alert nav,.alertify .dialog nav{text-align:right}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button),.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button){background:transparent;box-sizing:border-box;color:rgba(0,0,0,.87);position:relative;outline:0;border:0;display:inline-block;-webkit-align-items:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center;padding:0 6px;margin:6px 8px;line-height:36px;min-height:36px;white-space:nowrap;min-width:88px;text-align:center;text-transform:uppercase;font-size:14px;text-decoration:none;cursor:pointer;border:1px solid transparent;border-radius:2px}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover{background-color:rgba(0,0,0,.05)}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus{border:1px solid rgba(0,0,0,.1)}.alertify .alert nav button.btn,.alertify .dialog nav button.btn{margin:6px 4px}.alertify-logs{position:fixed;z-index:1}.alertify-logs.bottom,.alertify-logs:not(.top){bottom:16px}.alertify-logs.left,.alertify-logs:not(.right){left:16px}.alertify-logs.left>*,.alertify-logs:not(.right)>*{float:left;-webkit-transform:translateZ(0);transform:translateZ(0);height:auto}.alertify-logs.left>.show,.alertify-logs:not(.right)>.show{left:0}.alertify-logs.left>*,.alertify-logs.left>.hide,.alertify-logs:not(.right)>*,.alertify-logs:not(.right)>.hide{left:-110%}.alertify-logs.right{right:16px}.alertify-logs.right>*{float:right;-webkit-transform:translateZ(0);transform:translateZ(0)}.alertify-logs.right>.show{right:0;opacity:1}.alertify-logs.right>*,.alertify-logs.right>.hide{right:-110%;opacity:0}.alertify-logs.top{top:0}.alertify-logs>*{box-sizing:border-box;transition:all .4s cubic-bezier(.25,.8,.25,1);position:relative;clear:both;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000;max-height:0;margin:0;padding:0;overflow:hidden;opacity:0;pointer-events:none}.alertify-logs>.show{margin-top:12px;opacity:1;max-height:1000px;padding:12px;pointer-events:auto} \ No newline at end of file diff --git a/public/build/assets/css/alertify-d84546f82d.css.br b/public/build/assets/css/alertify-d84546f82d.css.br new file mode 100644 index 0000000000000000000000000000000000000000..e5b38b0bb120a74fd1d7999b86f5e40231d5fbb7 GIT binary patch literal 857 zcmV-f1E%~NG!FnA2j!+Sdnqxlpfb1A zXb0ZE@#~{=UUsa~AvD9NBHo*!39Rg@SB+g+j4PIA7?NVps#JeRAaJ5Iu2zO=yZwfd z$0AM*f(rbQ-(gS^X= z2CP%jQR>%9=4J1)0Rss5mzSeN2d*(GkhAMGBHDd1ov%^aT5oqBqz&!4s){X%UT{^% z$B+u?b{8ZN<`VUAK@SAD5_tlDp|TpwPOB4HHiZ$T<~ayf?t@^D|e!V(uHso zx_t82ucRX9<1v|cgbpmoCUxjk>}tbS>+)RWF8rq(MA`_hM{$)ewMwSVeS1bYOc@Q2 zPsa4oj~1cQnBBcF?Wl(Gp$iHDk~gr;H&x4~G{p;w;>U04_Y5Lh+Q?Hp$TY-Mix8X= zHGnNq-%86y@fApQ{TRRk#d4wP6o%Ds-7Lg!?mhQ^eR7CoSdJ{8>X#CE{7qK|U|UX= zoZFDsLU3+h0L8yVra|)ae>p0nxu~RQWBaPDIMHob~LvXAICcNWC4cOKT>fp~#2N zrM%VxX`+?cMD|3g9&o?iv{B=+JC8JdNB)W?u^}ds{LzCi+2r8PLkYJHg(m`Fv&IgG j&rzFVLfd(m9&umsn7I>Tz}nK-xfMW#2G_VUvlLhqN87M- literal 0 HcmV?d00001 diff --git a/public/build/assets/css/alertify-d84546f82d.css.gz b/public/build/assets/css/alertify-d84546f82d.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..59ce31ea2fee73edaed164a9566e36a96571c6dc GIT binary patch literal 1043 zcmV+u1nm1CiwFP!000021GN{4ZmT%(SKj>|6-JQe1gZbAtJ8ogA~uxGX8#r^!OJpB78eW(BXgOutrDmF2ue>VQjr zPUBC8U!Q5h=O!=oianxZZ@T&(6n>7I>8myl(V#=Eh)1b8|q`? zn)n=KHK}wOXOiv@=2vq8-#OQsAK`GOr9Pxd9DmOa#FE(aJEE*4ZMwMWjSjRV9T&Ku z`VBY*r%V%x$cZqmQpOp%5r;Q6b>QdDUJ-paS9rMxfMi-?cJT$*^{43hS$!&+oE9i2 z@07@2(P9N53(ZdwOiBOrG%fl@`zb0ZhCsV1i;n^{e9YnA#Iik>7qHpa`=2D9|8K-iTbYpg)O5 z5@b;WjB{F|Gy-=z0=l}z>+YXO}8DtO>Q^AL|I?r3K`Zj!=a=~)c7r>%tkz~ zdGUHJdmBSUH94xG?I6bTpg2)0Z;%51B;4DeOB{qSxBOogpsUW(S z=`cjjGzGl^yUy>w;vl;NAGS=hqD)#~_r*CYEJ5!^eBTETYS-6U z@8*z}yH|>mB>p~DY{@$N?FVn~5|+)N25v#562x{@ zv$Mt77+{y{OSZX`G1W@akBR{ER_&RyDHx9%~5WR0i3&2jy2e7 N`V$p(H$ycK005$<{$>CG literal 0 HcmV?d00001 diff --git a/public/build/assets/css/global-ef9dfef096.css b/public/build/assets/css/global-ef9dfef096.css new file mode 100644 index 00000000..1750d873 --- /dev/null +++ b/public/build/assets/css/global-ef9dfef096.css @@ -0,0 +1,243 @@ +html { + background: url("/assets/img/escheresque.png"); } + +.map { + height: 150px; } + +html { + box-sizing: border-box; } + +*, *:before, *:after { + box-sizing: inherit; } + +#topheader { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-flow: row; + -ms-flex-flow: row; + flex-flow: row; } + +#topheader a { + padding: 0.5em 1em; } + +nav { + padding-top: 0.5em; } + +.social-list { + padding-left: 2em; } + +.note { + background-color: #eee8d5; + box-shadow: 0 0 10px 2px #93a1a1; + padding: 0.5em 0.5em; + margin-top: 1em; } + +.note:after { + content: " "; + display: block; + height: 0; + clear: both; } + +.note a { + word-wrap: break-word; } + +.note .e-content p:first-child { + margin-top: 0; } + +.note-metadata { + width: 100%; } + +.social-links { + float: right; } + +.social-links a { + text-decoration: none; } + +.icon { + width: auto; + height: 1em; + fill: #268bd2; } + +.reply { + margin-left: 2em; + margin-right: 2em; + font-size: 0.8em; + padding: 0.5em 0.5em; } + +.reply-to { + margin-left: 2em; + margin-right: 2em; + font-size: 0.8em; + padding-top: 2em; } + +.reply-to + .note { + margin-top: 0.3em; } + +.mini-h-card { + border-radius: 2px; + border: 1px solid #586e75; + padding: 0 0.2em; + text-decoration: none; + margin-right: 5px; + white-space: nowrap; } + +.mini-h-card img { + height: 1.26em; + display: inline; + border-radius: 2px; + vertical-align: text-bottom; } + +.like-photo { + height: 1.26em; } + +.reply .e-content { + margin-top: 0.5em; + padding-left: 0.5em; } + +.notes-subtitle { + font-size: 1em; } + +.note-photo { + width: 100%; + height: auto; + image-orientation: from-image; } + +article header { + margin-top: 0.5em; + margin-bottom: 0.8em; } + +.post-info { + font-size: 0.8em; + font-style: italic; + margin-top: -0.8em; } + +.contact { + position: relative; } + +.contact-links { + list-style-type: none; } + +.contact img { + height: auto; + width: 2em; + position: absolute; + top: 0; + left: 0; } + +.contact-info { + margin-left: 2em; } + +#map { + height: 300px; } + +/* media queries */ +@media (min-width: 700px) { + main { + margin-left: 10em; + margin-right: 10em; } + footer { + margin-left: 13em; + margin-right: 13em; } + .youtube { + width: 640px; + height: 360px; } } + +@media (max-width: 699px) { + main { + margin-left: 10px; + margin-right: 10px; } + article { + word-wrap: break-word; } + footer { + margin-left: 15px; + margin-right: 15px; } + .youtube { + width: 100%; + height: auto; } } + +body { + text-rendering: optimizeLegibility; + -webkit-font-feature-settings: "liga"; + font-feature-settings: "liga"; + font-family: "leitura-news", serif; + font-size: 1.2em; } + +#topheader h1 { + font-family: "leitura-news", serif; } + +h1 { + font-family: "prenton", sans-serif; } + +#topheader a { + text-decoration: none; } + +nav { + -webkit-font-feature-settings: "dlig"; + font-feature-settings: "dlig"; } + +article header h1 a { + text-decoration: none; } + +article div a { + text-decoration: none; } + +footer { + font-size: 0.8em; } + +.emoji { + width: auto; + height: 1em; } + +body { + color: #002b36; } + +header a { + color: #002b36; } + +a { + color: #268bd2; } + +form { + width: 100%; } + +fieldset { + min-width: 0; + width: 100%; } + +input[type="text"], input[type="file"], textarea { + width: 100%; } + +input, button, textarea { + -webkit-appearance: none; + -moz-appearance: none; + background-color: #002b36; + color: #fdf6e3; + border: 1px solid #fdf6e3; + border-radius: 4px; } + +button:hover { + transition: 0.5s ease-in-out; + background-color: #fdf6e3; + color: #002b36; } + +button:disabled { + background-color: #93a1a1; + color: #002b36; } + +input[type="checkbox"] { + -webkit-appearance: checkbox; + -moz-appearance: checkbox; } + +#photo { + background: inherit; + color: inherit; + border: none; } + +.twitter-tweet-rendered { + margin-bottom: 0 !important; } + +.twitter-tweet-rendered + .note { + margin-top: 0; } + +/*# sourceMappingURL=global.css.map */ diff --git a/public/build/assets/css/global-ef9dfef096.css.br b/public/build/assets/css/global-ef9dfef096.css.br new file mode 100644 index 0000000000000000000000000000000000000000..45595e736d1c624c58ed49c9d6fc1b618549843d GIT binary patch literal 1061 zcmV+=1ls!>QV#%}1$H|}5{8~!C~7(EUHHi=r&jF`lAVtf$3>^sm8+Ln(0TYk$O)nV zlnNtl$s*O|`#<*D^IZXlR!q*$O_?S)c_mTD`!6s zy0f3(K1(CXe>$pqzj8Ke`f}nj89Ov1t?u1nuJ%Q0I&4+rq#7GUDz!N=bsivpIa3oMSD=og@on|WH6_pxlFgx^2!|vNyS-|CY!};0pxX3 z84(`SbifyWcKugEyNOE?$v_5`u25%v62}FB=r~E{KBr5LaQfA}FM7p*zX7PEg^;r} zlZlI#3+g&p?iV&d8zbdm7nH0{+R|eODdsMA>O0SWI!y|b^l^O+u)Ofa+`6Ka3h)H9 zO~{~Z6+1LJYREDsaf&RoG+FhEqb{A8#}W>gmigu0lV6eKDY9g+z0am_ zJ~_$oh7u8qe1im(LM`5xXm}S^Ew;VshAEV{Te>p6q0}H2nj+XhraH>xc>`ktt@wEY5(rrM18e>yiWOV%Z z8VrrXaeeoGWyyN<$Ql$>s_3t?D2ipW$*rk%x{7M6-kn@Y=YZT5miZO9qyP)!R9i8YY$UL!&UQHW< zLApd@l(DPm902aqn{`iMA=3uv%>SJGv_uR4`}|=k=W@P&j59#-@>1Fyb-*|0Zdrm7 zqY1RfHHjuC#Ky`bn>Bk8vvs4cK-wn#RIn%lT{~k_v9q%B=N9BfGyq=-w7r=5K|Q)N>dfDRU`fXH-ql zNCO$ozq-Wnt6BKN!VQyWIDMD1e)?WrL?xssBR{V#f{QM$&OQl}cT0a!hwZL0c(3z- zp@j{c&1V7spqjiqplH%y2<)is@(J5zZ#zAhn(7!j>kiiK^(@p73+*<9=BESqmEa(($+XGESSmK}X z8RQtFLOSrBrY(;QB-Iv#10rwZ{KQt6%XVl#r-Cd|9U3v9*OWrT&P^^O2NtvSpq(@= zdAJo7^A`NGFKZ1)wJQsnjBXUAcB0qjZk{=$!~XSbdQu-gr)OMYtjQJgXM*T0QrtdM zm%TDZG3#hhn&0tRYsbk0>KDb?Y!NSS+cVDI*f~EqSzR(?%hB~JLr|#$Y7bennXN~Z zQCBtn*tFIUCk+*opD!aW%TPfhYtE#FfM)cP%P6jijApt#-Lk4cTB#E_?gyeYe~umS z-FiR?<04D5TUd^6EbMT&9b9)EI)GgjX4~bMJcckL+VSWjkPZZDVQL!1#GMRKG6yL- z87oM~zZv-Vz{nju6G;KdCN}%Y&rkB&tMuHC9)`N@R}GHo_^sEY;gXI>K7nb6L|_H& z0Q$z*MLOIoqBpRtj3ue*|7@S$V!N?=9ywFn1U~nnq0Ybm=CcoTWn!tOiF57eu%ER5 M0$th?+EWhz0OYn|rvLx| literal 0 HcmV?d00001 diff --git a/public/build/assets/css/global.css.map b/public/build/assets/css/global.css.map new file mode 100644 index 00000000..fa39372b --- /dev/null +++ b/public/build/assets/css/global.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["global.scss","layout.scss","components/fonts.scss","components/colours.scss","components/forms.scss","components/twitter.scss"],"names":[],"mappings":"AAyBA;EACC,+CAAe,EACf;;AAED;EACC,cAAc,EACd;;AC5BD;EACC,uBAAuB,EACvB;;AAED;EACC,oBAAoB,EACpB;;AAED;EACC,sBAAc;EAAd,qBAAc;EAAd,cAAc;EACd,uBAAe;EAAf,mBAAe;EAAf,eAAe,EACf;;AAED;EACC,mBAAmB,EACnB;;AAED;EACC,mBAAmB,EACnB;;AAED;EACC,kBAAkB,EAClB;;AAED;EACC,0BDhBkB;ECiBlB,iCDlBkB;ECmBlB,qBAAqB;EACrB,gBAAgB,EAChB;;AAED;EACC,aAAa;EACb,eAAe;EACf,UAAU;EACV,YAAY,EACZ;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,cAAc,EACd;;AAED;EACC,YAAY,EACZ;;AAED;EACC,aAAa,EACb;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,YAAY;EACZ,YAAY;EACZ,cD7CkB,EC8ClB;;AAED;EACC,iBAAiB;EACjB,kBAAkB;EAClB,iBAAiB;EACjB,qBAAqB,EACrB;;AAED;EACC,iBAAiB;EACjB,kBAAkB;EAClB,iBAAiB;EACjB,iBAAiB,EACjB;;AAED;EACC,kBAAkB,EAClB;;AAED;EACC,mBAAmB;EACnB,0BD/EkB;ECgFlB,iBAAiB;EACjB,sBAAsB;EACtB,kBAAkB;EAClB,oBAAoB,EACpB;;AAED;EACC,eAAe;EACf,gBAAgB;EAChB,mBAAmB;EACnB,4BAA4B,EAC5B;;AAED;EACC,eAAe,EACf;;AAED;EACC,kBAAkB;EAClB,oBAAoB,EACpB;;AAED;EACC,eAAe,EACf;;AAED;EACC,YAAY;EACZ,aAAa;EACb,8BAA8B,EAC9B;;AAID;EACC,kBAAkB;EAClB,qBAAqB,EACrB;;AAED;EACC,iBAAiB;EACjB,mBAAmB;EACnB,mBAAmB,EACnB;;AAGD;EACC,mBAAmB,EACnB;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,aAAa;EACb,WAAW;EACX,mBAAmB;EACnB,OAAO;EACP,QAAQ,EACR;;AAED;EACC,iBAAiB,EACjB;;AAED;EACC,cAAc,EACd;;AAED,mBAAmB;AACnB;EACC;IACC,kBAAkB;IAClB,mBAAmB,EACnB;EAED;IACC,kBAAkB;IAClB,mBAAmB,EACnB;EAED;IACC,aAAa;IACb,cAAc,EACd,EAAA;;AAGF;EACC;IACC,kBAAkB;IAClB,mBAAmB,EACnB;EAED;IACC,sBAAsB,EACtB;EAED;IACC,kBAAkB;IAClB,mBAAmB,EACnB;EAED;IACC,YAAY;IACZ,aAAa,EACb,EAAA;;ACjMF;EACC,mCAAmC;EACnC,sCAA8B;EAA9B,8BAA8B;EAC9B,mCFFsC;EEGtC,iBAAiB,EACjB;;AAED;EACC,mCFPsC,EEQtC;;AAED;EACC,mCFVyC,EEWzC;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,sCAA8B;EAA9B,8BAA8B,EAC9B;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,sBAAsB,EACtB;;AAED;EACC,iBAAiB,EACjB;;AAED;EACC,YAAY;EACZ,YAAY,EACZ;;ACvCD;EACC,eHKkB,EGJlB;;AAED;EACC,eHCkB,EGAlB;;AAED;EACC,eHUkB,EGTlB;;ACTD;EACC,YAAY,EACZ;;AAED;EACC,aAAa;EACb,YAAY,EACZ;;AAED;EACC,YAAY,EACZ;;AAED;EACC,yBAAyB;EACzB,sBAAsB;EACtB,0BJXkB;EIYlB,eJLkB;EIMlB,0BJNkB;EIOlB,mBAAmB,EACnB;;AAED;EACC,6BAA6B;EAC7B,0BJZkB;EIalB,eJpBkB,EIqBlB;;AAED;EACC,0BJnBkB;EIoBlB,eJzBkB,EI0BlB;;AAED;EACC,6BAA6B;EAC7B,0BAA0B,EAC1B;;AAED;EACC,oBAAoB;EACpB,eAAe;EACf,aAAa,EACb;;AC1CD;EACE,4BAA4B,EAC7B;;AAED;EACE,cAAc,EACf","file":"global.css","sourcesContent":["//global.scss\n\n//variables\n$font-stack-body: \"leitura-news\", serif;\n$font-stack-headers: \"prenton\", sans-serif;\n\n//solarized variables TERMCOL\n$base03: #002b36;//brblack\n$base02: #073642;//black\n$base01: #586e75;//brgreen\n$base00: #657b83;//bryellow\n$base0: #839496;//brblue\n$base1: #93a1a1;//brcyan\n$base2: #eee8d5;//white\n$base3: #fdf6e3;//brwhite\n$yellow: #b58900;\n$orange: #cb4b16;\n$red: #dc322f;\n$magenta: #d33682;\n$violet: #6c71c4;\n$blue: #268bd2;\n$cyan: #2aa198;\n$green: #859900;\n\n//global styles\nhtml {\n\tbackground: url('/assets/img/escheresque.png');\n}\n\n.map {\n\theight: 150px;\n}\n\n//layout\n@import \"layout\";\n\n//components\n@import \"components/fonts\";\n@import \"components/colours\";\n@import \"components/forms\";\n@import \"components/twitter\";\n","//layout.scss\n\n//boxes\nhtml {\n\tbox-sizing: border-box;\n}\n\n*, *:before, *:after {\n\tbox-sizing: inherit;\n}\n\n#topheader {\n\tdisplay: flex;\n\tflex-flow: row;\n}\n\n#topheader a {\n\tpadding: 0.5em 1em;\n}\n\nnav {\n\tpadding-top: 0.5em;\n}\n\n.social-list {\n\tpadding-left: 2em;\n}\n\n.note {\n\tbackground-color: $base2;\n\tbox-shadow: 0 0 10px 2px $base1;\n\tpadding: 0.5em 0.5em;\n\tmargin-top: 1em;\n}\n\n.note:after {\n\tcontent: \" \";\n\tdisplay: block;\n\theight: 0;\n\tclear: both;\n}\n\n.note a {\n\tword-wrap: break-word;\n}\n\n.note .e-content p:first-child {\n\tmargin-top: 0;\n}\n\n.note-metadata {\n\twidth: 100%;\n}\n\n.social-links {\n\tfloat: right;\n}\n\n.social-links a {\n\ttext-decoration: none;\n}\n\n.icon {\n\twidth: auto;\n\theight: 1em;\n\tfill: $blue;\n}\n\n.reply {\n\tmargin-left: 2em;\n\tmargin-right: 2em;\n\tfont-size: 0.8em;\n\tpadding: 0.5em 0.5em;\n}\n\n.reply-to {\n\tmargin-left: 2em;\n\tmargin-right: 2em;\n\tfont-size: 0.8em;\n\tpadding-top: 2em;\n}\n\n.reply-to + .note {\n\tmargin-top: 0.3em;\n}\n\n.mini-h-card {\n\tborder-radius: 2px;\n\tborder: 1px solid $base01;\n\tpadding: 0 0.2em;\n\ttext-decoration: none;\n\tmargin-right: 5px;\n\twhite-space: nowrap;\n}\n\n.mini-h-card img {\n\theight: 1.26em;\n\tdisplay: inline;\n\tborder-radius: 2px;\n\tvertical-align: text-bottom;\n}\n\n.like-photo {\n\theight: 1.26em;\n}\n\n.reply .e-content {\n\tmargin-top: 0.5em;\n\tpadding-left: 0.5em;\n}\n\n.notes-subtitle {\n\tfont-size: 1em;\n}\n\n.note-photo {\n\twidth: 100%;\n\theight: auto;\n\timage-orientation: from-image;\n}\n\n//articles\n\narticle header {\n\tmargin-top: 0.5em;\n\tmargin-bottom: 0.8em;\n}\n\n.post-info {\n\tfont-size: 0.8em;\n\tfont-style: italic;\n\tmargin-top: -0.8em;\n}\n\n//contacts\n.contact {\n\tposition: relative;\n}\n\n.contact-links {\n\tlist-style-type: none;\n}\n\n.contact img {\n\theight: auto;\n\twidth: 2em;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n}\n\n.contact-info {\n\tmargin-left: 2em;\n}\n\n#map {\n\theight: 300px;\n}\n\n/* media queries */\n@media (min-width: 700px) {\n\tmain {\n\t\tmargin-left: 10em;\n\t\tmargin-right: 10em;\n\t}\n\n\tfooter {\n\t\tmargin-left: 13em;\n\t\tmargin-right: 13em;\n\t}\n\n\t.youtube {\n\t\twidth: 640px;\n\t\theight: 360px;\n\t}\n}\n\n@media (max-width: 699px) {\n\tmain {\n\t\tmargin-left: 10px;\n\t\tmargin-right: 10px;\n\t}\n\n\tarticle {\n\t\tword-wrap: break-word;\n\t}\n\n\tfooter {\n\t\tmargin-left: 15px;\n\t\tmargin-right: 15px;\n\t}\n\n\t.youtube {\n\t\twidth: 100%;\n\t\theight: auto;\n\t}\n}\n","//fonts.scss\n\nbody {\n\ttext-rendering: optimizeLegibility;\n\tfont-feature-settings: \"liga\";\n\tfont-family: $font-stack-body;\n\tfont-size: 1.2em;\n}\n\n#topheader h1 {\n\tfont-family: $font-stack-body;\n}\n\nh1 {\n\tfont-family: $font-stack-headers;\n}\n\n#topheader a {\n\ttext-decoration: none;\n}\n\nnav {\n\tfont-feature-settings: \"dlig\";\n}\n\narticle header h1 a {\n\ttext-decoration: none;\n}\n\narticle div a {\n\ttext-decoration: none;\n}\n\nfooter {\n\tfont-size: 0.8em;\n}\n\n.emoji {\n\twidth: auto;\n\theight: 1em;\n}\n","//colours.scss\nbody {\n\tcolor: $base03;\n}\n\nheader a {\n\tcolor: $base03;\n}\n\na {\n\tcolor: $blue;\n}","//forms.scss\n\nform {\n\twidth: 100%;\n}\n\nfieldset {\n\tmin-width: 0;\n\twidth: 100%;\n}\n\ninput[type=\"text\"], input[type=\"file\"], textarea {\n\twidth: 100%;\n}\n\ninput, button, textarea {\n\t-webkit-appearance: none;\n\t-moz-appearance: none;\n\tbackground-color: $base03;\n\tcolor: $base3;\n\tborder: 1px solid $base3;\n\tborder-radius: 4px;\n}\n\nbutton:hover {\n\ttransition: 0.5s ease-in-out;\n\tbackground-color: $base3;\n\tcolor: $base03;\n}\n\nbutton:disabled {\n\tbackground-color: $base1;\n\tcolor: $base03;\n}\n\ninput[type=\"checkbox\"] {\n\t-webkit-appearance: checkbox;\n\t-moz-appearance: checkbox;\n}\n\n#photo {\n\tbackground: inherit;\n\tcolor: inherit;\n\tborder: none;\n}\n","//twitter.scss\n\n.twitter-tweet-rendered {\n margin-bottom: 0 !important;\n}\n\n.twitter-tweet-rendered + .note {\n margin-top: 0;\n}\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/public/build/assets/css/prism-5c98941a94.css b/public/build/assets/css/prism-5c98941a94.css new file mode 100644 index 00000000..86122e46 --- /dev/null +++ b/public/build/assets/css/prism-5c98941a94.css @@ -0,0 +1,188 @@ +/* http://prismjs.com/download.html?themes=prism-dark&languages=markup+css+clike+javascript+git+http+markdown+php+php-extras+scss+sql&plugins=line-numbers+show-invisibles */ +/** + * prism.js Dark theme for JavaScript, CSS and HTML + * Based on the slides of the talk “/Reg(exp){2}lained/” + * @author Lea Verou + */ + +code[class*="language-"], +pre[class*="language-"] { + color: white; + text-shadow: 0 -.1em .2em black; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +pre[class*="language-"], +:not(pre) > code[class*="language-"] { + background: hsl(30, 20%, 25%); +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; + border: .3em solid hsl(30, 20%, 40%); + border-radius: .5em; + box-shadow: 1px 1px .5em black inset; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .15em .2em .05em; + border-radius: .3em; + border: .13em solid hsl(30, 20%, 40%); + box-shadow: 1px 1px .3em -.1em black inset; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: hsl(30, 20%, 50%); +} + +.token.punctuation { + opacity: .7; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol { + color: hsl(350, 40%, 70%); +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: hsl(75, 70%, 60%); +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + color: hsl(40, 90%, 60%); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: hsl(350, 40%, 70%); +} + +.token.regex, +.token.important { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.deleted { + color: red; +} + +pre.line-numbers { + position: relative; + padding-left: 3.8em; + counter-reset: linenumber; +} + +pre.line-numbers > code { + position: relative; +} + +.line-numbers .line-numbers-rows { + position: absolute; + pointer-events: none; + top: 0; + font-size: 100%; + left: -3.8em; + width: 3em; /* works for line-numbers below 1000 lines */ + letter-spacing: -1px; + border-right: 1px solid #999; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + +} + + .line-numbers-rows > span { + pointer-events: none; + display: block; + counter-increment: linenumber; + } + + .line-numbers-rows > span:before { + content: counter(linenumber); + color: #999; + display: block; + padding-right: 0.8em; + text-align: right; + } +.token.tab:not(:empty):before, +.token.cr:before, +.token.lf:before { + color: hsl(24, 20%, 85%); +} + +.token.tab:not(:empty):before { + content: '\21E5'; +} + +.token.cr:before { + content: '\240D'; +} + +.token.crlf:before { + content: '\240D\240A'; +} +.token.lf:before { + content: '\240A'; +} diff --git a/public/build/assets/css/prism-5c98941a94.css.br b/public/build/assets/css/prism-5c98941a94.css.br new file mode 100644 index 0000000000000000000000000000000000000000..101b950898791e187b8df3733867ba96033e3c31 GIT binary patch literal 1095 zcmV-N1i1Sf^bP==gK@KbWXsFq&_oer&Wb|QyINb{k`}QSlZaS@_~ta`5|FcV-{sF^ zR2j3Eek}d0=h0iG<7PTYT9$B<0P&;!8qFmoLO((yL8?2u`%VlKO*=dPAL>mKRYD}v zprS*XP0qF#t%bG+VPeBPg$jA+$cv;^UQ!^crQ}1cCGH}{LCnlq3GurE5A>?Ni1xW3 z(K#>ZX=%EExQ?i@ozQizKNCAbvg(b5QM|KKW^2)B{p-eJrKK|M@TekxdubPrdw0gmB3*?EVdk z!hl%)=_y0?oN?&~6c6A_h#ze_a&>o9FJFhF?*JnQPOCrQH+!uVYKhGLQ?-%Ni$7Tb zffKW&jFctSXo$?n+wbEcOCgluJY@7`ID|PM#s9^N_So@uJ-0r@x;^z3hT&6++)w?V9s-AC#$UQBTU<1Uqpo40al z7t6pUdZ0p;$<*-ArO<^eFenMT0VQ>JDe%CK!jlw93DMdbQWDG6o`_ijkE>Z_IW?qL zUC;2+NN?vGw|0_~v*Z_Ym=%iPO_6|WOLcWAh(*Z!)aZaX{`{m^zS_A)sAp2)n5(g(7BcZ168@ zq%ms?9z?E~Iu~z`kexrW0QFxSONNrw)uBj_q*-2; z|1##b)JaNR1KzV2ehHId+jBUzDRdY?LBBtjU_S*fJ z;Y)68hpvN=BAmMe&t%R}EQWw4;E98gIo2h}r5a@yyl_hFS@?hA;F%*A$w_m=6AMD( zwtf@*>Q}0@7_L)Az7V!r`jgnvoJyhe>?BX&-Q{uoM7_zsqA+FZkc%ee4)KYzZi!!^ z>yG3yZ{;Wo^hB}yB&ZURqJ)TZW*MYl)lOz7w2*4*)=R}4zESYa=a;ZJyyHzS*|Uer zJ0Fs`IK$yhTEB~6%irviS+fX^Tog-|Q`}=Uq;|uQLz(f-bJ|c^=#%m{PQ)pd5d8=- zdI`r!5|#&>ysQz|RG-NIt)Vf9KCh6JBB{nu0~dyjP|Y77K9ZQK2Xb*nj^C0ZBzLEA NR=*^|WM&9DAv$EL9peB1 literal 0 HcmV?d00001 diff --git a/public/build/assets/css/prism-5c98941a94.css.gz b/public/build/assets/css/prism-5c98941a94.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..652d5e2b320f7312b82b4d4b040043b2ae2693f9 GIT binary patch literal 1274 zcmV^1qT?tG{-0AYeNvpBDW2`U_ujFs#7r=FK~9-|kloA8 zNfvNka2zMIZ|Xz(Bz+RH#Gpe`#5^1fa>aD^Q1@e*4HCH)T+*bUV#eRZ6f)4SJ3x?7 zwYk;FJJsK_y!iYVUxEXkDqdC zs3e1zFaEX0Z_xr%6W}wTeyI-;7 zQiWulGK2?vDVoXzI;EysAsLdOKZ1<($L61i(|GBDb15*G(~R+LNZyq~OB1a}K9_>V zvPW*cEfUJXp5-lb{5~oK78l1%3aN7%R{|$YL5xg_kZ@ErLX@+GRlpp*#xW0^n~<1% zD;lX1r(j|c5+PMac}*KBpvz;OyZ;o}BE^u5`m+bEy(-A$qX20XX!ghioO+``Hp>r$ z9=(QW$uLN_c?v>X4#IPHVNUDxDOFAUwAFemgM?Arssbz5ezIluh*!5xQ?u0gJhc>Z zbs|(KB;GdKHhIGnIvp=Eowrc35J^Z<&2LYJJu)8NF#pVMv|X}hio9$5kci88>Auug zXOYt+aSdWx+!N2JS}+lk{tPlQ^m4fZHRm=_TA=juNU8*s!A}fcOU{x*iqoN?SVISj zCaln9kg9UCujVM<*uNIB`}7DC8t@|9kA-bjS3HyLB@60P?~i5|-*$yVSkPjiu8EC9nhLNT0TTxh!_iM z$4!;EoBK_yD5`?PVP#g77hbf4tz8h8 zExLjQY<$hKTq=8&$8N5{{h>FkKr3CsefZs?UGG+s)fwx(F;dRrI@r}MB&E`#53iug zsZiSG20X6<6X4Kz5E4 z@QO0?pqBcYC77Cm7#T6ceJ#~ey9ea~_XxOLTYp0*cWci3MZ?ZNdIB?JkB52LL`Jon z+1Kvhzu)jQDYOBXW2EtUa#pX;sT)+Sr=CE=?Yu!uPSxrB|1QKoD|OE4HY{HTb-iyo zCSnB{h=a!S@CwIQat$LeR|gH0eNcfm)J62$K4kltVts&^JM*B+=3D;~cP%mW{aF81 ze}p@WW9U=A@FMpb2_egI+ul{f?;2H?@cB;CJafm>-SWP-d+ePKtx&QzG literal 0 HcmV?d00001 diff --git a/public/build/assets/css/projects-d945298e4f.css b/public/build/assets/css/projects-d945298e4f.css new file mode 100644 index 00000000..d108175a --- /dev/null +++ b/public/build/assets/css/projects-d945298e4f.css @@ -0,0 +1,10 @@ +#projects { + padding-left: 33.33%; +} + +h3 { + float: left; + width: 45%; + margin: 0 5% 0 -50%; + text-align: right; +} diff --git a/public/build/assets/css/projects-d945298e4f.css.br b/public/build/assets/css/projects-d945298e4f.css.br new file mode 100644 index 0000000000000000000000000000000000000000..1d6b0300e8a4292fa5673557e5559db1ffd88b57 GIT binary patch literal 82 zcmV-Y0ImNUaR2}u1#Y|Xxxy|Q2s(~X>7W~HK^_%hK6XQYDkStJ$PS%O4%mOVeLI#% o5Mf|eFHME%tn)xF*cIjSg8^k8k?%RJz0Oj1j77J%EP!f;C>!YsQqMJX2zqOEPZ$AK=#_+qa2 Z{(V2z+dS$IpU3HL#1w)7WW90#007N+H>Lmp literal 0 HcmV?d00001 diff --git a/public/build/assets/css/sanitize.min-535bccd783.css b/public/build/assets/css/sanitize.min-535bccd783.css new file mode 100644 index 00000000..9d0d9800 --- /dev/null +++ b/public/build/assets/css/sanitize.min-535bccd783.css @@ -0,0 +1,2 @@ +/*! sanitize.css v3.2.0 | CC0 1.0 Public Domain | github.com/10up/sanitize.css */audio:not([controls]){display:none}button{-webkit-appearance:button;overflow:visible}details{display:block}html{-ms-overflow-style:-ms-autohiding-scrollbar;overflow-y:scroll;-webkit-text-size-adjust:100%}input{-webkit-border-radius:0}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button}input[type=number]{width:auto}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}main{display:block}pre{overflow:auto}progress{display:inline-block}small{font-size:75%}summary{display:block}svg:not(:root){overflow:hidden}template{display:none}textarea{overflow:auto}[hidden]{display:none}*,:after,:before{box-sizing:inherit}*{font-size:inherit;line-height:inherit}:after,:before{text-decoration:inherit;vertical-align:inherit}*,:after,:before{border-style:solid;border-width:0}*{background-repeat:no-repeat;margin:0;padding:0}:root{background-color:#fff;box-sizing:border-box;color:#000;cursor:default;font:100%/1.5 sans-serif}a{text-decoration:none}audio,canvas,iframe,img,svg,video{vertical-align:middle}button,input,select,textarea{background-color:transparent;color:inherit;font-family:inherit;font-style:inherit;font-weight:inherit}[type=button],[type=date],[type=datetime-local],[type=datetime],[type=email],[type=month],[type=number],[type=password],[type=reset],[type=search],[type=submit],[type=tel],[type=text],[type=time],[type=url],[type=week],button,select,textarea{min-height:1.5em}code,kbd,pre,samp{font-family:monospace}nav ol,nav ul{list-style:none}select{-moz-appearance:none;-webkit-appearance:none}select::-ms-expand{display:none}select::-ms-value{color:currentColor}table{border-collapse:collapse;border-spacing:0}textarea{resize:vertical}::-moz-selection{background-color:#b3d4fc;color:#fff;text-shadow:none}::selection{background-color:#b3d4fc;color:#fff;text-shadow:none}[aria-busy=true]{cursor:progress}[aria-controls]{cursor:pointer}[aria-disabled]{cursor:default}[hidden][aria-hidden=false]{clip:rect(0 0 0 0);display:inherit;position:absolute}[hidden][aria-hidden=false]:focus{clip:auto}[tabindex],a,area,button,input,label,select,textarea{-ms-touch-action:manipulation;touch-action:manipulation} +/*# sourceMappingURL=sanitize.min.css.map */ \ No newline at end of file diff --git a/public/build/assets/css/sanitize.min-535bccd783.css.br b/public/build/assets/css/sanitize.min-535bccd783.css.br new file mode 100644 index 0000000000000000000000000000000000000000..f20400fdc8d26a6576f8c2d49949b9e9dc4487dd GIT binary patch literal 790 zcmV+x1L^!5O$h*ul5!)$UD5OkUHg!UaOD5Sb zwBC~aO79jFLO%*G(IL&YSEX`TLgzKN-gs0ht1CUk#p#dcxH)WgqyN$Kxf|`@B=3;~ zY1^tqSHE>&^w<5a&bBkOdRtd)K~!_P(;6Vbb#)vcy< z%5jn|kT9hfgP7$|Oi^k1)wxwCES?NhA^W!V_}L)!Am8MKLwkgZe3Zjj<=KZpSGaSp zC{(2D5_diFK2<>X%O4v?D$$jB?>~ zeG2ij!u|+MW7|iBDOJ2+O=d+*abFHJH4?N~$K(7agw>CgLk5J$`%_g-?@HYM~v8S)ft0cOT<9Id~k2>6g zr@ltCK~f^|nH1}#7@6~F#~z`*PLN9lvYF2YtvmMR33T)Tm$swE%cfFkg)An=$qUpA zv*e^-7)zhF`_1{3=NDNK{p6WF_CTm?qe`II-JneZWs?9|9Y@Xq)mCu^*8vkZK$s)u z9A!SyUtMnq(aPau`*utlT!#rDAv!isM7Mdt&2EdzxV-2Kmxn|cK_$xmB2&7t=&b_Y zQOTn!PG1_kCZk7ZT|CjP*3^MvzHbMNwi*6!`^`Bv9J(lmzaWCFh@n&_BcF~MXI*vL z!B#aRm%^VtbxP$8K1Lp3Q{R#>ZXlQACF$64d8B^SK}B(-57)ptioF!h+*6R}@^~!O zNc~5#MP>jj!5LTpHDG%7GNJ*Yw#NYVb8w7KKcR#dV*)iEdOsxMB(;21XeENW>>oD? zR8Ig^@|8}ZOdm(b2Fi!7B$9ydz?bL>0T!ic_uo>TVG)PbYB&1Xv6eAW97T?LEO^p9 zu4^zg$oj~w_l|skflu zhZHE7lDn;n>3xXvM>lVH&=lw;o^kJQtiL+@@~pb?-;F0vsv8&M>G#-3;x~RY3P_Lm z6@@M~XWXdsiz?dlBk4!y5Cs{gO?Ys{jSkL8|MX!m$Xf}!5wCG*VhBd}lMETa%|o;vg^pNuSj;((vn{3rhB-^5ucQ^kFBFO(=-LbR9SDk^Rf&2Pb`~#_-%pDL z%Av<_gz>Ra6rR34?xjW@RfFznzabGiHbt|fdIZP2H>#QP~HPQYh=NKjc2eVx3tz^gc6^mZY&v{9b{SeQR{83H$DwyMvEP zf!m#E_UqNY*O)UVJbY!OBOy=^0oBMH@VNh`6oErH@#!iFJw0ZAR4`}*x`H*>8i##j zwv$(+SB!Lrj>7P0;p>d6_u+I%t1e`|6HSvJi;QN`(W^ilWC@a18T|%NQbVSu_ePSa zXH@E%YILjte!X%gYEe402!UxcpK1keMVeK$1u;#^D6r4tQivOA9J}4NZM_J5HZx-C znW3txnn&lyv%nUj40UUCnxpfJvu~y)<4cc@+5t`@Pnq6tj)H?;gDloBlL;6CG%`=rNS9zevcusp zS5pXSP;w$1?#KSnnge5d=aW$~`VGU>d?mhadA%5|^!VvOm`(DTvCmX+1&*L>qTgKx z7x8I759eX=&J6hxo#}>jKsS>G`6(|VljqsayE3sQ;IakjCrgqnbI8Mk>c;;4u%7FY zXUG~)`@x6C8yN$>OCf6wk3OkQi#k9zrALvTE + * MIT + * + * https://github.com/gregjacobs/Autolinker.js + */ +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Autolinker=b()}):"object"==typeof exports?module.exports=b():a.Autolinker=b()}(this,function(){var a=function(a){a=a||{},this.urls=this.normalizeUrlsCfg(a.urls),this.email="boolean"==typeof a.email?a.email:!0,this.twitter="boolean"==typeof a.twitter?a.twitter:!0,this.phone="boolean"==typeof a.phone?a.phone:!0,this.hashtag=a.hashtag||!1,this.newWindow="boolean"==typeof a.newWindow?a.newWindow:!0,this.stripPrefix="boolean"==typeof a.stripPrefix?a.stripPrefix:!0;var b=this.hashtag;if(b!==!1&&"twitter"!==b&&"facebook"!==b&&"instagram"!==b)throw new Error("invalid `hashtag` cfg - see docs");this.truncate=this.normalizeTruncateCfg(a.truncate),this.className=a.className||"",this.replaceFn=a.replaceFn||null,this.htmlParser=null,this.matchers=null,this.tagBuilder=null};return a.prototype={constructor:a,normalizeUrlsCfg:function(a){return null==a&&(a=!0),"boolean"==typeof a?{schemeMatches:a,wwwMatches:a,tldMatches:a}:{schemeMatches:"boolean"==typeof a.schemeMatches?a.schemeMatches:!0,wwwMatches:"boolean"==typeof a.wwwMatches?a.wwwMatches:!0,tldMatches:"boolean"==typeof a.tldMatches?a.tldMatches:!0}},normalizeTruncateCfg:function(b){return"number"==typeof b?{length:b,location:"end"}:a.Util.defaults(b||{},{length:Number.POSITIVE_INFINITY,location:"end"})},parse:function(a){for(var b=this.getHtmlParser(),c=b.parse(a),d=0,e=[],f=0,g=c.length;g>f;f++){var h=c[f],i=h.getType();if("element"===i&&"a"===h.getTagName())h.isClosing()?d=Math.max(d-1,0):d++;else if("text"===i&&0===d){var j=this.parseText(h.getText(),h.getOffset());e.push.apply(e,j)}}return e=this.compactMatches(e),this.hashtag||(e=e.filter(function(a){return"hashtag"!==a.getType()})),this.email||(e=e.filter(function(a){return"email"!==a.getType()})),this.phone||(e=e.filter(function(a){return"phone"!==a.getType()})),this.twitter||(e=e.filter(function(a){return"twitter"!==a.getType()})),this.urls.schemeMatches||(e=e.filter(function(a){return"url"!==a.getType()||"scheme"!==a.getUrlMatchType()})),this.urls.wwwMatches||(e=e.filter(function(a){return"url"!==a.getType()||"www"!==a.getUrlMatchType()})),this.urls.tldMatches||(e=e.filter(function(a){return"url"!==a.getType()||"tld"!==a.getUrlMatchType()})),e},compactMatches:function(a){a.sort(function(a,b){return a.getOffset()-b.getOffset()});for(var b=0;be;e++){for(var g=c[e].parseMatches(a),h=0,i=g.length;i>h;h++)g[h].setOffset(b+g[h].getOffset());d.push.apply(d,g)}return d},link:function(a){if(!a)return"";for(var b=this.parse(a),c=[],d=0,e=0,f=b.length;f>e;e++){var g=b[e];c.push(a.substring(d,g.getOffset())),c.push(this.createMatchReturnVal(g)),d=g.getOffset()+g.getMatchedText().length}return c.push(a.substring(d)),c.join("")},createMatchReturnVal:function(b){var c;if(this.replaceFn&&(c=this.replaceFn.call(this,this,b)),"string"==typeof c)return c;if(c===!1)return b.getMatchedText();if(c instanceof a.HtmlTag)return c.toAnchorString();var d=this.getTagBuilder(),e=d.build(b);return e.toAnchorString()},getHtmlParser:function(){var b=this.htmlParser;return b||(b=this.htmlParser=new a.htmlParser.HtmlParser),b},getMatchers:function(){if(this.matchers)return this.matchers;var b=a.matcher,c=[new b.Hashtag({serviceName:this.hashtag}),new b.Email,new b.Phone,new b.Twitter,new b.Url({stripPrefix:this.stripPrefix})];return this.matchers=c},getTagBuilder:function(){var b=this.tagBuilder;return b||(b=this.tagBuilder=new a.AnchorTagBuilder({newWindow:this.newWindow,truncate:this.truncate,className:this.className})),b}},a.link=function(b,c){var d=new a(c);return d.link(b)},a.match={},a.matcher={},a.htmlParser={},a.truncate={},a.Util={abstractMethod:function(){throw"abstract"},trimRegex:/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,assign:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},defaults:function(a,b){for(var c in b)b.hasOwnProperty(c)&&void 0===a[c]&&(a[c]=b[c]);return a},extend:function(b,c){var d=b.prototype,e=function(){};e.prototype=d;var f;f=c.hasOwnProperty("constructor")?c.constructor:function(){d.constructor.apply(this,arguments)};var g=f.prototype=new e;return g.constructor=f,g.superclass=d,delete c.constructor,a.Util.assign(g,c),f},ellipsis:function(a,b,c){return a.length>b&&(c=null==c?"..":c,a=a.substring(0,b-c.length)+c),a},indexOf:function(a,b){if(Array.prototype.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},splitAndCapture:function(a,b){if(!b.global)throw new Error("`splitRegex` must have the 'g' flag set");for(var c,d=[],e=0;c=b.exec(a);)d.push(a.substring(e,c.index)),d.push(c[0]),e=c.index+c[0].length;return d.push(a.substring(e)),d},trim:function(a){return a.replace(this.trimRegex,"")}},a.HtmlTag=a.Util.extend(Object,{whitespaceRegex:/\s+/,constructor:function(b){a.Util.assign(this,b),this.innerHtml=this.innerHtml||this.innerHTML},setTagName:function(a){return this.tagName=a,this},getTagName:function(){return this.tagName||""},setAttr:function(a,b){var c=this.getAttrs();return c[a]=b,this},getAttr:function(a){return this.getAttrs()[a]},setAttrs:function(b){var c=this.getAttrs();return a.Util.assign(c,b),this},getAttrs:function(){return this.attrs||(this.attrs={})},setClass:function(a){return this.setAttr("class",a)},addClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);c=h.shift();)-1===f(g,c)&&g.push(c);return this.getAttrs()["class"]=g.join(" "),this},removeClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);g.length&&(c=h.shift());){var i=f(g,c);-1!==i&&g.splice(i,1)}return this.getAttrs()["class"]=g.join(" "),this},getClass:function(){return this.getAttrs()["class"]||""},hasClass:function(a){return-1!==(" "+this.getClass()+" ").indexOf(" "+a+" ")},setInnerHtml:function(a){return this.innerHtml=a,this},getInnerHtml:function(){return this.innerHtml||""},toAnchorString:function(){var a=this.getTagName(),b=this.buildAttrsStr();return b=b?" "+b:"",["<",a,b,">",this.getInnerHtml(),""].join("")},buildAttrsStr:function(){if(!this.attrs)return"";var a=this.getAttrs(),b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c+'="'+a[c]+'"');return b.join(" ")}}),a.RegexLib=function(){var a="A-Za-zªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢴऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡૹଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘ-ౚౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎↃↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々〆〱-〵〻〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ",b="0-9٠-٩۰-۹߀-߉०-९০-৯੦-੯૦-૯୦-୯௦-௯౦-౯೦-೯൦-൯෦-෯๐-๙໐-໙༠-༩၀-၉႐-႙០-៩᠐-᠙᥆-᥏᧐-᧙᪀-᪉᪐-᪙᭐-᭙᮰-᮹᱀-᱉᱐-᱙꘠-꘩꣐-꣙꤀-꤉꧐-꧙꧰-꧹꩐-꩙꯰-꯹0-9",c=a+b,d=new RegExp("["+c+".\\-]*["+c+"\\-]"),e=/(?:international|construction|contractors|enterprises|photography|productions|foundation|immobilien|industries|management|properties|technology|christmas|community|directory|education|equipment|institute|marketing|solutions|vacations|bargains|boutique|builders|catering|cleaning|clothing|computer|democrat|diamonds|graphics|holdings|lighting|partners|plumbing|supplies|training|ventures|academy|careers|company|cruises|domains|exposed|flights|florist|gallery|guitars|holiday|kitchen|neustar|okinawa|recipes|rentals|reviews|shiksha|singles|support|systems|agency|berlin|camera|center|coffee|condos|dating|estate|events|expert|futbol|kaufen|luxury|maison|monash|museum|nagoya|photos|repair|report|social|supply|tattoo|tienda|travel|viajes|villas|vision|voting|voyage|actor|build|cards|cheap|codes|dance|email|glass|house|mango|ninja|parts|photo|press|shoes|solar|today|tokyo|tools|watch|works|aero|arpa|asia|best|bike|blue|buzz|camp|club|cool|coop|farm|fish|gift|guru|info|jobs|kiwi|kred|land|limo|link|menu|mobi|moda|name|pics|pink|post|qpon|rich|ruhr|sexy|tips|vote|voto|wang|wien|wiki|zone|bar|bid|biz|cab|cat|ceo|com|edu|gov|int|kim|mil|net|onl|org|pro|pub|red|tel|uno|wed|xxx|xyz|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)\b/;return{alphaNumericCharsStr:c,domainNameRegex:d,tldRegex:e}}(),a.AnchorTagBuilder=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},build:function(b){return new a.HtmlTag({tagName:"a",attrs:this.createAttrs(b.getType(),b.getAnchorHref()),innerHtml:this.processAnchorText(b.getAnchorText())})},createAttrs:function(a,b){var c={href:b},d=this.createCssClass(a);return d&&(c["class"]=d),this.newWindow&&(c.target="_blank"),c},createCssClass:function(a){var b=this.className;return b?b+" "+b+"-"+a:""},processAnchorText:function(a){return a=this.doTruncate(a)},doTruncate:function(b){var c=this.truncate;if(!c)return b;var d=c.length,e=c.location;return"smart"===e?a.truncate.TruncateSmart(b,d,".."):"middle"===e?a.truncate.TruncateMiddle(b,d,".."):a.truncate.TruncateEnd(b,d,"..")}}),a.htmlParser.HtmlParser=a.Util.extend(Object,{htmlRegex:function(){var a=/!--([\s\S]+?)--/,b=/[0-9a-zA-Z][0-9a-zA-Z:]*/,c=/[^\s\0"'>\/=\x01-\x1F\x7F]+/,d=/(?:"[^"]*?"|'[^']*?'|[^'"=<>`\s]+)/,e=c.source+"(?:\\s*=\\s*"+d.source+")?";return new RegExp(["(?:","<(!DOCTYPE)","(?:","\\s+","(?:",e,"|",d.source+")",")*",">",")","|","(?:","<(/)?","(?:",a.source,"|","(?:","("+b.source+")","(?:","\\s+",e,")*","\\s*/?",")",")",">",")"].join(""),"gi")}(),htmlCharacterEntitiesRegex:/( | |<|<|>|>|"|"|')/gi,parse:function(a){for(var b,c,d=this.htmlRegex,e=0,f=[];null!==(b=d.exec(a));){var g=b[0],h=b[3],i=b[1]||b[4],j=!!b[2],k=b.index,l=a.substring(e,k);l&&(c=this.parseTextAndEntityNodes(e,l),f.push.apply(f,c)),f.push(h?this.createCommentNode(k,g,h):this.createElementNode(k,g,i,j)),e=k+g.length}if(ef;f+=2){var h=e[f],i=e[f+1];h&&(d.push(this.createTextNode(b,h)),b+=h.length),i&&(d.push(this.createEntityNode(b,i)),b+=i.length)}return d},createCommentNode:function(b,c,d){return new a.htmlParser.CommentNode({offset:b,text:c,comment:a.Util.trim(d)})},createElementNode:function(b,c,d,e){return new a.htmlParser.ElementNode({offset:b,text:c,tagName:d.toLowerCase(),closing:e})},createEntityNode:function(b,c){return new a.htmlParser.EntityNode({offset:b,text:c})},createTextNode:function(b,c){return new a.htmlParser.TextNode({offset:b,text:c})}}),a.htmlParser.HtmlNode=a.Util.extend(Object,{offset:void 0,text:void 0,constructor:function(b){if(a.Util.assign(this,b),null==this.offset)throw new Error("`offset` cfg required");if(null==this.text)throw new Error("`text` cfg required")},getType:a.Util.abstractMethod,getOffset:function(){return this.offset},getText:function(){return this.text}}),a.htmlParser.CommentNode=a.Util.extend(a.htmlParser.HtmlNode,{comment:"",getType:function(){return"comment"},getComment:function(){return this.comment}}),a.htmlParser.ElementNode=a.Util.extend(a.htmlParser.HtmlNode,{tagName:"",closing:!1,getType:function(){return"element"},getTagName:function(){return this.tagName},isClosing:function(){return this.closing}}),a.htmlParser.EntityNode=a.Util.extend(a.htmlParser.HtmlNode,{getType:function(){return"entity"}}),a.htmlParser.TextNode=a.Util.extend(a.htmlParser.HtmlNode,{getType:function(){return"text"}}),a.match.Match=a.Util.extend(Object,{constructor:function(a,b){if(null==a)throw new Error("`matchedText` arg required");if(null==b)throw new Error("`offset` arg required");this.matchedText=a,this.offset=b},getType:a.Util.abstractMethod,getMatchedText:function(){return this.matchedText},setOffset:function(a){this.offset=a},getOffset:function(){return this.offset},getAnchorHref:a.Util.abstractMethod,getAnchorText:a.Util.abstractMethod}),a.match.Email=a.Util.extend(a.match.Match,{constructor:function(b,c,d){if(a.match.Match.prototype.constructor.call(this,b,c),!d)throw new Error("`email` arg required");this.email=d},getType:function(){return"email"},getEmail:function(){return this.email},getAnchorHref:function(){return"mailto:"+this.email},getAnchorText:function(){return this.email}}),a.match.Hashtag=a.Util.extend(a.match.Match,{constructor:function(b,c,d,e){if(a.match.Match.prototype.constructor.call(this,b,c),!e)throw new Error("`hashtag` arg required");this.serviceName=d,this.hashtag=e},getType:function(){return"hashtag"},getServiceName:function(){return this.serviceName},getHashtag:function(){return this.hashtag},getAnchorHref:function(){var a=this.serviceName,b=this.hashtag;switch(a){case"twitter":return"https://twitter.com/hashtag/"+b;case"facebook":return"https://www.facebook.com/hashtag/"+b;case"instagram":return"https://instagram.com/explore/tags/"+b;default:throw new Error("Unknown service name to point hashtag to: ",a)}},getAnchorText:function(){return"#"+this.hashtag}}),a.match.Phone=a.Util.extend(a.match.Match,{constructor:function(b,c,d,e){if(a.match.Match.prototype.constructor.call(this,b,c),!d)throw new Error("`number` arg required");if(null==e)throw new Error("`plusSign` arg required");this.number=d,this.plusSign=e},getType:function(){return"phone"},getNumber:function(){return this.number},getAnchorHref:function(){return"tel:"+(this.plusSign?"+":"")+this.number},getAnchorText:function(){return this.matchedText}}),a.match.Twitter=a.Util.extend(a.match.Match,{constructor:function(b,c,d){if(a.match.Match.prototype.constructor.call(this,b,c),!d)throw new Error("`twitterHandle` arg required");this.twitterHandle=d},getType:function(){return"twitter"},getTwitterHandle:function(){return this.twitterHandle},getAnchorHref:function(){return"https://twitter.com/"+this.twitterHandle},getAnchorText:function(){return"@"+this.twitterHandle}}),a.match.Url=a.Util.extend(a.match.Match,{constructor:function(b,c,d,e,f,g,h){if(a.match.Match.prototype.constructor.call(this,b,c),"scheme"!==e&&"www"!==e&&"tld"!==e)throw new Error('`urlMatchType` must be one of: "scheme", "www", or "tld"');if(!d)throw new Error("`url` arg required");if(null==f)throw new Error("`protocolUrlMatch` arg required");if(null==g)throw new Error("`protocolRelativeMatch` arg required");if(null==h)throw new Error("`stripPrefix` arg required");this.urlMatchType=e,this.url=d,this.protocolUrlMatch=f,this.protocolRelativeMatch=g,this.stripPrefix=h},urlPrefixRegex:/^(https?:\/\/)?(www\.)?/i,protocolRelativeRegex:/^\/\//,protocolPrepended:!1,getType:function(){return"url"},getUrlMatchType:function(){return this.urlMatchType},getUrl:function(){var a=this.url;return this.protocolRelativeMatch||this.protocolUrlMatch||this.protocolPrepended||(a=this.url="http://"+a,this.protocolPrepended=!0),a},getAnchorHref:function(){var a=this.getUrl();return a.replace(/&/g,"&")},getAnchorText:function(){var a=this.getMatchedText();return this.protocolRelativeMatch&&(a=this.stripProtocolRelativePrefix(a)),this.stripPrefix&&(a=this.stripUrlPrefix(a)),a=this.removeTrailingSlash(a)},stripUrlPrefix:function(a){return a.replace(this.urlPrefixRegex,"")},stripProtocolRelativePrefix:function(a){return a.replace(this.protocolRelativeRegex,"")},removeTrailingSlash:function(a){return"/"===a.charAt(a.length-1)&&(a=a.slice(0,-1)),a}}),a.matcher.Matcher=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},parseMatches:a.Util.abstractMethod}),a.matcher.Email=a.Util.extend(a.matcher.Matcher,{matcherRegex:function(){var b=a.RegexLib.alphaNumericCharsStr,c=new RegExp("["+b+"\\-;:&=+$.,]+@"),d=a.RegexLib.domainNameRegex,e=a.RegexLib.tldRegex;return new RegExp([c.source,d.source,"\\.",e.source].join(""),"gi")}(),parseMatches:function(b){for(var c,d=this.matcherRegex,e=[];null!==(c=d.exec(b));){var f=c[0];e.push(new a.match.Email(f,c.index,f))}return e}}),a.matcher.Hashtag=a.Util.extend(a.matcher.Matcher,{matcherRegex:new RegExp("#[_"+a.RegexLib.alphaNumericCharsStr+"]{1,139}","g"),nonWordCharRegex:new RegExp("[^"+a.RegexLib.alphaNumericCharsStr+"]"),constructor:function(){a.matcher.Matcher.prototype.constructor.apply(this,arguments)},parseMatches:function(b){for(var c,d=this.matcherRegex,e=this.nonWordCharRegex,f=this.serviceName,g=[];null!==(c=d.exec(b));){var h=c.index,i=b.charAt(h-1);if(0===h||e.test(i)){var j=c[0],k=c[0].slice(1);g.push(new a.match.Hashtag(j,h,f,k))}}return g}}),a.matcher.Phone=a.Util.extend(a.matcher.Matcher,{matcherRegex:/(?:(\+)?\d{1,3}[-\040.])?\(?\d{3}\)?[-\040.]?\d{3}[-\040.]\d{4}/g,parseMatches:function(b){for(var c,d=this.matcherRegex,e=[];null!==(c=d.exec(b));){var f=c[0],g=f.replace(/\D/g,""),h=!!c[1];e.push(new a.match.Phone(f,c.index,g,h))}return e}}),a.matcher.Twitter=a.Util.extend(a.matcher.Matcher,{matcherRegex:new RegExp("@[_"+a.RegexLib.alphaNumericCharsStr+"]{1,20}","g"),nonWordCharRegex:new RegExp("[^"+a.RegexLib.alphaNumericCharsStr+"]"),parseMatches:function(b){for(var c,d=this.matcherRegex,e=this.nonWordCharRegex,f=[];null!==(c=d.exec(b));){var g=c.index,h=b.charAt(g-1);if(0===g||e.test(h)){var i=c[0],j=c[0].slice(1);f.push(new a.match.Twitter(i,g,j))}}return f}}),a.matcher.Url=a.Util.extend(a.matcher.Matcher,{matcherRegex:function(){var b=/(?:[A-Za-z][-.+A-Za-z0-9]*:(?![A-Za-z][-.+A-Za-z0-9]*:\/\/)(?!\d+\/?)(?:\/\/)?)/,c=/(?:www\.)/,d=a.RegexLib.domainNameRegex,e=a.RegexLib.tldRegex,f=a.RegexLib.alphaNumericCharsStr,g=new RegExp("["+f+"\\-+&@#/%=~_()|'$*\\[\\]?!:,.;]*["+f+"\\-+&@#/%=~_()|'$*\\[\\]]");return new RegExp(["(?:","(",b.source,d.source,")","|","(","(//)?",c.source,d.source,")","|","(","(//)?",d.source+"\\.",e.source,")",")","(?:"+g.source+")?"].join(""),"gi")}(),wordCharRegExp:/\w/,openParensRe:/\(/g,closeParensRe:/\)/g,constructor:function(){if(a.matcher.Matcher.prototype.constructor.apply(this,arguments),null==this.stripPrefix)throw new Error("`stripPrefix` cfg required")},parseMatches:function(b){for(var c,d=this.matcherRegex,e=this.stripPrefix,f=[];null!==(c=d.exec(b));){var g=c[0],h=c[1],i=c[2],j=c[3],k=c[5],l=c.index,m=j||k,n=b.charAt(l-1);if(a.matcher.UrlMatchValidator.isValid(g,h)&&!(l>0&&"@"===n||l>0&&m&&this.wordCharRegExp.test(n))){if(this.matchHasUnbalancedClosingParen(g))g=g.substr(0,g.length-1);else{var o=this.matchHasInvalidCharAfterTld(g,h);o>-1&&(g=g.substr(0,o))}var p=h?"scheme":i?"www":"tld",q=!!h;f.push(new a.match.Url(g,l,g,p,q,!!m,e))}}return f},matchHasUnbalancedClosingParen:function(a){var b=a.charAt(a.length-1);if(")"===b){var c=a.match(this.openParensRe),d=a.match(this.closeParensRe),e=c&&c.length||0,f=d&&d.length||0;if(f>e)return!0}return!1},matchHasInvalidCharAfterTld:function(a,b){if(!a)return-1;var c=0;b&&(c=a.indexOf(":"),a=a.slice(c));var d=/^((.?\/\/)?[A-Za-z0-9\u00C0-\u017F\.\-]*[A-Za-z0-9\u00C0-\u017F\-]\.[A-Za-z]+)/,e=d.exec(a);return null===e?-1:(c+=e[1].length,a=a.slice(e[1].length),/^[^.A-Za-z:\/?#]/.test(a)?c:-1)}}),a.matcher.UrlMatchValidator={hasFullProtocolRegex:/^[A-Za-z][-.+A-Za-z0-9]*:\/\//,uriSchemeRegex:/^[A-Za-z][-.+A-Za-z0-9]*:/,hasWordCharAfterProtocolRegex:/:[^\s]*?[A-Za-z\u00C0-\u017F]/,isValid:function(a,b){return b&&!this.isValidUriScheme(b)||this.urlMatchDoesNotHaveProtocolOrDot(a,b)||this.urlMatchDoesNotHaveAtLeastOneWordChar(a,b)?!1:!0},isValidUriScheme:function(a){var b=a.match(this.uriSchemeRegex)[0].toLowerCase();return"javascript:"!==b&&"vbscript:"!==b},urlMatchDoesNotHaveProtocolOrDot:function(a,b){return!(!a||b&&this.hasFullProtocolRegex.test(b)||-1!==a.indexOf("."))},urlMatchDoesNotHaveAtLeastOneWordChar:function(a,b){return a&&b?!this.hasWordCharAfterProtocolRegex.test(a):!1}},a.truncate.TruncateEnd=function(b,c,d){return a.Util.ellipsis(b,c,d)},a.truncate.TruncateMiddle=function(a,b,c){if(a.length<=b)return a;var d=b-c.length,e="";return d>0&&(e=a.substr(-1*Math.floor(d/2))),(a.substr(0,Math.ceil(d/2))+c+e).substr(0,b)},a.truncate.TruncateSmart=function(a,b,c){var d=function(a){var b={},c=a,d=c.match(/^([a-z]+):\/\//i);return d&&(b.scheme=d[1],c=c.substr(d[0].length)),d=c.match(/^(.*?)(?=(\?|#|\/|$))/i),d&&(b.host=d[1],c=c.substr(d[0].length)),d=c.match(/^\/(.*?)(?=(\?|#|$))/i),d&&(b.path=d[1],c=c.substr(d[0].length)),d=c.match(/^\?(.*?)(?=(#|$))/i),d&&(b.query=d[1],c=c.substr(d[0].length)),d=c.match(/^#(.*?)$/i),d&&(b.fragment=d[1]),b},e=function(a){var b="";return a.scheme&&a.host&&(b+=a.scheme+"://"),a.host&&(b+=a.host),a.path&&(b+="/"+a.path),a.query&&(b+="?"+a.query),a.fragment&&(b+="#"+a.fragment),b},f=function(a,b){var d=b/2,e=Math.ceil(d),f=-1*Math.floor(d),g="";return 0>f&&(g=a.substr(f)),a.substr(0,e)+c+g};if(a.length<=b)return a;var g=b-c.length,h=d(a);if(h.query){var i=h.query.match(/^(.*?)(?=(\?|\#))(.*?)$/i);i&&(h.query=h.query.substr(0,i[1].length),a=e(h))}if(a.length<=b)return a;if(h.host&&(h.host=h.host.replace(/^www\./,""),a=e(h)),a.length<=b)return a;var j="";if(h.host&&(j+=h.host),j.length>=g)return h.host.length==b?(h.host.substr(0,b-c.length)+c).substr(0,b):f(j,g).substr(0,b);var k="";if(h.path&&(k+="/"+h.path),h.query&&(k+="?"+h.query),k){if((j+k).length>=g){if((j+k).length==b)return(j+k).substr(0,b);var l=g-j.length;return(j+f(k,l)).substr(0,b)}j+=k}if(h.fragment){var m="#"+h.fragment;if((j+m).length>=g){if((j+m).length==b)return(j+m).substr(0,b);var n=g-j.length;return(j+f(m,n)).substr(0,b)}j+=m}if(h.scheme&&h.host){var o=h.scheme+"://";if((j+o).length0&&(p=j.substr(-1*Math.floor(g/2))),(j.substr(0,Math.ceil(g/2))+c+p).substr(0,b)},a}); \ No newline at end of file diff --git a/public/build/assets/js/Autolinker.min-b46556773a.js.br b/public/build/assets/js/Autolinker.min-b46556773a.js.br new file mode 100644 index 0000000000000000000000000000000000000000..2b8b84f719e0526700abcf058cb96500d70c9500 GIT binary patch literal 7715 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 H8eaeap%rm_ literal 0 HcmV?d00001 diff --git a/public/build/assets/js/alertify-269e23cb46.js b/public/build/assets/js/alertify-269e23cb46.js new file mode 100644 index 00000000..d9d6a2b2 --- /dev/null +++ b/public/build/assets/js/alertify-269e23cb46.js @@ -0,0 +1 @@ +!function(){"use strict";function t(){var t={version:"1.0.8",defaultOkLabel:"Ok",okLabel:"Ok",defaultCancelLabel:"Cancel",cancelLabel:"Cancel",defaultMaxLogItems:2,maxLogItems:2,promptValue:"",promptPlaceholder:"",closeLogOnClick:!1,closeLogOnClickDefault:!1,delay:5e3,defaultDelay:5e3,logContainerClass:"alertify-logs",logContainerDefaultClass:"alertify-logs",dialogs:{buttons:{holder:"",ok:"",cancel:""},input:"",message:"

    {{message}}

    ",log:"
    {{message}}
    "},defaultDialogs:{buttons:{holder:"",ok:"",cancel:""},input:"",message:"

    {{message}}

    ",log:"
    {{message}}
    "},build:function(t){var e=this.dialogs.buttons.ok,o="
    "+this.dialogs.message.replace("{{message}}",t.message);return"confirm"!==t.type&&"prompt"!==t.type||(e=this.dialogs.buttons.cancel+this.dialogs.buttons.ok),"prompt"===t.type&&(o+=this.dialogs.input),o=(o+this.dialogs.buttons.holder+"
    ").replace("{{buttons}}",e).replace("{{ok}}",this.okLabel).replace("{{cancel}}",this.cancelLabel)},setCloseLogOnClick:function(t){this.closeLogOnClick=!!t},close:function(t,e){this.closeLogOnClick&&t.addEventListener("click",function(t){o(t.srcElement)}),e=e&&!isNaN(+e)?+e:this.delay,0>e?o(t):e>0&&setTimeout(function(){o(t)},e)},dialog:function(t,e,o,n){return this.setup({type:e,message:t,onOkay:o,onCancel:n})},log:function(t,e,o){var n=document.querySelectorAll(".alertify-logs > div");if(n){var i=n.length-this.maxLogItems;if(i>=0)for(var a=0,l=i+1;l>a;a++)this.close(n[a],-1)}this.notify(t,e,o)},setLogPosition:function(t){this.logContainerClass="alertify-logs "+t},setupLogContainer:function(){var t=document.querySelector(".alertify-logs"),e=this.logContainerClass;return t||(t=document.createElement("div"),t.className=e,document.body.appendChild(t)),t.className!==e&&(t.className=e),t},notify:function(e,o,n){var i=this.setupLogContainer(),a=document.createElement("div");a.className=o||"default",t.logTemplateMethod?a.innerHTML=t.logTemplateMethod(e):a.innerHTML=e,"function"==typeof n&&a.addEventListener("click",n),i.appendChild(a),setTimeout(function(){a.className+=" show"},10),this.close(a,this.delay)},setup:function(t){function e(e){"function"!=typeof e&&(e=function(){}),i&&i.addEventListener("click",function(i){t.onOkay&&"function"==typeof t.onOkay&&(l?t.onOkay(l.value,i):t.onOkay(i)),e(l?{buttonClicked:"ok",inputValue:l.value,event:i}:{buttonClicked:"ok",event:i}),o(n)}),a&&a.addEventListener("click",function(i){t.onCancel&&"function"==typeof t.onCancel&&t.onCancel(i),e({buttonClicked:"cancel",event:i}),o(n)})}var n=document.createElement("div");n.className="alertify hide",n.innerHTML=this.build(t);var i=n.querySelector(".ok"),a=n.querySelector(".cancel"),l=n.querySelector("input"),s=n.querySelector("label");l&&("string"==typeof this.promptPlaceholder&&(s?s.textContent=this.promptPlaceholder:l.placeholder=this.promptPlaceholder),"string"==typeof this.promptValue&&(l.value=this.promptValue));var r;return"function"==typeof Promise?r=new Promise(e):e(),document.body.appendChild(n),setTimeout(function(){n.classList.remove("hide"),l&&t.type&&"prompt"===t.type?(l.select(),l.focus()):i&&i.focus()},100),r},okBtn:function(t){return this.okLabel=t,this},setDelay:function(t){var e=parseInt(t||0,10);return this.delay=isNaN(e)?this.defultDelay:t,this},cancelBtn:function(t){return this.cancelLabel=t,this},setMaxLogItems:function(t){this.maxLogItems=parseInt(t||this.defaultMaxLogItems)},theme:function(t){switch(t.toLowerCase()){case"bootstrap":this.dialogs.buttons.ok="",this.dialogs.buttons.cancel="",this.dialogs.input="";break;case"purecss":this.dialogs.buttons.ok="",this.dialogs.buttons.cancel="";break;case"mdl":case"material-design-light":this.dialogs.buttons.ok="",this.dialogs.buttons.cancel="",this.dialogs.input="
    ";break;case"angular-material":this.dialogs.buttons.ok="",this.dialogs.buttons.cancel="",this.dialogs.input="
    ";break;case"default":default:this.dialogs.buttons.ok=this.defaultDialogs.buttons.ok,this.dialogs.buttons.cancel=this.defaultDialogs.buttons.cancel,this.dialogs.input=this.defaultDialogs.input}},reset:function(){this.theme("default"),this.okBtn(this.defaultOkLabel),this.cancelBtn(this.defaultCancelLabel),this.setMaxLogItems(),this.promptValue="",this.promptPlaceholder="",this.delay=this.defaultDelay,this.setCloseLogOnClick(this.closeLogOnClickDefault),this.setLogPosition("bottom left"),this.logTemplateMethod=null},injectCSS:function(){if(!document.querySelector("#alertifyCSS")){var t=document.getElementsByTagName("head")[0],e=document.createElement("style");e.type="text/css",e.id="alertifyCSS",e.innerHTML=".alertify-logs>*{padding:12px 24px;color:#fff;box-shadow:0 2px 5px 0 rgba(0,0,0,.2);border-radius:1px}.alertify-logs>*,.alertify-logs>.default{background:rgba(0,0,0,.8)}.alertify-logs>.error{background:rgba(244,67,54,.8)}.alertify-logs>.success{background:rgba(76,175,80,.9)}.alertify{position:fixed;background-color:rgba(0,0,0,.3);left:0;right:0;top:0;bottom:0;width:100%;height:100%;z-index:2}.alertify.hide{opacity:0;pointer-events:none}.alertify,.alertify.show{box-sizing:border-box;transition:all .33s cubic-bezier(.25,.8,.25,1)}.alertify,.alertify *{box-sizing:border-box}.alertify .dialog{padding:12px}.alertify .alert,.alertify .dialog{width:100%;margin:0 auto;position:relative;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.alertify .alert>*,.alertify .dialog>*{width:400px;max-width:95%;margin:0 auto;text-align:center;padding:12px;background:#fff;box-shadow:0 2px 4px -1px rgba(0,0,0,.14),0 4px 5px 0 rgba(0,0,0,.098),0 1px 10px 0 rgba(0,0,0,.084)}.alertify .alert .msg,.alertify .dialog .msg{padding:12px;margin-bottom:12px;margin:0;text-align:left}.alertify .alert input:not(.form-control),.alertify .dialog input:not(.form-control){margin-bottom:15px;width:100%;font-size:100%;padding:12px}.alertify .alert input:not(.form-control):focus,.alertify .dialog input:not(.form-control):focus{outline-offset:-2px}.alertify .alert nav,.alertify .dialog nav{text-align:right}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button),.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button){background:transparent;box-sizing:border-box;color:rgba(0,0,0,.87);position:relative;outline:0;border:0;display:inline-block;-webkit-align-items:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center;padding:0 6px;margin:6px 8px;line-height:36px;min-height:36px;white-space:nowrap;min-width:88px;text-align:center;text-transform:uppercase;font-size:14px;text-decoration:none;cursor:pointer;border:1px solid transparent;border-radius:2px}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover{background-color:rgba(0,0,0,.05)}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus{border:1px solid rgba(0,0,0,.1)}.alertify .alert nav button.btn,.alertify .dialog nav button.btn{margin:6px 4px}.alertify-logs{position:fixed;z-index:1}.alertify-logs.bottom,.alertify-logs:not(.top){bottom:16px}.alertify-logs.left,.alertify-logs:not(.right){left:16px}.alertify-logs.left>*,.alertify-logs:not(.right)>*{float:left;-webkit-transform:translateZ(0);transform:translateZ(0);height:auto}.alertify-logs.left>.show,.alertify-logs:not(.right)>.show{left:0}.alertify-logs.left>*,.alertify-logs.left>.hide,.alertify-logs:not(.right)>*,.alertify-logs:not(.right)>.hide{left:-110%}.alertify-logs.right{right:16px}.alertify-logs.right>*{float:right;-webkit-transform:translateZ(0);transform:translateZ(0)}.alertify-logs.right>.show{right:0;opacity:1}.alertify-logs.right>*,.alertify-logs.right>.hide{right:-110%;opacity:0}.alertify-logs.top{top:0}.alertify-logs>*{box-sizing:border-box;transition:all .4s cubic-bezier(.25,.8,.25,1);position:relative;clear:both;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000;max-height:0;margin:0;padding:0;overflow:hidden;opacity:0;pointer-events:none}.alertify-logs>.show{margin-top:12px;opacity:1;max-height:1000px;padding:12px;pointer-events:auto}",t.insertBefore(e,t.firstChild)}},removeCSS:function(){var t=document.querySelector("#alertifyCSS");t&&t.parentNode&&t.parentNode.removeChild(t)}};return t.injectCSS(),{_$$alertify:t,reset:function(){return t.reset(),this},alert:function(e,o,n){return t.dialog(e,"alert",o,n)||this},confirm:function(e,o,n){return t.dialog(e,"confirm",o,n)||this},prompt:function(e,o,n){return t.dialog(e,"prompt",o,n)||this},log:function(e,o){return t.log(e,"default",o),this},theme:function(e){return t.theme(e),this},success:function(e,o){return t.log(e,"success",o),this},error:function(e,o){return t.log(e,"error",o),this},cancelBtn:function(e){return t.cancelBtn(e),this},okBtn:function(e){return t.okBtn(e),this},delay:function(e){return t.setDelay(e),this},placeholder:function(e){return t.promptPlaceholder=e,this},defaultValue:function(e){return t.promptValue=e,this},maxLogItems:function(e){return t.setMaxLogItems(e),this},closeLogOnClick:function(e){return t.setCloseLogOnClick(!!e),this},logPosition:function(e){return t.setLogPosition(e||""),this},setLogTemplate:function(e){return t.logTemplateMethod=e,this},clearLogs:function(){return t.setupLogContainer().innerHTML="",this},version:t.version}}var e=500,o=function(t){if(t){var o=function(){t&&t.parentNode&&t.parentNode.removeChild(t)};t.classList.remove("show"),t.classList.add("hide"),t.addEventListener("transitionend",o),setTimeout(o,e)}};if("undefined"!=typeof module&&module&&module.exports){module.exports=function(){return new t};var n=new t;for(var i in n)module.exports[i]=n[i]}else"function"==typeof define&&define.amd?define(function(){return new t}):window.alertify=new t}(); \ No newline at end of file diff --git a/public/build/assets/js/alertify-269e23cb46.js.br b/public/build/assets/js/alertify-269e23cb46.js.br new file mode 100644 index 0000000000000000000000000000000000000000..69f96a3901b3a411f561d1be52b311215e537b82 GIT binary patch literal 2762 zcmV;*3N`f`MJxau1#T?QqY!0i8QVF%M@TZes_ON|>|`Sgl)bZ#x5rt?0S^K)nZaI0 zR#WZub%;VCVM@1tGAQ4Aj`bQ#iIu?hgry{HZGlM}D*uXmBG4@`r6*=o7yoOmYESL5 zKjltHKq)8x%byt&RW%*aRXei;kUxKRZ#5h=9CgnDvBdD_&PgDLQUD5hkllZ*_M(Uc6%lB6>s9yrZ1|6%c&4R2Ca6kQj$GR8vZ21*LW&e807v<`i%fbw3%?z( zZ47kUJ3k&npJx-M0$*Rb&`BTt!-we{3iWu~gf)e~J@j%;oollNxD5lG=o$xTa^>fd z-4ku~;)O>n<)XLmu|2<{pz%I&YnjdgQy7V*g&w@UJw0lFFai|gO#rsta&xp>SDUvR z$!DC@U)|(Y*?~>mG``Kj-;LtI*6mNyvi>W5MfX~l9hi=@@y%ul1S=YQDUg&eI?i?Y zT%0my_uj40bqq0g!@gmSXKb8H&*kh`Gs=R`f8*D-?F`EnFc?+rxc}#sQTUmG+~BOx zZ%P(P&wZ>gH?M1~W0M*z)XdIql%4yMT%kX!#E^z9D>#fl#Zv*|@dVh3B*TJDO2KFh zk{7dWNT20uKPBz+1iG5kFafQ62KV0r!sOdtZSNTOH3bQvt@(k&nxRI@9OGSWAl4_SS86o@_%=eR(N--xHOiKg6)jh`0&Ak74$-u%& z?b`Usf5LsBPZ?}2kb?V}F26eW=Be0SpGrLf-cw1KgyoXvJ#4IMIFLj8XyVq43zi4R z$2;5jx$}?K*hcC9CamTNQrpcJROW5W>UPS1-)VW%_Xttgo?KjtroDoelPiYJBC6(R zny_$6A;=@*p659A{s>tp6p`}9vAA!Q%aWSmBT#?kKh!VK^rlV~GpT6%Egz|4pS-%kK$)FQ_ zb0@v66EPU5$}lcCF!USORQ^eF;b|a}DZO*&J+^J295&fG;KH8m`6u4H_9r;)B`}Xe zrh44M3>0q$k(KjPRHghte7q9Ep+#h3NQK02C*O5ZOO7-Z24d3I`O zELaCqs#WV;ar_WlQzcg!2k`9^43!L7DSt#Pcl1qw1p7@C`lEMN_$w3@%B}Q%dt>#| zfMS9k46J<+?O!dIfmXCki;w>|WgQSX)6!{xTPWbXS-0@SQe(*}U6evtJq3IMS#jOl z(3d^yXgoZmWlJA&^B7yqEhPnTT%u}p7wXu&b(QR#xK%vFoz~WTF12UWi)gr|(D+|0 zBg(qIbTqG0>V9l;D-jy>1&N}Rp0q|b)mZ*_ObqN#*IlMYD5sE6F#Yu(8SCDr=|xVs ztgdVj=OhRVtY$Q=(XT#t__jTlIeuR7(k2&G!8CqooK{D!65GF$$+A#U(!>%^7LQKR zl2!mHYs8Ht>vM_Bu6qa3*TcUin7R5G;4n=orp3=-wa^~2tk_X3Y5Z8|g?UTMj8xq> zUW3i@weWGax)$jXwBlZ}E^&2{6`;_+EU=Ak9jy;p#TT+YJ#xnw@2Fg^bADqSQEEu$ zhCH5wL(_xZb4HI`n@KWl^Jw33ZeE-I2D`)V6w464Cx{BUg%q zn|cmR#axq5toE*p=_Sg4|MCq7OZ8H5gX|f38z0tYvJKfrJg4v4*=TN*8vRClsKi2CSEG#RK~iWmymbTo`k6F{vITqU$VFk zrm;gWiQJ7@jM!osgaVNH4LmGXm@z@-_#$nSfN@kvIBA}Au#q`xA|eXLQxJflxNxqU zMdi^^ss&K21eU4l?Wpu%S$5Ko-YQn13u z?>>CfbzvAo-)(H6kKf;L96}oVFwu?Y#_FVk)1X%sU?a)g*kZdoN;V}gC>L8vu#(>E|yt>yzVY4(=q+PCl=tJ4??)cBQFy4l)H&GxAoxh+h!R(UGE zpv`?>#I}7F*UOO**H!-BEtL!82=BNNszM)C7d%TO$XL^qNk*z3V%Lhd+sIGjj| zD~0$v+q3KhYv`ZTGB{_Z^*^wt#>CE!(>22F`S)D7%5hqrdJkioI_Ccx1 zn(&{eQ^Kei_n_L-z`G3*%ldHq2sa)*3i8`TQdX-#m9X?e#pMIK&DD?979Lg*qyOuQ4UZ}cr>d>{hEBafF<-ZB+LVkw6&OR#9qln6B(}+Wxc}pS_ z2#j<$svG*?W2Qa2ZrEK?4^f}`@Q^QZ$Z!4xdYNu78X6yoR2w?JdD6-5gi|+bVFueV z4X)oz|D>qaxs5m5eP^d{6j_1PP>#W;O`4_X=`;lF zy;C!z>YLNFx+U1$%rsp%#~#-apJtkwXxR`gPP3r?0{Pygfl0d>*X{cUy?YJrN!E9! z|3rE~9t$W^Q*uMstkZOmz-*0!L&c|W6lj9x9D~h$M z>v$)QkW0;W7{YKV(%Y6%ED;Je_t*wK1ygd@W1v;*%OmC$w^uv;W0{PnEuby8nL!&oNH zL}dHByTd%fy5+|gL@t|U%1p7iKiL&vnQW{KfHMH8{#$ttVrh9}aJg~lS<6orI`U*} z`5NBwgEMedZ1-_bN1e+ddmb5@Z3wN@!jR!5>=mt)1e|-3ejuGX4-!x~o^>UV?V&k1 zPrr2jt>7(mE9%8Gi(SFREx*|Zomw71zGUdDN}^L-2GquEeL4cwP`FU-&~%n)6CH&# z86M$n19(BcHy7$SG<#x$kKp>?m!5Husu3K*lve;E7fia=&0dvtPQFf06inQC^Kx=s zhI#iNj_4WH?x7`_Yb3I_=BDx7s)1I)y!Ee7&Z=fh*F>P zFGgz!O#tI=$A0q4C2zxl4JILb;{X5v literal 0 HcmV?d00001 diff --git a/public/build/assets/js/alertify-269e23cb46.js.gz b/public/build/assets/js/alertify-269e23cb46.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..b3205c6b7b0ce1894b89f130274726e58ee2f906 GIT binary patch literal 3143 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 literal 0 HcmV?d00001 diff --git a/public/build/assets/js/fetch-5e9040330a.js b/public/build/assets/js/fetch-5e9040330a.js new file mode 100644 index 00000000..fac11e42 --- /dev/null +++ b/public/build/assets/js/fetch-5e9040330a.js @@ -0,0 +1,389 @@ +(function(self) { + 'use strict'; + + if (self.fetch) { + return + } + + function normalizeName(name) { + if (typeof name !== 'string') { + name = String(name) + } + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name') + } + return name.toLowerCase() + } + + function normalizeValue(value) { + if (typeof value !== 'string') { + value = String(value) + } + return value + } + + function Headers(headers) { + this.map = {} + + if (headers instanceof Headers) { + headers.forEach(function(value, name) { + this.append(name, value) + }, this) + + } else if (headers) { + Object.getOwnPropertyNames(headers).forEach(function(name) { + this.append(name, headers[name]) + }, this) + } + } + + Headers.prototype.append = function(name, value) { + name = normalizeName(name) + value = normalizeValue(value) + var list = this.map[name] + if (!list) { + list = [] + this.map[name] = list + } + list.push(value) + } + + Headers.prototype['delete'] = function(name) { + delete this.map[normalizeName(name)] + } + + Headers.prototype.get = function(name) { + var values = this.map[normalizeName(name)] + return values ? values[0] : null + } + + Headers.prototype.getAll = function(name) { + return this.map[normalizeName(name)] || [] + } + + Headers.prototype.has = function(name) { + return this.map.hasOwnProperty(normalizeName(name)) + } + + Headers.prototype.set = function(name, value) { + this.map[normalizeName(name)] = [normalizeValue(value)] + } + + Headers.prototype.forEach = function(callback, thisArg) { + Object.getOwnPropertyNames(this.map).forEach(function(name) { + this.map[name].forEach(function(value) { + callback.call(thisArg, value, name, this) + }, this) + }, this) + } + + function consumed(body) { + if (body.bodyUsed) { + return Promise.reject(new TypeError('Already read')) + } + body.bodyUsed = true + } + + function fileReaderReady(reader) { + return new Promise(function(resolve, reject) { + reader.onload = function() { + resolve(reader.result) + } + reader.onerror = function() { + reject(reader.error) + } + }) + } + + function readBlobAsArrayBuffer(blob) { + var reader = new FileReader() + reader.readAsArrayBuffer(blob) + return fileReaderReady(reader) + } + + function readBlobAsText(blob) { + var reader = new FileReader() + reader.readAsText(blob) + return fileReaderReady(reader) + } + + var support = { + blob: 'FileReader' in self && 'Blob' in self && (function() { + try { + new Blob(); + return true + } catch(e) { + return false + } + })(), + formData: 'FormData' in self, + arrayBuffer: 'ArrayBuffer' in self + } + + function Body() { + this.bodyUsed = false + + + this._initBody = function(body) { + this._bodyInit = body + if (typeof body === 'string') { + this._bodyText = body + } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { + this._bodyBlob = body + } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { + this._bodyFormData = body + } else if (!body) { + this._bodyText = '' + } else if (support.arrayBuffer && ArrayBuffer.prototype.isPrototypeOf(body)) { + // Only support ArrayBuffers for POST method. + // Receiving ArrayBuffers happens via Blobs, instead. + } else { + throw new Error('unsupported BodyInit type') + } + + if (!this.headers.get('content-type')) { + if (typeof body === 'string') { + this.headers.set('content-type', 'text/plain;charset=UTF-8') + } else if (this._bodyBlob && this._bodyBlob.type) { + this.headers.set('content-type', this._bodyBlob.type) + } + } + } + + if (support.blob) { + this.blob = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return Promise.resolve(this._bodyBlob) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as blob') + } else { + return Promise.resolve(new Blob([this._bodyText])) + } + } + + this.arrayBuffer = function() { + return this.blob().then(readBlobAsArrayBuffer) + } + + this.text = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return readBlobAsText(this._bodyBlob) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as text') + } else { + return Promise.resolve(this._bodyText) + } + } + } else { + this.text = function() { + var rejected = consumed(this) + return rejected ? rejected : Promise.resolve(this._bodyText) + } + } + + if (support.formData) { + this.formData = function() { + return this.text().then(decode) + } + } + + this.json = function() { + return this.text().then(JSON.parse) + } + + return this + } + + // HTTP methods whose capitalization should be normalized + var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] + + function normalizeMethod(method) { + var upcased = method.toUpperCase() + return (methods.indexOf(upcased) > -1) ? upcased : method + } + + function Request(input, options) { + options = options || {} + var body = options.body + if (Request.prototype.isPrototypeOf(input)) { + if (input.bodyUsed) { + throw new TypeError('Already read') + } + this.url = input.url + this.credentials = input.credentials + if (!options.headers) { + this.headers = new Headers(input.headers) + } + this.method = input.method + this.mode = input.mode + if (!body) { + body = input._bodyInit + input.bodyUsed = true + } + } else { + this.url = input + } + + this.credentials = options.credentials || this.credentials || 'omit' + if (options.headers || !this.headers) { + this.headers = new Headers(options.headers) + } + this.method = normalizeMethod(options.method || this.method || 'GET') + this.mode = options.mode || this.mode || null + this.referrer = null + + if ((this.method === 'GET' || this.method === 'HEAD') && body) { + throw new TypeError('Body not allowed for GET or HEAD requests') + } + this._initBody(body) + } + + Request.prototype.clone = function() { + return new Request(this) + } + + function decode(body) { + var form = new FormData() + body.trim().split('&').forEach(function(bytes) { + if (bytes) { + var split = bytes.split('=') + var name = split.shift().replace(/\+/g, ' ') + var value = split.join('=').replace(/\+/g, ' ') + form.append(decodeURIComponent(name), decodeURIComponent(value)) + } + }) + return form + } + + function headers(xhr) { + var head = new Headers() + var pairs = xhr.getAllResponseHeaders().trim().split('\n') + pairs.forEach(function(header) { + var split = header.trim().split(':') + var key = split.shift().trim() + var value = split.join(':').trim() + head.append(key, value) + }) + return head + } + + Body.call(Request.prototype) + + function Response(bodyInit, options) { + if (!options) { + options = {} + } + + this.type = 'default' + this.status = options.status + this.ok = this.status >= 200 && this.status < 300 + this.statusText = options.statusText + this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers) + this.url = options.url || '' + this._initBody(bodyInit) + } + + Body.call(Response.prototype) + + Response.prototype.clone = function() { + return new Response(this._bodyInit, { + status: this.status, + statusText: this.statusText, + headers: new Headers(this.headers), + url: this.url + }) + } + + Response.error = function() { + var response = new Response(null, {status: 0, statusText: ''}) + response.type = 'error' + return response + } + + var redirectStatuses = [301, 302, 303, 307, 308] + + Response.redirect = function(url, status) { + if (redirectStatuses.indexOf(status) === -1) { + throw new RangeError('Invalid status code') + } + + return new Response(null, {status: status, headers: {location: url}}) + } + + self.Headers = Headers; + self.Request = Request; + self.Response = Response; + + self.fetch = function(input, init) { + return new Promise(function(resolve, reject) { + var request + if (Request.prototype.isPrototypeOf(input) && !init) { + request = input + } else { + request = new Request(input, init) + } + + var xhr = new XMLHttpRequest() + + function responseURL() { + if ('responseURL' in xhr) { + return xhr.responseURL + } + + // Avoid security warnings on getResponseHeader when not allowed by CORS + if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { + return xhr.getResponseHeader('X-Request-URL') + } + + return; + } + + xhr.onload = function() { + var status = (xhr.status === 1223) ? 204 : xhr.status + if (status < 100 || status > 599) { + reject(new TypeError('Network request failed')) + return + } + var options = { + status: status, + statusText: xhr.statusText, + headers: headers(xhr), + url: responseURL() + } + var body = 'response' in xhr ? xhr.response : xhr.responseText; + resolve(new Response(body, options)) + } + + xhr.onerror = function() { + reject(new TypeError('Network request failed')) + } + + xhr.open(request.method, request.url, true) + + if (request.credentials === 'include') { + xhr.withCredentials = true + } + + if ('responseType' in xhr && support.blob) { + xhr.responseType = 'blob' + } + + request.headers.forEach(function(value, name) { + xhr.setRequestHeader(name, value) + }) + + xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) + }) + } + self.fetch.polyfill = true +})(typeof self !== 'undefined' ? self : this); diff --git a/public/build/assets/js/fetch-5e9040330a.js.br b/public/build/assets/js/fetch-5e9040330a.js.br new file mode 100644 index 0000000000000000000000000000000000000000..682a42a0e5ed48b76150d92497ad861cefca1ed6 GIT binary patch literal 2381 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 literal 0 HcmV?d00001 diff --git a/public/build/assets/js/fetch-5e9040330a.js.gz b/public/build/assets/js/fetch-5e9040330a.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..af7036e67d77640a39a3cc256fed723a096fda8f GIT binary patch literal 2643 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 BF`xhd literal 0 HcmV?d00001 diff --git a/public/build/assets/js/form-save-7849d1a5f3.js b/public/build/assets/js/form-save-7849d1a5f3.js new file mode 100644 index 00000000..151d1219 --- /dev/null +++ b/public/build/assets/js/form-save-7849d1a5f3.js @@ -0,0 +1,69 @@ +var feature = { + addEventListener : !!window.addEventListener, + querySelectorAll : !!document.querySelectorAll, +}; +if(feature.addEventListener && feature.querySelectorAll) { + this.init(); +} +function init() { + var keys = getKeys(); + for(var i = 0; i < keys.length; i++) { + if(store.get(keys[i])) { + var formId = keys[i].split("~")[1]; + document.getElementById(formId).value = store.get(keys[i]); + } + } +} +var timerId = window.setInterval(function() { + var saved = false; + var inputs = document.querySelectorAll('input[type=text], textarea'); + for(var i = 0; i < inputs.length; i++) { + var key = getFormElement(inputs[i]).id + '~' + inputs[i].id; + if(store.get(key) !== inputs[i].value && inputs[i].value !== "") { + store.set(key, inputs[i].value); + saved = true; + } + } + if(saved === true) { + alertify.logPosition('top right'); + alertify.success('Auto saved text'); + } +}, 5000); +var forms = document.querySelectorAll('form'); +for(var f = 0; f < forms.length; f++) { + var form = forms[f]; + form.addEventListener('submit', function() { + window.clearInterval(timerId); + var formId = form.id; + var storedKeys = store.keys(); + for(var i = 0; i < storedKeys.length; i++) { + if(storedKeys[i].indexOf(formId) > -1) { + store.remove(storedKeys[i]); + } + } + }); +} +function getKeys() { + var keys = []; + var formFields = document.querySelectorAll('input[type=text], textarea'); + for(var f = 0; f < formFields.length; f++) { + var parent = getFormElement(formFields[f]); + if(parent !== false) { + var key = parent.id + '~' + formFields[f].id; + keys.push(key); + } + } + return keys; +} +function getFormElement(elem) { + if(elem.nodeName.toLowerCase() !== 'body') { + var parent = elem.parentNode; + if(parent.nodeName.toLowerCase() === 'form') { + return parent; + } else { + return getFormElement(parent); + } + } else { + return false; + } +} diff --git a/public/build/assets/js/form-save-7849d1a5f3.js.br b/public/build/assets/js/form-save-7849d1a5f3.js.br new file mode 100644 index 0000000000000000000000000000000000000000..6fc60195534ea572980cb1144b58bce319eb7447 GIT binary patch literal 565 zcmV-50?Pdxod*CMhp{tylg8q-C%(Mc$)FFry@7?RS-Wl;xO-5T519&P1ko~gilCQ zK`~V|bNAm;Q)H08Aj2)gr;q!5tQj0BOBfM6>D3VZ6$H%DQt$F^t|HL4K!;okL~u3~ zm~m0;TU~p+n!ifh!{YyHcPH1w5!u$06;UPOuF884%`RYuFgZV6&DL^w(e@P9AO-`4 zo!-1P=f>BAc`?2ZO6~c1+~RVcnfoerClnvKuW*dN4veCeuE&hwAf%VK+GaA%R8NJi zP1;r$u2oN8E?f*8uY8G=5^oK|imFNp4pzpf&P?ROgCW))uQKTY?^|&H`MF;&pL&sC znXj?T1-nlr16>>JZ&|iU<-oCY$Xv{2%7w&@2A$z4IM`^ByGcT+GeazZn$C4RJI{&i zHNOJCp9o$_h~18bVIsfhRviMUuXg3k=|+Y-gokd}Cr@SC^3EHiQg5i_NMxF^g{$xb Dgh3h) literal 0 HcmV?d00001 diff --git a/public/build/assets/js/form-save-7849d1a5f3.js.gz b/public/build/assets/js/form-save-7849d1a5f3.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..ff873cbbf4570638e1912f333fd598b382f02f9a GIT binary patch literal 712 zcmV;(0yq61iwFP!000021Fckdf15B6{hv>9nLrZLJw3YjZvX2h=CJh(My@10vOaqy z4isCsyV;T6y&LbICb57NV^s)*E*yCPagsckV6L7ssW3+YH(_mU%JPIyBlm7ku6qY`48I>5Qq9Su-D(|;K(K*~j6?wGzf-`2l6B`nG?AE==|*xe-p09~TgSuxTC zfdPGBpThc*GHABZlSETh*O44&x`g%9_3*=mPwfh6C!vWRWN7}pJAaY{6dgvBI4jKP zo7srr#53O~p2?`#2t}E)(nF$pk}DLNB&Y|mFasG+(4f;eli02fSw1e58O;wh3j7lD zLCwe5RX9_h_Q3p#1;+l521&HdQCc-fjEB1IY77B|m{uc}z%KZwzW!-X^@rrHsta=6LJ3%6Z%CEIxYXL< zz*=_IuGxsy)+L#02yIfH;Otden+|%=x?tgUF$9kI1eZhYQk-bzX-De|>@}YGa!Hsq3*&wQA9}{NLv`b`GU7+W6T*zVR z+hsEeRE5Y($l^fVI#K_oB3N4f6XiU?m+=TA#h>#jihHrdfF1>ZpC@yFW&33){r6H6 uI1T@Z)EJ%2Rg>DnDX{8E(@S&_PA3##r{F|UO#N2VqyHV%r5zfc2LJ$`qF+b= literal 0 HcmV?d00001 diff --git a/public/build/assets/js/links-ea4c99f585.js b/public/build/assets/js/links-ea4c99f585.js new file mode 100644 index 00000000..b683edd5 --- /dev/null +++ b/public/build/assets/js/links-ea4c99f585.js @@ -0,0 +1,25 @@ +//the autlinker object +var autolinker = new Autolinker(); + +//the youtube regex +var ytidregex = /watch\?v=([A-Za-z0-9\-_]+)/; + +//grab the notes and loop through them +var notes = document.querySelectorAll('.e-content'); +for(var i = 0; i < notes.length; i++) { + //get Youtube ID + var ytid = notes[i].textContent.match(ytidregex); + if(ytid !== null) { + var id = ytid[1]; + var iframe = document.createElement('iframe'); + iframe.classList.add('youtube'); + iframe.setAttribute('src', '//www.youtube.com/embed/' + id); + iframe.setAttribute('frameborder', 0); + iframe.setAttribute('allowfullscreen', 'true'); + notes[i].appendChild(iframe); + } + //now linkify everything + var orig = notes[i].innerHTML; + var linked = autolinker.link(orig); + notes[i].innerHTML = linked; +} \ No newline at end of file diff --git a/public/build/assets/js/links-ea4c99f585.js.br b/public/build/assets/js/links-ea4c99f585.js.br new file mode 100644 index 0000000000000000000000000000000000000000..570224c5abd97781bd7bd3c4a654f45de94a7f17 GIT binary patch literal 337 zcmV-X0j~ZV4Fdp-)L_k>6CG_cZzbIlk3My3A!71~NSs)3DiDV-_xIVGQd=N%08Y~a z6}9Hp9z}%EPq*p3n-TRemoaVv0#@5BTO=DV_`xxjsEhGE(?cOe^={1D0eMytpA6?@ zY(h83Og?VrkLtBMBjwJ^7C(vnUgZsqrLmc*Us*QTk}oB3$J=p_BN%DsSiE0 zkGu03;)oS^8*_3%0OO5aAbdK9T0?_`a*EbshA%J(i^8|CTo)m5D0c+xv96r)*Co&7h+;(C*6vTGN&Y`70Xw-v!{=L+Fif jsT37MUWL9ru7}5sPZ;-S{$e>kppBYNT_v1VyW@5R*v^~! literal 0 HcmV?d00001 diff --git a/public/build/assets/js/links-ea4c99f585.js.gz b/public/build/assets/js/links-ea4c99f585.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..bb58b7338a712b93a5016ad2c4837bfea27a7acd GIT binary patch literal 434 zcmV;j0ZslNiwFP!000021AS7(+T1V5C|Jw2i=BM z753SjsnImtI%F~# z!7c%CRUpHc{YG9qcF;i|P8&qu)DOwH=10+AcD^lf*r`hgpy~j?)jLi!XdTV3c&lLK zgWsxu0-?+guSo{V^`pBOw}8}CDMjlWt#nsSW?aLjVNP~p1*(d`c@R literal 0 HcmV?d00001 diff --git a/public/build/assets/js/maps-ffa37774ae.js b/public/build/assets/js/maps-ffa37774ae.js new file mode 100644 index 00000000..4901c5da --- /dev/null +++ b/public/build/assets/js/maps-ffa37774ae.js @@ -0,0 +1,15 @@ +//This code runs on page load and looks for
    , then adds map +var mapDivs = document.querySelectorAll('.map'); +for(var i = 0; i < mapDivs.length; i++) { + var mapDiv = mapDivs[i]; + var latitude = mapDiv.dataset.latitude; + var longitude = mapDiv.dataset.longitude; + L.mapbox.accessToken = 'pk.eyJ1Ijoiam9ubnliYXJuZXMiLCJhIjoiVlpndW1EYyJ9.aP9fxAqLKh7lj0LpFh5k1w'; + var map = L.mapbox.map(mapDiv, 'jonnybarnes.gnoihnim') + .setView([latitude, longitude], 15) + .addLayer(L.mapbox.tileLayer('jonnybarnes.gnoihnim', { + detectRetina: true, + })); + var marker = L.marker([latitude, longitude]).addTo(map); + map.scrollWheelZoom.disable(); +} diff --git a/public/build/assets/js/maps-ffa37774ae.js.br b/public/build/assets/js/maps-ffa37774ae.js.br new file mode 100644 index 0000000000000000000000000000000000000000..ef0a316db6e68f76f5be3412d2ad84f8a6da27a8 GIT binary patch literal 352 zcmV-m0iXUGu>t@r4$M=ZP7AiqT9W`QoyAcrX~dvZW~G_TVJp zI_!_fO6ZlKHQ@wf)5LNIy54F6cOtbEVZ6W~@f{LHVKQ}4DwRIrl-%3ClutLzGQQ#m zywIosOdC(|fq8L1A`Vx36T@WK%JkSQUUL_{7v{y`X#3gXZxgjNczJJf9SG(&s8)(S_3|jHy}vkQaP` y^N)hBm<-cL*YApvV<9$gnHlohPrHA z=Ch*s)My8_C;~gM17YZKN?-&PAggeY*1@7!xTW+m)CQfqeY(T`^qmZRLky^tgYXb7 zqaF80dfCBkP*M*avCo$VvTGm7Q0>LuHztYmP!*>)qrjSsARWrfn_;`PhtCc1)HmU6 zVIhT$2tqrc59PacKlSgM`=18A_JgAR?_8lrM?T;CIaDh=-6@_^9sUlLzZ&gMWHraS zCg(m$OB_IP-{!RTqIy0PjotNO!bX4p_G0+)?X`aO@I^Dee=$9)uhrx4YcHiwlxFPp1oR=(<=G?&|ICBAt$9Na#T3tO_|EQ5F^%xe?0OfH|Y=!SI{rxEP7+>!sH zX(jo&7d1PG_&bB@@}XK(>J_e$P4=a{Hnj6JUnql(eYhe|wf{g~Gu{Ai2g[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]||""});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&(cap[1]==="pre"||cap[1]==="script"||cap[1]==="style"),text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(cap[0]):escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.text(escape(this.smartypants(cap[0])));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){if(!this.options.mangle)return text;var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
    "+(escaped?code:escape(code,true))+"\n
    "}return'
    '+(escaped?code:escape(code,true))+"\n
    \n"};Renderer.prototype.blockquote=function(quote){return"
    \n"+quote+"
    \n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
    \n":"
    \n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};Renderer.prototype.text=function(text){return text};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,sanitizer:null,mangle:true,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file diff --git a/public/build/assets/js/marked.min-c2a88705e2.js.br b/public/build/assets/js/marked.min-c2a88705e2.js.br new file mode 100644 index 0000000000000000000000000000000000000000..73d34d617d70dfbc5522ee9a2af26c66ac953993 GIT binary patch literal 5184 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 0) { + var i; + var places = []; + for (i = 0; i < j.length; ++i) { + var latlng = parseLocation(j[i].location); + var name = j[i].name; + var slug = j[i].slug; + places.push([name, slug, latlng[0], latlng[1]]); + } + //add a map with the nearby places + addMap(latitude, longitude, places); + } else { + //add a map with just current location + addMap(latitude, longitude); + } + }).catch(function (err) { + console.log(err); + }); +} + +function addMap(latitude, longitude, places) { + //make places null if not supplied + if (arguments.length == 2) { + places = null; + } + var form = button.parentNode; + var div = document.createElement('div'); + div.setAttribute('id', 'map'); + //add the map div + form.appendChild(div); + L.mapbox.accessToken = 'pk.eyJ1Ijoiam9ubnliYXJuZXMiLCJhIjoiVlpndW1EYyJ9.aP9fxAqLKh7lj0LpFh5k1w'; + var map = L.mapbox.map('map', 'jonnybarnes.gnoihnim') + .setView([latitude, longitude], 15) + .addLayer(L.mapbox.tileLayer('jonnybarnes.gnoihnim', { + detectRetina: true, + })); + //add a marker for the current location + var marker = L.marker([latitude, longitude], { + draggable: true, + }).addTo(map); + //when the location marker is dragged, if the new place form elements exist + //update the lat/lng values + marker.on('dragend', function () { + var placeFormLatitude = document.querySelector('#place-latitude'); + if (placeFormLatitude !== null) { + placeFormLatitude.value = getLatitudeFromMapboxMarker(marker.getLatLng()); + } + var placeFormLongitude = document.querySelector('#place-longitude'); + if (placeFormLongitude !== null) { + placeFormLongitude.value = getLongitudeFromMapboxMarker(marker.getLatLng()); + } + }); + //create the + places.forEach(function (item, index, array) { + var option = document.createElement('option'); + option.setAttribute('value', item[1]); + var text = document.createTextNode(item[0]); + option.appendChild(text); + option.dataset.latitude = item[2]; + option.dataset.longitude = item[3]; + selectEl.appendChild(option); + var placeMarker = L.marker([item[2], item[3]], { + icon: L.mapbox.marker.icon({ + 'marker-size': 'large', + 'marker-symbol': 'building', + 'marker-color': '#fa0' + }) + }).addTo(map); + var name = 'Name: ' + item[0]; + placeMarker.bindPopup(name, { + closeButton: true + }); + placeMarker.on('click', function (e) { + map.panTo([item[2], item[3]]); + selectPlace(item[1]); + }); + }); + //add an event listener + selectEl.addEventListener('change', function () { + if (selectEl.value !== 'no-location') { + var placeLat = selectEl[selectEl.selectedIndex].dataset.latitude; + var placeLon = selectEl[selectEl.selectedIndex].dataset.longitude; + map.panTo([placeLat, placeLon]); + } + }); + } + //add a button to add a new place + var newLocButton = document.createElement('button'); + newLocButton.setAttribute('type', 'button'); + newLocButton.setAttribute('id', 'create-new-place'); + newLocButton.appendChild(document.createTextNode('Create New Place?')); + //the event listener + newLocButton.addEventListener('click', function() { + //add the form elements + var nameLabel = document.createElement('label'); + nameLabel.setAttribute('for', 'place-name'); + nameLabel.classList.add('place-label') + nameLabel.appendChild(document.createTextNode('Place Name:')); + var nameEl = document.createElement('input'); + nameEl.setAttribute('placeholder', 'Name'); + nameEl.setAttribute('name', 'place-name'); + nameEl.setAttribute('id', 'place-name'); + nameEl.setAttribute('type', 'text'); + var descLabel = document.createElement('label'); + descLabel.setAttribute('for', 'place-description'); + descLabel.classList.add('place-label'); + descLabel.appendChild(document.createTextNode('Place Description:')); + var descEl = document.createElement('input'); + descEl.setAttribute('placeholder', 'Description'); + descEl.setAttribute('name', 'place-description'); + descEl.setAttribute('id', 'place-description'); + descEl.setAttribute('type', 'text'); + var latLabel = document.createElement('label'); + latLabel.setAttribute('for', 'place-latitude'); + latLabel.classList.add('place-label'); + latLabel.appendChild(document.createTextNode('Place Latitude:')); + var latEl = document.createElement('input'); + latEl.setAttribute('name', 'place-latitude'); + latEl.setAttribute('id', 'place-latitude'); + latEl.setAttribute('type', 'text'); + latEl.value = getLatitudeFromMapboxMarker(marker.getLatLng()); + var lonLabel = document.createElement('label'); + lonLabel.setAttribute('for', 'place-longitude'); + lonLabel.classList.add('place-label'); + lonLabel.appendChild(document.createTextNode('Place Longitude:')); + var lonEl = document.createElement('input'); + lonEl.setAttribute('name', 'place-longitude'); + lonEl.setAttribute('id', 'place-longitude'); + lonEl.setAttribute('type', 'text'); + lonEl.value = getLongitudeFromMapboxMarker(marker.getLatLng()); + var placeSubmit = document.createElement('button'); + placeSubmit.setAttribute('id', 'place-submit'); + placeSubmit.setAttribute('value', 'Submit New Place'); + placeSubmit.setAttribute('name', 'place-submit'); + placeSubmit.setAttribute('type', 'button'); + placeSubmit.appendChild(document.createTextNode('Submit New Place')); + form.appendChild(nameLabel); + form.appendChild(nameEl); + form.appendChild(descLabel); + form.appendChild(descEl); + form.appendChild(latLabel); + form.appendChild(latEl); + form.appendChild(lonLabel); + form.appendChild(lonEl); + form.appendChild(placeSubmit); + //the event listener for the new place form + placeSubmit.addEventListener('click', function () { + //create the form data to send + var formData = new FormData(); + formData.append('place-name', document.querySelector('#place-name').value); + formData.append('place-description', document.querySelector('#place-description').value); + formData.append('place-latitude', document.querySelector('#place-latitude').value); + formData.append('place-longitude', document.querySelector('#place-longitude').value); + //post the new place + fetch('/places/new', { + //send cookies with the request + credentials: 'same-origin', + method: 'post', + body: formData + }) + .then(status) + .then(json) + .then(function (placeJson) { + //create the slug from the url + var urlParts = placeJson.split('/'); + var slug = urlParts.pop(); + //remove un-needed form elements + form.removeChild(document.querySelector('#place-name')); + form.removeChild(document.querySelector('#place-description')); + form.removeChild(document.querySelector('#place-latitude')); + form.removeChild(document.querySelector('#place-longitude')); + var labels = document.querySelectorAll('.place-label'); + for (var label of labels) { + form.removeChild(label); + } + form.removeChild(document.querySelector('#place-submit')); + form.removeChild(document.querySelector('#create-new-place')); + //remove location marker + map.removeLayer(marker); + //add place marker + var newOption = document.createElement('option'); + newOption.setAttribute('value', slug); + newOption.appendChild(document.createTextNode(placeJson['name'])); + newOption.dataset.latitude = placeJson['latitude']; + newOption.dataset.longitude = placeJson['longitude']; + selectEl.appendChild(newOption); + var newPlaceMarker = L.marker([placeJson['latitude'], placeJson['longitude']], { + icon: L.mapbox.marker.icon({ + 'marker-size': 'large', + 'marker-symbol': 'building', + 'marker-color': '#fa0' + }) + }).addTo(map); + var newName = 'Name: ' + placeJson['name']; + newPlaceMarker.bindPopup(newName, { + closeButton: true + }); + newPlaceMarker.on('click', function (e) { + map.panTo([placeJson['latitude'], placeJson['longitude']]); + selectPlace(slug); + }); + //make selected + selectPlace(slug); + }).catch(function (placeError) { + console.log(placeError); + }); + }) + }); + form.insertBefore(newLocButton, div); +} + +function parseLocation(point) { + var re = /\((.*)\)/; + var resultArray = re.exec(point); + var location = resultArray[1].split(' '); + + return [location[1], location[0]]; +} + +function selectPlace(slug) { + document.querySelector('select [value=' + slug + ']').selected = true; +} + +function getLatitudeFromMapboxMarker(latlng) { + var resultArray = /\((.*)\)/.exec(latlng); + var location = resultArray[1].split(' '); + + return location[0].replace(',', ''); +} + +function getLongitudeFromMapboxMarker(latlng) { + var resultArray = /\((.*)\)/.exec(latlng); + var location = resultArray[1].split(' '); + + return location[1]; +} + +function status(response) { + if (response.status >= 200 && response.status < 300) { + return Promise.resolve(response); + } else { + return Promise.reject(new Error(response.statusText)); + } +} + +function json(response) { + return response.json(); +} diff --git a/public/build/assets/js/newnote-c1700073b7.js.br b/public/build/assets/js/newnote-c1700073b7.js.br new file mode 100644 index 0000000000000000000000000000000000000000..920c3a5b8b1cc609cb05b4455f9ed44be10e4eb8 GIT binary patch literal 2371 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 literal 0 HcmV?d00001 diff --git a/public/build/assets/js/newnote-c1700073b7.js.gz b/public/build/assets/js/newnote-c1700073b7.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..b1d81ea5d4b606ddcf479fe30899b5cde4b71fcc GIT binary patch literal 2636 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 mdo39_Lu=r1b>_eh=~h literal 0 HcmV?d00001 diff --git a/public/build/assets/js/newplace-18722f800b.js.gz b/public/build/assets/js/newplace-18722f800b.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..db9cb1c7c91d9f045e49f5af237f2daf4813ddfb GIT binary patch literal 649 zcmV;40(Si$iwFP!000021Eo~wmfI{4{qLvXtFY(zkluUmz4u@-mRRFKi$*T#uaVcw zlLTyG$(x?AYnyWKolBXSD9;8pkwbQjX_wVwK$2TE`1u{MkdgC(|6^UI2>8a4Ue64f zSQ4bt`rIVIubPSg!EdnFJr>$GmIcqO$ws`-a-geG(Krl}ZyDGMwsDD6RxId(JNyQ* z*BjQD#Zh-fBp=Z#&%xPdfir^))x_kATyh&*J1INx(5ExC_keWMRc0Zb;)$}ENh+z; zrB(#zogc3tGIP%BO4^`GwT3?XV#Q&;SPGl!iYcwHsqznn-ZuUAn46Y4tek~F$_2l~ z5I{3>OgmP&F;HPJXVU_ZEzU$O&)HP?>BC22YNCu)gFxp=zk46ub7<|h_8J@U^%*Q{ zy4qmA_Xv|t3fPi^?2p+Al;~@57s5CNW!3npt~;>AHTf-(fhD?--5C-5qK( z>7p|air}1uI1)UpCUEG=3g{G(H-nl$aHDyj@v$lsBx*}lmVo+9VXPK`(=1(;0XJ|n zsj>{J>aH6BhPb>ONtj>Wb!pQXH9k}i(3(dNFV~MBUNcwETrT4LeOsb_ue7yCxLro7!x2orQuxcDQY#pra?AQybkK z`4RYLQ?dJXgI#^?Ri4M}=?DkW==!b`!EhtL)RPVcj}*XoqpSC}Ds<~kQXOQ+5x;)jBWMmpe.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),N=[p,1];b&&N.push(b);var O=new a(l,g?t.tokenize(m,g):m,h);N.push(O),w&&N.push(w),Array.prototype.splice.apply(r,N)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var i={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==i.type&&(i.attributes.spellcheck="true"),e.alias){var l="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,l)}t.hooks.run("wrap",i);var o="";for(var s in i.attributes)o+=s+'="'+(i.attributes[s]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+o+">"+i.content+""},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code;_self.postMessage(JSON.stringify(t.util.encode(t.tokenize(r,t.languages[a])))),_self.close()},!1),_self.Prism):_self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism);; +Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(t){"entity"===t.type&&(t.attributes.title=t.content.replace(/&/,"&"))});; +Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/i,inside:{tag:{pattern:/|<\/style>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css},alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag));; +Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};; +Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/(?!\d)[a-z0-9_$]+(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/i,inside:{tag:{pattern:/|<\/script>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript},alias:"language-javascript"}});; +Prism.languages.git={comment:/^#.*$/m,string:/("|')(\\?.)*?\1/m,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s(--|-)\w+/m}},coord:/^@@.*@@$/m,deleted:/^-(?!-).+$/m,inserted:/^\+(?!\+).+$/m,commit_sha1:/^commit \w{40}$/m};; +Prism.languages.http={"request-line":{pattern:/^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b\shttps?:\/\/\S+\sHTTP\/[0-9.]+/,inside:{property:/^\b(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b/,"attr-name":/:\w+/}},"response-status":{pattern:/^HTTP\/1.[01] [0-9]+.*/,inside:{property:/[0-9]+[A-Z\s-]+$/i}},keyword:/^[\w-]+:(?=.+)/m};var httpLanguages={"application/json":Prism.languages.javascript,"application/xml":Prism.languages.markup,"text/xml":Prism.languages.markup,"text/html":Prism.languages.markup};for(var contentType in httpLanguages)if(httpLanguages[contentType]){var options={};options[contentType]={pattern:new RegExp("(content-type:\\s*"+contentType+"[\\w\\W]*?)\\n\\n[\\w\\W]*","i"),lookbehind:!0,inside:{rest:httpLanguages[contentType]}},Prism.languages.insertBefore("http","keyword",options)}; +Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/(^|\n)>(?:[\t ]*>)*/,lookbehind:!0,alias:"punctuation"},code:[{pattern:/(^|\n)(?: {4}|\t).+/,lookbehind:!0,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*\n(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/((?:^|\n)\s*)#+.+/,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/((?:^|\n)\s*)([*-])([\t ]*\2){2,}(?=\s*(?:\n|$))/,lookbehind:!0,alias:"punctuation"},list:{pattern:/((?:^|\n)\s*)(?:[*+-]|\d+\.)(?=[\t ].)/,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:[^>]|\\>)+>)(?:[\t ]+(?:"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\((?:[^)]|\\\))*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\((?:[^)]|\\\))*\))$/,punctuation:/[[\]\(\)<>:]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:\n(?!\n)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*\s*$|__\s*$/}},italic:{pattern:/(^|[^\\])(?:\*(?:\n(?!\n)|.)+?\*|_(?:\n(?!\n)|.)+?_)/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:[^"]|\\")*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:[^"]|\\")*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold);; +Prism.languages.php=Prism.languages.extend("clike",{keyword:/\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,constant:/\b[A-Z0-9_]{2,}\b/,comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])(\/\/).*?(\r?\n|$))/,lookbehind:!0}}),Prism.languages.insertBefore("php","class-name",{"shell-comment":{pattern:/(^|[^\\])#.*?(\r?\n|$)/,lookbehind:!0,alias:"comment"}}),Prism.languages.insertBefore("php","keyword",{delimiter:/(\?>|<\?php|<\?)/i,variable:/(\$\w+)\b/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),Prism.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}}),Prism.languages.markup&&(Prism.hooks.add("before-highlight",function(e){"php"===e.language&&(e.tokenStack=[],e.backupCode=e.code,e.code=e.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/gi,function(n){return e.tokenStack.push(n),"{{{PHP"+e.tokenStack.length+"}}}"}))}),Prism.hooks.add("before-insert",function(e){"php"===e.language&&(e.code=e.backupCode,delete e.backupCode)}),Prism.hooks.add("after-highlight",function(e){if("php"===e.language){for(var n,a=0;n=e.tokenStack[a];a++)e.highlightedCode=e.highlightedCode.replace("{{{PHP"+(a+1)+"}}}",Prism.highlight(n,e.grammar,"php"));e.element.innerHTML=e.highlightedCode}}),Prism.hooks.add("wrap",function(e){"php"===e.language&&"markup"===e.type&&(e.content=e.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g,'$1'))}),Prism.languages.insertBefore("php","comment",{markup:{pattern:/<[^?]\/?(.*?)>/,inside:Prism.languages.markup},php:/\{\{\{PHP[0-9]+\}\}\}/}));; +Prism.languages.insertBefore("php","variable",{"this":/\$this/,global:/\$_?(GLOBALS|SERVER|GET|POST|FILES|REQUEST|SESSION|ENV|COOKIE|HTTP_RAW_POST_DATA|argc|argv|php_errormsg|http_response_header)/,scope:{pattern:/\b[\w\\]+::/,inside:{keyword:/(static|self|parent)/,punctuation:/(::|\\)/}}});; +Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/,lookbehind:!0},atrule:{pattern:/@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+(\{|;))/i,inside:{rule:/@[\w-]+/}},url:/([-a-z]+-)*url(?=\()/i,selector:{pattern:/([^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+)(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/m,inside:{placeholder:/%[-_\w]+/i}}}),Prism.languages.insertBefore("scss","atrule",{keyword:/@(if|else if|else|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)|(?=@for\s+\$[-_\w]+\s)+from/i}),Prism.languages.insertBefore("scss","property",{variable:/((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i}),Prism.languages.insertBefore("scss","function",{placeholder:{pattern:/%[-_\w]+/i,alias:"selector"},statement:/\B!(default|optional)\b/i,"boolean":/\b(true|false)\b/,"null":/\b(null)\b/,operator:/\s+([-+]{1,2}|={1,2}|!=|\|?\||\?|\*|\/|%)\s+/}),Prism.languages.scss.atrule.inside.rest=Prism.util.clone(Prism.languages.scss);; +Prism.languages.sql={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|((--)|(\/\/)|#).*?(\r?\n|$))/,lookbehind:!0},string:{pattern:/(^|[^@])("|')(\\?[\s\S])*?\2/,lookbehind:!0},variable:/@[\w.$]+|@("|'|`)(\\?[\s\S])+?\1/,"function":/\b(?:COUNT|SUM|AVG|MIN|MAX|FIRST|LAST|UCASE|LCASE|MID|LEN|ROUND|NOW|FORMAT)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALTER|ANALYZE|APPLY|AS|ASC|AUTHORIZATION|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADE|CASCADED|CASE|CHAIN|CHAR VARYING|CHARACTER VARYING|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATA|DATABASE|DATABASES|DATETIME|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DOUBLE PRECISION|DROP|DUMMY|DUMP|DUMPFILE|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE|ESCAPED BY|EXCEPT|EXEC|EXECUTE|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR|FOR EACH ROW|FORCE|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GEOMETRY|GEOMETRYCOLLECTION|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEY|KEYS|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONGBLOB|LONGTEXT|MATCH|MATCHED|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTILINESTRING|MULTIPOINT|MULTIPOLYGON|NATIONAL|NATIONAL CHAR VARYING|NATIONAL CHARACTER|NATIONAL CHARACTER VARYING|NATIONAL VARCHAR|NATURAL|NCHAR|NCHAR VARCHAR|NEXT|NO|NO SQL|NOCHECK|NOCYCLE|NONCLUSTERED|NULLIF|NUMERIC|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUT|OUTER|OUTFILE|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC|PROCEDURE|PUBLIC|PURGE|QUICK|RAISERROR|READ|READS SQL DATA|READTEXT|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURN|RETURNS|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROWCOUNT|ROWGUIDCOL|ROWS?|RTREE|RULE|SAVE|SAVEPOINT|SCHEMA|SELECT|SERIAL|SERIALIZABLE|SESSION|SESSION_USER|SET|SETUSER|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START|STARTING BY|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLE|TABLES|TABLESPACE|TEMP(?:ORARY)?|TEMPTABLE|TERMINATED BY|TEXT|TEXTSIZE|THEN|TIMESTAMP|TINYBLOB|TINYINT|TINYTEXT|TO|TOP|TRAN|TRANSACTION|TRANSACTIONS|TRIGGER|TRUNCATE|TSEQUAL|TYPE|TYPES|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH|WITH ROLLUP|WITHIN|WORK|WRITE|WRITETEXT)\b/i,"boolean":/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b-?(0x)?\d*\.?[\da-f]+\b/,operator:/\b(?:ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|IS|UNIQUE|CHARACTER SET|COLLATE|DIV|OFFSET|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b|[-+]|!|[=<>]{1,2}|(&){1,2}|\|?\||\?|\*|\//i,punctuation:/[;[\]()`,.]/};; +Prism.hooks.add("complete",function(e){if(e.code){var t=e.element.parentNode,s=/\s*\bline-numbers\b\s*/;if(t&&/pre/i.test(t.nodeName)&&(s.test(t.className)||s.test(e.element.className))&&!e.element.querySelector(".line-numbers-rows")){s.test(e.element.className)&&(e.element.className=e.element.className.replace(s,"")),s.test(t.className)||(t.className+=" line-numbers");var a,n=e.code.match(/\n(?!$)/g).length+1,l=new Array(n+1);l=l.join(""),a=document.createElement("span"),a.className="line-numbers-rows",a.innerHTML=l,t.hasAttribute("data-start")&&(t.style.counterReset="linenumber "+(parseInt(t.getAttribute("data-start"),10)-1)),e.element.appendChild(a)}}});; +!function(){if(window.Prism)for(var r in Prism.languages){var g=Prism.languages[r];g.tab=/\t/g,g.crlf=/\r\n/g,g.lf=/\n/g,g.cr=/\r/g}}();; diff --git a/public/build/assets/js/prism-f6e997bc6d.js.br b/public/build/assets/js/prism-f6e997bc6d.js.br new file mode 100644 index 0000000000000000000000000000000000000000..2cef61aa3bb408d58bb9c9d0aa343e781ccd904b GIT binary patch literal 6464 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 f=this._out(c.key(this._area,d));if(void 0!==f&&a.call(this,f,b||this.get(f))===!1)break;e>c.length(this._area)&&(e--,d--)}return b||this},keys:function(){return this.each(function(a,b){b.push(a)},[])},get:function(a,b){var d=c.get(this._area,this._in(a));return null!==d?c.parse(d):b||d},getAll:function(){return this.each(function(a,b){b[a]=this.get(a)},{})},set:function(a,b,d){var e=this.get(a);return null!=e&&d===!1?b:c.set(this._area,this._in(a),c.stringify(b),d)||e},setAll:function(a,b){var c,d;for(var e in a)d=a[e],this.set(e,d,b)!==d&&(c=!0);return c},remove:function(a){var b=this.get(a);return c.remove(this._area,this._in(a)),b},clear:function(){return this._ns?this.each(function(a){c.remove(this._area,this._in(a))},1):c.clear(this._area),this},clearAll:function(){var a=this._area;for(var b in c.areas)c.areas.hasOwnProperty(b)&&(this._area=c.areas[b],this.clear());return this._area=a,this},_in:function(a){return"string"!=typeof a&&(a=c.stringify(a)),this._ns?this._ns+a:a},_out:function(a){return this._ns?a&&0===a.indexOf(this._ns)?a.substring(this._ns.length):void 0:a}},storageAPI:{length:0,has:function(a){return this.items.hasOwnProperty(a)},key:function(a){var b=0;for(var c in this.items)if(this.has(c)&&a===b++)return c},setItem:function(a,b){this.has(a)||this.length++,this.items[a]=b},removeItem:function(a){this.has(a)&&(delete this.items[a],this.length--)},getItem:function(a){return this.has(a)?this.items[a]:null},clear:function(){for(var a in this.list)this.removeItem(a)},toString:function(){return this.length+" items in "+this.name+"Storage"}}};a.store&&(c.conflict=a.store);var d=c.Store("local",function(){try{return localStorage}catch(a){}}());d.local=d,d._=c,d.area("session",function(){try{return sessionStorage}catch(a){}}()),a.store=d,"function"==typeof b&&void 0!==b.amd?b(function(){return d}):"undefined"!=typeof module&&module.exports&&(module.exports=d)}(this,this.define); +//# sourceMappingURL=store2.min.js.map \ No newline at end of file diff --git a/public/build/assets/js/store2.min-c4daa8f871.js.br b/public/build/assets/js/store2.min-c4daa8f871.js.br new file mode 100644 index 0000000000000000000000000000000000000000..49dda19b0f4a953fc5c77df5bb1ae976b68716de GIT binary patch literal 1303 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 + */ + +/* +|-------------------------------------------------------------------------- +| Register The Auto Loader +|-------------------------------------------------------------------------- +| +| Composer provides a convenient, automatically generated class loader for +| our application. We just need to utilize it! We'll simply require it +| into the script here so that we don't have to worry about manual +| loading any of our classes later on. It feels nice to relax. +| +*/ + +require __DIR__.'/../bootstrap/autoload.php'; + +/* +|-------------------------------------------------------------------------- +| Turn On The Lights +|-------------------------------------------------------------------------- +| +| We need to illuminate PHP development, so let us turn on the lights. +| This bootstraps the framework and gets it ready for use, then it +| will load up this application so that we can run it and send +| the responses back to the browser and delight our users. +| +*/ + +$app = require_once __DIR__.'/../bootstrap/app.php'; + +/* +|-------------------------------------------------------------------------- +| Run The Application +|-------------------------------------------------------------------------- +| +| Once we have the application, we can handle the incoming request +| through the kernel, and send the associated response back to +| the client's browser allowing them to enjoy the creative +| and wonderful application we have prepared for them. +| +*/ + +$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); + +$response = $kernel->handle( + $request = Illuminate\Http\Request::capture() +); + +$response->send(); + +$kernel->terminate($request, $response); diff --git a/public/media/.gitignore b/public/media/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/public/media/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 00000000..eb053628 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/public/web.config b/public/web.config new file mode 100644 index 00000000..624c1760 --- /dev/null +++ b/public/web.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readme.md b/readme.md new file mode 100644 index 00000000..7f8816d6 --- /dev/null +++ b/readme.md @@ -0,0 +1,27 @@ +# Laravel PHP Framework + +[![Build Status](https://travis-ci.org/laravel/framework.svg)](https://travis-ci.org/laravel/framework) +[![Total Downloads](https://poser.pugx.org/laravel/framework/d/total.svg)](https://packagist.org/packages/laravel/framework) +[![Latest Stable Version](https://poser.pugx.org/laravel/framework/v/stable.svg)](https://packagist.org/packages/laravel/framework) +[![Latest Unstable Version](https://poser.pugx.org/laravel/framework/v/unstable.svg)](https://packagist.org/packages/laravel/framework) +[![License](https://poser.pugx.org/laravel/framework/license.svg)](https://packagist.org/packages/laravel/framework) + +Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable, creative experience to be truly fulfilling. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as authentication, routing, sessions, queueing, and caching. + +Laravel is accessible, yet powerful, providing tools needed for large, robust applications. A superb inversion of control container, expressive migration system, and tightly integrated unit testing support give you the tools you need to build any application with which you are tasked. + +## Official Documentation + +Documentation for the framework can be found on the [Laravel website](http://laravel.com/docs). + +## Contributing + +Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](http://laravel.com/docs/contributions). + +## Security Vulnerabilities + +If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed. + +## License + +The Laravel framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). diff --git a/resources/assets/sass/app.scss b/resources/assets/sass/app.scss new file mode 100644 index 00000000..bb76e29c --- /dev/null +++ b/resources/assets/sass/app.scss @@ -0,0 +1,2 @@ +// @import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap"; + diff --git a/resources/assets/sass/components/colours.scss b/resources/assets/sass/components/colours.scss new file mode 100644 index 00000000..61ad3735 --- /dev/null +++ b/resources/assets/sass/components/colours.scss @@ -0,0 +1,12 @@ +//colours.scss +body { + color: $base03; +} + +header a { + color: $base03; +} + +a { + color: $blue; +} \ No newline at end of file diff --git a/resources/assets/sass/components/fonts.scss b/resources/assets/sass/components/fonts.scss new file mode 100644 index 00000000..744735df --- /dev/null +++ b/resources/assets/sass/components/fonts.scss @@ -0,0 +1,41 @@ +//fonts.scss + +body { + text-rendering: optimizeLegibility; + font-feature-settings: "liga"; + font-family: $font-stack-body; + font-size: 1.2em; +} + +#topheader h1 { + font-family: $font-stack-body; +} + +h1 { + font-family: $font-stack-headers; +} + +#topheader a { + text-decoration: none; +} + +nav { + font-feature-settings: "dlig"; +} + +article header h1 a { + text-decoration: none; +} + +article div a { + text-decoration: none; +} + +footer { + font-size: 0.8em; +} + +.emoji { + width: auto; + height: 1em; +} diff --git a/resources/assets/sass/components/forms.scss b/resources/assets/sass/components/forms.scss new file mode 100644 index 00000000..095c423c --- /dev/null +++ b/resources/assets/sass/components/forms.scss @@ -0,0 +1,45 @@ +//forms.scss + +form { + width: 100%; +} + +fieldset { + min-width: 0; + width: 100%; +} + +input[type="text"], input[type="file"], textarea { + width: 100%; +} + +input, button, textarea { + -webkit-appearance: none; + -moz-appearance: none; + background-color: $base03; + color: $base3; + border: 1px solid $base3; + border-radius: 4px; +} + +button:hover { + transition: 0.5s ease-in-out; + background-color: $base3; + color: $base03; +} + +button:disabled { + background-color: $base1; + color: $base03; +} + +input[type="checkbox"] { + -webkit-appearance: checkbox; + -moz-appearance: checkbox; +} + +#photo { + background: inherit; + color: inherit; + border: none; +} diff --git a/resources/assets/sass/components/twitter.scss b/resources/assets/sass/components/twitter.scss new file mode 100644 index 00000000..8eb8a6a5 --- /dev/null +++ b/resources/assets/sass/components/twitter.scss @@ -0,0 +1,9 @@ +//twitter.scss + +.twitter-tweet-rendered { + margin-bottom: 0 !important; +} + +.twitter-tweet-rendered + .note { + margin-top: 0; +} diff --git a/resources/assets/sass/global.scss b/resources/assets/sass/global.scss new file mode 100644 index 00000000..bc2e0534 --- /dev/null +++ b/resources/assets/sass/global.scss @@ -0,0 +1,41 @@ +//global.scss + +//variables +$font-stack-body: "leitura-news", serif; +$font-stack-headers: "prenton", sans-serif; + +//solarized variables TERMCOL +$base03: #002b36;//brblack +$base02: #073642;//black +$base01: #586e75;//brgreen +$base00: #657b83;//bryellow +$base0: #839496;//brblue +$base1: #93a1a1;//brcyan +$base2: #eee8d5;//white +$base3: #fdf6e3;//brwhite +$yellow: #b58900; +$orange: #cb4b16; +$red: #dc322f; +$magenta: #d33682; +$violet: #6c71c4; +$blue: #268bd2; +$cyan: #2aa198; +$green: #859900; + +//global styles +html { + background: url('/assets/img/escheresque.png'); +} + +.map { + height: 150px; +} + +//layout +@import "layout"; + +//components +@import "components/fonts"; +@import "components/colours"; +@import "components/forms"; +@import "components/twitter"; diff --git a/resources/assets/sass/layout.scss b/resources/assets/sass/layout.scss new file mode 100644 index 00000000..c80cf830 --- /dev/null +++ b/resources/assets/sass/layout.scss @@ -0,0 +1,197 @@ +//layout.scss + +//boxes +html { + box-sizing: border-box; +} + +*, *:before, *:after { + box-sizing: inherit; +} + +#topheader { + display: flex; + flex-flow: row; +} + +#topheader a { + padding: 0.5em 1em; +} + +nav { + padding-top: 0.5em; +} + +.social-list { + padding-left: 2em; +} + +.note { + background-color: $base2; + box-shadow: 0 0 10px 2px $base1; + padding: 0.5em 0.5em; + margin-top: 1em; +} + +.note:after { + content: " "; + display: block; + height: 0; + clear: both; +} + +.note a { + word-wrap: break-word; +} + +.note .e-content p:first-child { + margin-top: 0; +} + +.note-metadata { + width: 100%; +} + +.social-links { + float: right; +} + +.social-links a { + text-decoration: none; +} + +.icon { + width: auto; + height: 1em; + fill: $blue; +} + +.reply { + margin-left: 2em; + margin-right: 2em; + font-size: 0.8em; + padding: 0.5em 0.5em; +} + +.reply-to { + margin-left: 2em; + margin-right: 2em; + font-size: 0.8em; + padding-top: 2em; +} + +.reply-to + .note { + margin-top: 0.3em; +} + +.mini-h-card { + border-radius: 2px; + border: 1px solid $base01; + padding: 0 0.2em; + text-decoration: none; + margin-right: 5px; + white-space: nowrap; +} + +.mini-h-card img { + height: 1.26em; + display: inline; + border-radius: 2px; + vertical-align: text-bottom; +} + +.like-photo { + height: 1.26em; +} + +.reply .e-content { + margin-top: 0.5em; + padding-left: 0.5em; +} + +.notes-subtitle { + font-size: 1em; +} + +.note-photo { + width: 100%; + height: auto; + image-orientation: from-image; +} + +//articles + +article header { + margin-top: 0.5em; + margin-bottom: 0.8em; +} + +.post-info { + font-size: 0.8em; + font-style: italic; + margin-top: -0.8em; +} + +//contacts +.contact { + position: relative; +} + +.contact-links { + list-style-type: none; +} + +.contact img { + height: auto; + width: 2em; + position: absolute; + top: 0; + left: 0; +} + +.contact-info { + margin-left: 2em; +} + +#map { + height: 300px; +} + +/* media queries */ +@media (min-width: 700px) { + main { + margin-left: 10em; + margin-right: 10em; + } + + footer { + margin-left: 13em; + margin-right: 13em; + } + + .youtube { + width: 640px; + height: 360px; + } +} + +@media (max-width: 699px) { + main { + margin-left: 10px; + margin-right: 10px; + } + + article { + word-wrap: break-word; + } + + footer { + margin-left: 15px; + margin-right: 15px; + } + + .youtube { + width: 100%; + height: auto; + } +} diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php new file mode 100644 index 00000000..e5506df2 --- /dev/null +++ b/resources/lang/en/auth.php @@ -0,0 +1,19 @@ + 'These credentials do not match our records.', + 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', + +]; diff --git a/resources/lang/en/pagination.php b/resources/lang/en/pagination.php new file mode 100644 index 00000000..fcab34b2 --- /dev/null +++ b/resources/lang/en/pagination.php @@ -0,0 +1,19 @@ + '« Previous', + 'next' => 'Next »', + +]; diff --git a/resources/lang/en/passwords.php b/resources/lang/en/passwords.php new file mode 100644 index 00000000..e5544d20 --- /dev/null +++ b/resources/lang/en/passwords.php @@ -0,0 +1,22 @@ + 'Passwords must be at least six characters and match the confirmation.', + 'reset' => 'Your password has been reset!', + 'sent' => 'We have e-mailed your password reset link!', + 'token' => 'This password reset token is invalid.', + 'user' => "We can't find a user with that e-mail address.", + +]; diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php new file mode 100644 index 00000000..b1e61204 --- /dev/null +++ b/resources/lang/en/validation.php @@ -0,0 +1,113 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/views/admin/deletearticle.blade.php b/resources/views/admin/deletearticle.blade.php new file mode 100644 index 00000000..95ab35d3 --- /dev/null +++ b/resources/views/admin/deletearticle.blade.php @@ -0,0 +1,13 @@ +@extends('master') + +@section('title') +Delete Article? « Admin CP +@stop + +@section('content') +
    + +
    + +
    +@stop diff --git a/resources/views/admin/deletearticlesuccess.blade.php b/resources/views/admin/deletearticlesuccess.blade.php new file mode 100644 index 00000000..1eac9ce1 --- /dev/null +++ b/resources/views/admin/deletearticlesuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Article Deleted « Admin CP +@stop + +@section('content') +

    You have successfully deletd the article with id: {{ $id }}

    +@stop diff --git a/resources/views/admin/deleteclientsuccess.blade.php b/resources/views/admin/deleteclientsuccess.blade.php new file mode 100644 index 00000000..892474a3 --- /dev/null +++ b/resources/views/admin/deleteclientsuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Edit Client « Admin CP +@stop + +@section('content') +

    Successfully deleted the client information.

    +@stop diff --git a/resources/views/admin/deletecontact.blade.php b/resources/views/admin/deletecontact.blade.php new file mode 100644 index 00000000..f855e4fc --- /dev/null +++ b/resources/views/admin/deletecontact.blade.php @@ -0,0 +1,14 @@ +@extends('master') + +@section('title') +Delete Contact? « Admin CP +@stop + +@section('content') +
    + + +
    + +
    +@stop diff --git a/resources/views/admin/deletecontactsuccess.blade.php b/resources/views/admin/deletecontactsuccess.blade.php new file mode 100644 index 00000000..df7f71c7 --- /dev/null +++ b/resources/views/admin/deletecontactsuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Deleted Contact « Admin CP +@stop + +@section('content') +

    Successfully deleted the contact information.

    +@stop diff --git a/resources/views/admin/deletetoken.blade.php b/resources/views/admin/deletetoken.blade.php new file mode 100644 index 00000000..fbaed92b --- /dev/null +++ b/resources/views/admin/deletetoken.blade.php @@ -0,0 +1,13 @@ +@extends('master') + +@section('title') +Delete Token? « Admin CP +@stop + +@section('content') +
    + +
    + +
    +@stop diff --git a/resources/views/admin/deletetokensuccess.blade.php b/resources/views/admin/deletetokensuccess.blade.php new file mode 100644 index 00000000..4e2709e2 --- /dev/null +++ b/resources/views/admin/deletetokensuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Token Deleted « Admin CP +@stop + +@section('content') +

    You have successfully deletd the token: {{ $id }}

    +@stop diff --git a/resources/views/admin/editarticle.blade.php b/resources/views/admin/editarticle.blade.php new file mode 100644 index 00000000..3e2ec22f --- /dev/null +++ b/resources/views/admin/editarticle.blade.php @@ -0,0 +1,41 @@ +@extends('master') + +@section('title') +Edit Article « Admin CP +@stop + +@section('content') +
    + + +
    + +
    + +
    + +
    + +
    + +
    + +
    +

    Preview

    +@stop + +@section('scripts') +@parent + + +@stop diff --git a/resources/views/admin/editarticlesuccess.blade.php b/resources/views/admin/editarticlesuccess.blade.php new file mode 100644 index 00000000..39a45e3b --- /dev/null +++ b/resources/views/admin/editarticlesuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Article Successfully Edited « Admin CP +@stop + +@section('content') +

    Successfully edited article with id: {{ $id }}

    +@stop diff --git a/resources/views/admin/editclient.blade.php b/resources/views/admin/editclient.blade.php new file mode 100644 index 00000000..cb3db738 --- /dev/null +++ b/resources/views/admin/editclient.blade.php @@ -0,0 +1,15 @@ +@extends('master') + +@section('title') +Edit Client « Admin CP +@stop + +@section('content') +

    Edit Client

    +
    +
    +
    +

    + +
    +@stop diff --git a/resources/views/admin/editclientsuccess.blade.php b/resources/views/admin/editclientsuccess.blade.php new file mode 100644 index 00000000..69068bad --- /dev/null +++ b/resources/views/admin/editclientsuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Edit Client « Admin CP +@stop + +@section('content') +

    Successfully edited the client information.

    +@stop diff --git a/resources/views/admin/editcontact.blade.php b/resources/views/admin/editcontact.blade.php new file mode 100644 index 00000000..100a7055 --- /dev/null +++ b/resources/views/admin/editcontact.blade.php @@ -0,0 +1,20 @@ +@extends('master') + +@section('title') +Edit Contact « Admin CP +@stop + +@section('content') +

    Edit Contact

    +
    + +
    +
    +
    +
    +
    + +
    +
    +

    Instead of uploading an image, you can grab from their homepage?

    +@stop \ No newline at end of file diff --git a/resources/views/admin/editcontactsuccess.blade.php b/resources/views/admin/editcontactsuccess.blade.php new file mode 100644 index 00000000..c9712779 --- /dev/null +++ b/resources/views/admin/editcontactsuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Edit Contact « Admin CP +@stop + +@section('content') +

    Successfully edited the contact information.

    +@stop diff --git a/resources/views/admin/editnote.blade.php b/resources/views/admin/editnote.blade.php new file mode 100644 index 00000000..6bf7e1ee --- /dev/null +++ b/resources/views/admin/editnote.blade.php @@ -0,0 +1,18 @@ +@extends('master') + +@section('title') +Edit Note « Admin CP +@stop + +@section('content') +
    + +
    + Edit Note +
    +
    +
    +
    +
    +
    +@stop diff --git a/resources/views/admin/editnotesuccess.blade.php b/resources/views/admin/editnotesuccess.blade.php new file mode 100644 index 00000000..4a138dd1 --- /dev/null +++ b/resources/views/admin/editnotesuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Note Successfully Edited « Admin CP +@stop + +@section('content') +

    Successfully edited note with id: {{ $id }}.

    +@stop diff --git a/resources/views/admin/editplace.blade.php b/resources/views/admin/editplace.blade.php new file mode 100644 index 00000000..93e92763 --- /dev/null +++ b/resources/views/admin/editplace.blade.php @@ -0,0 +1,18 @@ +@extends('master') + +@section('title') +Edit Place « Admin CP +@stop + +@section('content') +

    Edit Place

    +
    + +
    +
    +
    +
    +

    + +
    +@stop diff --git a/resources/views/admin/editplacesuccess.blade.php b/resources/views/admin/editplacesuccess.blade.php new file mode 100644 index 00000000..eb4ef9a3 --- /dev/null +++ b/resources/views/admin/editplacesuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Edit Place « Admin CP +@stop + +@section('content') +

    Successfully edited the place information.

    +@stop diff --git a/resources/views/admin/getavatarsuccess.blade.php b/resources/views/admin/getavatarsuccess.blade.php new file mode 100644 index 00000000..d0b0187d --- /dev/null +++ b/resources/views/admin/getavatarsuccess.blade.php @@ -0,0 +1,10 @@ +@extends('master') + +@section('title') +New Contact Avatar « Admin CP +@stop + +@section('content') +

    Successfully saved the avatar contact

    + +@stop diff --git a/resources/views/admin/listarticles.blade.php b/resources/views/admin/listarticles.blade.php new file mode 100644 index 00000000..04049827 --- /dev/null +++ b/resources/views/admin/listarticles.blade.php @@ -0,0 +1,14 @@ +@extends('master') + +@section('title') +List Articles « Admin CP +@stop + +@section('content') +

    Select article to edit:

    +
      +@foreach($posts as $post) +
    1. {{ $post['title'] }}@if($post['published'] == '0')not published@endif Delete? +@endforeach +
    +@stop diff --git a/resources/views/admin/listclients.blade.php b/resources/views/admin/listclients.blade.php new file mode 100644 index 00000000..ad699eed --- /dev/null +++ b/resources/views/admin/listclients.blade.php @@ -0,0 +1,17 @@ +@extends('master') + +@section('title') +List Clients « Admin CP +@stop + +@section('content') +

    Clients

    +
      +@foreach($clients as $client) +
    • {{ $client['client_url'] }} : {{ $client['client_name'] }} + edit? +
    • +@endforeach +
    +

    Createn a new entry?

    +@stop diff --git a/resources/views/admin/listcontacts.blade.php b/resources/views/admin/listcontacts.blade.php new file mode 100644 index 00000000..86a5e2d2 --- /dev/null +++ b/resources/views/admin/listcontacts.blade.php @@ -0,0 +1,27 @@ +@extends('master') + +@section('title') +List Contacts « Admin CP +@stop + +@section('content') +

    Contacts

    + + + + + + + + +@foreach($contacts as $contact) + + + + + + + +@endforeach +
    Real NameNickHomepageTwitter
    {{ $contact->name }}{{ $contact->nick }}{{ $contact->homepage }}{{ $contact->twitter }}edit
    +@stop \ No newline at end of file diff --git a/resources/views/admin/listnotes.blade.php b/resources/views/admin/listnotes.blade.php new file mode 100644 index 00000000..1bf767e6 --- /dev/null +++ b/resources/views/admin/listnotes.blade.php @@ -0,0 +1,14 @@ +@extends('master') + +@section('title') +List Notes « Admin CP +@stop + +@section('content') +

    Select note to edit:

    +
      +@foreach($notes as $note) +
    1. {{ $note->originalNote }}
    2. +@endforeach +
    +@stop diff --git a/resources/views/admin/listplaces.blade.php b/resources/views/admin/listplaces.blade.php new file mode 100644 index 00000000..a51c0bfb --- /dev/null +++ b/resources/views/admin/listplaces.blade.php @@ -0,0 +1,15 @@ +@extends('master') + +@section('title') +List Places « Admin CP +@stop + +@section('content') +

    Places

    +
      +@foreach($places as $place) +
    • {{ $place['name'] }} edit?
    • +@endforeach +
    +

    Createn a new entry?

    +@stop diff --git a/resources/views/admin/listtokens.blade.php b/resources/views/admin/listtokens.blade.php new file mode 100644 index 00000000..4039f461 --- /dev/null +++ b/resources/views/admin/listtokens.blade.php @@ -0,0 +1,21 @@ +@extends('master') + +@section('title') +List Tokens « Admin CP +@stop + +@section('content') +

    Tokens

    +
      +@foreach($tokens as $token => $data) +
    • {{ $token }} +
        + @foreach($data as $key => $value) +
      • {{ $key }}: '; foreach($value as $scope) { echo "
      • $scope
      • "; } echo '
      '; } else { echo $value; }; ?>
    • + @endforeach +
    + delete? + +@endforeach + +@stop diff --git a/resources/views/admin/newarticle.blade.php b/resources/views/admin/newarticle.blade.php new file mode 100644 index 00000000..a8061147 --- /dev/null +++ b/resources/views/admin/newarticle.blade.php @@ -0,0 +1,49 @@ +@extends('master') + +@section('title') +New Article « Admin CP +@stop + +@section('content') +@if(isset($message))

    {{ $message }}

    @endif +
    + + +
    + +
    + +
    + +
    + +
    + +
    +

    Or you can upload an .md file:

    +
    + +
    +

    Preview

    +@stop + +@section('scripts') +@parent + + + + + + + +@stop diff --git a/resources/views/admin/newarticlesuccess.blade.php b/resources/views/admin/newarticlesuccess.blade.php new file mode 100644 index 00000000..6bc1a0b3 --- /dev/null +++ b/resources/views/admin/newarticlesuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +New Article Success « Admin CP +@stop + +@section('content') +

    Successfully created article with id: {{ $id }}, title: {{ $title }}

    +@stop diff --git a/resources/views/admin/newclient.blade.php b/resources/views/admin/newclient.blade.php new file mode 100644 index 00000000..a7f50405 --- /dev/null +++ b/resources/views/admin/newclient.blade.php @@ -0,0 +1,15 @@ +@extends('master') + +@section('title') +New Client « Admin CP +@stop + +@section('content') +

    New Client

    +
    + +
    +
    + +
    +@stop diff --git a/resources/views/admin/newclientsuccess.blade.php b/resources/views/admin/newclientsuccess.blade.php new file mode 100644 index 00000000..ac23d4fa --- /dev/null +++ b/resources/views/admin/newclientsuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +New Client « Admin CP +@stop + +@section('content') +

    Succesfully created new client info.

    +@stop diff --git a/resources/views/admin/newcontact.blade.php b/resources/views/admin/newcontact.blade.php new file mode 100644 index 00000000..0c38a367 --- /dev/null +++ b/resources/views/admin/newcontact.blade.php @@ -0,0 +1,17 @@ +@extends('master') + +@section('title') +New Contact « Admin CP +@stop + +@section('content') +

    New Contact

    +
    + +
    +
    +
    +
    + +
    +@stop \ No newline at end of file diff --git a/resources/views/admin/newcontactsuccess.blade.php b/resources/views/admin/newcontactsuccess.blade.php new file mode 100644 index 00000000..13fe7532 --- /dev/null +++ b/resources/views/admin/newcontactsuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +New Contact « Admin CP +@stop + +@section('content') +

    Succesfully created new contact entry.

    +@stop diff --git a/resources/views/admin/newnote.blade.php b/resources/views/admin/newnote.blade.php new file mode 100644 index 00000000..9787c822 --- /dev/null +++ b/resources/views/admin/newnote.blade.php @@ -0,0 +1,34 @@ +@extends('master') + +@section('title') +New Note « Admin CP +@stop + +@section('content') +@if (count($errors) > 0) +
    +
      + @foreach ($errors->all() as $error) +
    • {{ $error }}
    • + @endforeach +
    +
    +@endif +@include('templates.new-note-form', [ + 'micropub' => false, + 'action' => '/admin/note/new', + 'id' => 'newnote-admin' +]) +@stop + +@section('scripts') + + + + + + + + + +@stop diff --git a/resources/views/admin/newnotesuccess.blade.php b/resources/views/admin/newnotesuccess.blade.php new file mode 100644 index 00000000..d96fda81 --- /dev/null +++ b/resources/views/admin/newnotesuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +New Note Success « Admin CP +@stop + +@section('content') +

    Successfully created note with id: {{ $id }}. {{ $shorturl }}

    +@stop diff --git a/resources/views/admin/newplace.blade.php b/resources/views/admin/newplace.blade.php new file mode 100644 index 00000000..c4f9b8d4 --- /dev/null +++ b/resources/views/admin/newplace.blade.php @@ -0,0 +1,24 @@ +@extends('master') + +@section('title') +New Place « Admin CP +@stop + +@section('content') +

    New Place

    +
    + +
    +
    +
    +
    + +

    Location

    + +
    +@stop + +@section('scripts') + + +@stop diff --git a/resources/views/admin/newplacesuccess.blade.php b/resources/views/admin/newplacesuccess.blade.php new file mode 100644 index 00000000..787aac8c --- /dev/null +++ b/resources/views/admin/newplacesuccess.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +New Place « Admin CP +@stop + +@section('content') +

    Succesfully created new place info.

    +@stop diff --git a/resources/views/admin/welcome.blade.php b/resources/views/admin/welcome.blade.php new file mode 100644 index 00000000..c60d66db --- /dev/null +++ b/resources/views/admin/welcome.blade.php @@ -0,0 +1,24 @@ +@extends('master') + +@section('title') +Admin CP +@stop + +@section('content') +

    Hello {{ $name }}!

    + +

    Articles

    +

    You can either create new blog posts, or edit them.

    + +

    Notes

    +

    You can either create new notes, or edit them.

    + +

    Tokens

    +

    See all issued tokens.

    + +

    Contacts

    +

    You can either create new contacts, or edit them.

    + +

    Places

    +

    You can either create new places, or edit them.

    +@stop diff --git a/resources/views/allnotes.blade.php b/resources/views/allnotes.blade.php new file mode 100644 index 00000000..eb41df56 --- /dev/null +++ b/resources/views/allnotes.blade.php @@ -0,0 +1,31 @@ +@extends('master') + +@section('title') +Notes « Jonny Barnes +@stop + +@section('content') +
    + + + @foreach ($notes as $note) +
    + @include('templates.note', ['note' => $note]) +
    + @endforeach +
    +{!! $notes->render() !!} +@stop + +@section('scripts') + + + + + + + + + +@stop diff --git a/resources/views/allplaces.blade.php b/resources/views/allplaces.blade.php new file mode 100644 index 00000000..94445d72 --- /dev/null +++ b/resources/views/allplaces.blade.php @@ -0,0 +1,13 @@ +@extends('master') + +@section('title') +Places « Jonny Barnes +@stop + +@section('content') + +@stop diff --git a/resources/views/contact-template.blade.php b/resources/views/contact-template.blade.php new file mode 100644 index 00000000..d6dae0af --- /dev/null +++ b/resources/views/contact-template.blade.php @@ -0,0 +1,10 @@ +
    +
    + {{ $contact->name }} {{ '@' . $contact->nick }} + +
    + +
    \ No newline at end of file diff --git a/resources/views/contact.blade.php b/resources/views/contact.blade.php new file mode 100644 index 00000000..1cecd3d1 --- /dev/null +++ b/resources/views/contact.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +Contacts « Jonny Barnes +@stop + +@section('content') +@include('contact-template', array('contact' => $contact)) +@stop \ No newline at end of file diff --git a/resources/views/contacts.blade.php b/resources/views/contacts.blade.php new file mode 100644 index 00000000..b53b34bf --- /dev/null +++ b/resources/views/contacts.blade.php @@ -0,0 +1,11 @@ +@extends('master') + +@section('title') +Contacts « Jonny Barnes +@stop + +@section('content') +@foreach($contacts as $contact) +@include('contact-template', array('contact' => $contact)) +@endforeach +@stop \ No newline at end of file diff --git a/resources/views/errors/503.blade.php b/resources/views/errors/503.blade.php new file mode 100644 index 00000000..4a415059 --- /dev/null +++ b/resources/views/errors/503.blade.php @@ -0,0 +1,47 @@ + + + + Be right back. + + + + + + +
    +
    +
    Be right back.
    +
    +
    + + diff --git a/resources/views/homepage.blade.php b/resources/views/homepage.blade.php new file mode 100644 index 00000000..a889caa3 --- /dev/null +++ b/resources/views/homepage.blade.php @@ -0,0 +1,29 @@ +@extends('master') + +@section('title') +Jonny Barnes +@stop + +@section('content') +
    +

    Hello

    +

    My name is Jonny Barnes, and I’m from Manchester, UK. I love everything web-related and this is a little place on the web I call my own. My aim now is to try and adhere to the IndieWeb principles and thus own my data.

    +

    My aim for this homepage is to turn it into a stream of my latest notes and articles I’ve written. Then maybe pull data from places like last.fm. Talking of which:

    + +

    Me Around the Web

    +

    Obviously there’s this website, which is my main online identity.

    +

    I am active to varying degrees on several silos: +

    +

    My usual online handle is jonnybarnes for other services, though if they’re not listed above then I don’t actively use the service. My usual profile pic. I also have a PGP key, with fingerprint.

    + +

    Though of course all this activity should eventually “flow” through this website if it is to truely be my online identity.

    +
    +@stop diff --git a/resources/views/login.blade.php b/resources/views/login.blade.php new file mode 100644 index 00000000..a6f9d86c --- /dev/null +++ b/resources/views/login.blade.php @@ -0,0 +1,12 @@ +@extends('master') +@section('title')Login @stop + +@section('content') +

    Login

    +
    + + + + +
    +@stop diff --git a/resources/views/master.blade.php b/resources/views/master.blade.php new file mode 100644 index 00000000..c17613dc --- /dev/null +++ b/resources/views/master.blade.php @@ -0,0 +1,58 @@ + + + + + @if (App::environment() == 'local'){!! "[testing] -"!!}@endif @yield('title') + + + + + + + + + + + + + +
    + + +
    + +
    +@yield('content') +
    + + + @section('scripts') + + @show + + {{-- The piwik code that should only be shown in production --}} + @if (env('PIWIK_URL') !== null) + + + + + @endif + + diff --git a/resources/views/micropubnewnotepage.blade.php b/resources/views/micropubnewnotepage.blade.php new file mode 100644 index 00000000..4aa5bd38 --- /dev/null +++ b/resources/views/micropubnewnotepage.blade.php @@ -0,0 +1,45 @@ +@extends('master') + +@section('title') +New Note « Jonny Barnes +@stop + +@section('content') +

    This is my UI for posting new notes, hopefully you’ll soon be able to use this if your site supports the micropub API.

    +@if($errors->endpoint->first() != '') +

    {{ $errors->endpoint->first() }}

    +@endif +@if($errors->indieauth->first() != '') +

    {{ $errors->indieauth->first() }}

    +@endif +@if($url === null) +
    + +
    + IndieAuth + + +
    +
    +@else +

    You are authenticated as {{ $url }}, log out.

    +@endif + @include('templates.new-note-form', [ + 'micropub' => true, + 'action' => '/notes/new', + 'id' => 'newnote' + ]) +@stop + +@section('scripts') + + + + + + + + + + +@stop diff --git a/resources/views/mini-hcard-template.blade.php b/resources/views/mini-hcard-template.blade.php new file mode 100644 index 00000000..c2ab1eba --- /dev/null +++ b/resources/views/mini-hcard-template.blade.php @@ -0,0 +1,4 @@ + + + {!! $contact->name !!} + diff --git a/resources/views/multipost.blade.php b/resources/views/multipost.blade.php new file mode 100644 index 00000000..59bab313 --- /dev/null +++ b/resources/views/multipost.blade.php @@ -0,0 +1,30 @@ +@extends('master') + +@section('title') +Articles « Jonny Barnes +@stop + +@section('content') +@if (count($data) == 0) +

    No articles exist for this time.

    +@endif +@foreach ($data as $article) +@if ($article['url'] != '')
    @else +@endforeach +{!! $data->render() !!} +@stop + +@section('scripts') + + +@stop diff --git a/resources/views/projects.blade.php b/resources/views/projects.blade.php new file mode 100644 index 00000000..a02f66d5 --- /dev/null +++ b/resources/views/projects.blade.php @@ -0,0 +1,14 @@ +@extends('master') +@section('title')Jonny Barnes’ Projects @stop + +@section('content') +
    +

    Projects

    +

    Shaaaaaaaaaaaaa.com

    +

    I’m collaborating on a project with Eric Mill (@konklone) to help people test their HTTPS certificates for weak signature algorithms. SHA-1 is the current standard, but is too weak. People should use a form of SHA-2.

    +

    IndieWeb tools

    +

    This library consists of various useful tools for running an IndieWeb aware site.

    +

    Webmentions Parser

    +

    A tool to parse incoming webmentions to a site, including determining the author of the source webmention.

    +
    +@stop diff --git a/resources/views/rss.blade.php b/resources/views/rss.blade.php new file mode 100644 index 00000000..8ec8a0a9 --- /dev/null +++ b/resources/views/rss.blade.php @@ -0,0 +1,22 @@ + + + + Jonny Barnes.uk + + An RSS feed of the blog posts found on jonnybarnes.uk + https://jonnybarnes.uk + {{ $buildDate }} + 1800 + + @foreach($articles as $article) + + {{ strip_tags($article->title) }} + main }}@if($article->url)

    Permalink

    @endif]]>
    + @if($article->url != ''){{ $article->url }}@else{{ config('app.url') }}{{ $article->link }}@endif + {{ config('app.url') }}{{ $article->link }} + {{ $article->pubdate }} +
    + @endforeach + +
    +
    diff --git a/resources/views/singlenote.blade.php b/resources/views/singlenote.blade.php new file mode 100644 index 00000000..40b0101c --- /dev/null +++ b/resources/views/singlenote.blade.php @@ -0,0 +1,43 @@ +@extends('master') + +@section('title') +{{ strip_tags($note->note) }} « Notes « Jonny Barnes +@stop + +@section('content') +
    + @include('templates.note', ['note' => $note]) +@foreach($replies as $reply) +
    + + {{ $reply['name'] }} + said at {{ $reply['date'] }} +
    + {!! $reply['reply'] !!} +
    +
    +@endforeach +
    +@if(count($likes) > 0)

    Likes

    @endif +@foreach($likes as $like) + +@endforeach +@if(count($reposts) > 0)

    Reposts

    @endif +@foreach($reposts as $repost) +

    + {{ $repost['name'] }} + reposted this at {{ $repost['date'] }}.

    +@endforeach +@stop + +@section('scripts') + + + + + + + + + +@stop diff --git a/resources/views/singleplace.blade.php b/resources/views/singleplace.blade.php new file mode 100644 index 00000000..eb5e3ce6 --- /dev/null +++ b/resources/views/singleplace.blade.php @@ -0,0 +1,21 @@ +@extends('master') + +@section('title') +{{ $place->name }} « Places « Jonny Barnes +@stop + +@section('content') +
    +

    {{ $place->name }}

    +

    {{ $place->description or 'No description'}}

    +
    +

    Latitude: {{ $place->latitude }}, longitude: {{ $place->longitude }}

    +
    +@stop + +@section('scripts') + + + + +@stop diff --git a/resources/views/singlepost.blade.php b/resources/views/singlepost.blade.php new file mode 100644 index 00000000..8b42a7fb --- /dev/null +++ b/resources/views/singlepost.blade.php @@ -0,0 +1,24 @@ +@extends('master') + +@section('title') +{{ strip_tags($article->title) }} Jonny Barnes +@stop + +@section('content') +@if($article->url != '')
    @else +@stop + +@section('scripts') + + +@stop diff --git a/resources/views/taggednotes.blade.php b/resources/views/taggednotes.blade.php new file mode 100644 index 00000000..53a9bb04 --- /dev/null +++ b/resources/views/taggednotes.blade.php @@ -0,0 +1,13 @@ +@extends('master') + +@section('title') +Notes Jonny Barnes +@stop + +@section('content') +

    Notes tagged with {{ $tag }}

    +@foreach ($notes as $note) +
    {!! $note->note !!} +{{ $note->human_time }}
    +@endforeach +@stop \ No newline at end of file diff --git a/resources/views/templates/new-note-form.blade.php b/resources/views/templates/new-note-form.blade.php new file mode 100644 index 00000000..e0c55ca2 --- /dev/null +++ b/resources/views/templates/new-note-form.blade.php @@ -0,0 +1,16 @@ +
    + +
    + New Note + + +
    +@if ($micropub === true) + @if($syndication)@endif + Refresh Syndication Targets
    +@endif + + + +
    +
    diff --git a/resources/views/templates/note.blade.php b/resources/views/templates/note.blade.php new file mode 100644 index 00000000..76f8eeb4 --- /dev/null +++ b/resources/views/templates/note.blade.php @@ -0,0 +1,26 @@ +@if ($note->twitter) + {!! $note->twitter->html !!} +@elseif ($note->in_reply_to) +
    + In reply to {{ $note->in_reply_to }} +
    +@endif +
    +
    + {!! $note->note !!} + @if(count($note->photoURLs) > 0) + @foreach($note->photoURLs as $photoURL) + + @endforeach + @endif +
    + +
    diff --git a/resources/views/templates/social-links.blade.php b/resources/views/templates/social-links.blade.php new file mode 100644 index 00000000..9f31a2f8 --- /dev/null +++ b/resources/views/templates/social-links.blade.php @@ -0,0 +1,31 @@ + diff --git a/resources/views/vendor/.gitkeep b/resources/views/vendor/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/resources/views/vendor/.gitkeep @@ -0,0 +1 @@ + diff --git a/resources/views/webmention-endpoint.blade.php b/resources/views/webmention-endpoint.blade.php new file mode 100644 index 00000000..2422bc87 --- /dev/null +++ b/resources/views/webmention-endpoint.blade.php @@ -0,0 +1,9 @@ +@extends('master') + +@section('title') +WebMentions « Jonny Barnes +@stop + +@section('content') +

    My WebMention endpoint.

    +@stop diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php new file mode 100644 index 00000000..87710ace --- /dev/null +++ b/resources/views/welcome.blade.php @@ -0,0 +1,45 @@ + + + + Laravel + + + + + + +
    +
    +
    Laravel 5
    +
    +
    + + diff --git a/server.php b/server.php new file mode 100644 index 00000000..f65c7c44 --- /dev/null +++ b/server.php @@ -0,0 +1,21 @@ + + */ + +$uri = urldecode( + parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) +); + +// This file allows us to emulate Apache's "mod_rewrite" functionality from the +// built-in PHP web server. This provides a convenient way to test a Laravel +// application without having installed a "real" web server software here. +if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { + return false; +} + +require_once __DIR__.'/public/index.php'; diff --git a/storage/HTML/.gitignore b/storage/HTML/.gitignore new file mode 100644 index 00000000..bf27f311 --- /dev/null +++ b/storage/HTML/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!.gitkeep diff --git a/storage/HTML/.gitkeep b/storage/HTML/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/storage/HTMLPurifier/.gitignore b/storage/HTMLPurifier/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/storage/HTMLPurifier/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/app/.gitignore b/storage/app/.gitignore new file mode 100644 index 00000000..8f4803c0 --- /dev/null +++ b/storage/app/.gitignore @@ -0,0 +1,3 @@ +* +!public/ +!.gitignore diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/storage/app/public/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/debugbar/.gitignore b/storage/debugbar/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/storage/debugbar/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore new file mode 100644 index 00000000..b02b700f --- /dev/null +++ b/storage/framework/.gitignore @@ -0,0 +1,8 @@ +config.php +routes.php +schedule-* +compiled.php +services.json +events.scanned.php +routes.scanned.php +down diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/storage/framework/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/media-tmp/.gitkeep b/storage/media-tmp/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/storage/medialibrary/.gitignore b/storage/medialibrary/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/storage/medialibrary/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/storage/tokens/.gitignore b/storage/tokens/.gitignore new file mode 100644 index 00000000..bf27f311 --- /dev/null +++ b/storage/tokens/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!.gitkeep diff --git a/storage/tokens/.gitkeep b/storage/tokens/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/ArticlesTest.php b/tests/ArticlesTest.php new file mode 100644 index 00000000..d39ce868 --- /dev/null +++ b/tests/ArticlesTest.php @@ -0,0 +1,78 @@ +appurl = config('app.url'); + } + + /** + * Test the `/blog` page returns the article, this + * means the database is being hit. + * + * @return void + */ + public function testArticlesPage() + { + $this->visit($this->appurl . '/blog') + ->see('My New Blog'); + } + + /** + * Test the `/blog/{year}` page returns the article, this + * means the database is being hit. + * + * @return void + */ + public function testArticlesYearPage() + { + $this->visit($this->appurl . '/blog/2016') + ->see('My New Blog'); + } + + /** + * Test the `/blog/{year}/{month}` page returns the article, + * this means the database is being hit. + * + * @return void + */ + public function testArticlesMonthPage() + { + $this->visit($this->appurl . '/blog/2016/01') + ->see('My New Blog'); + } + + /** + * Test a single article page. + * + * @return void + */ + public function testSingleArticlePage() + { + $this->visit($this->appurl . '/blog/2016/01/my-new-blog') + ->see('My New Blog'); + } + + /** + * Test the RSS feed. + * + * @return void + */ + public function testRSSFeed() + { + $response = $this->call('GET', $this->appurl . '/feed'); + + $this->assertEquals('application/rss+xml', $response->headers->get('Content-Type')); + } +} diff --git a/tests/ContactsTest.php b/tests/ContactsTest.php new file mode 100644 index 00000000..16318a6b --- /dev/null +++ b/tests/ContactsTest.php @@ -0,0 +1,52 @@ +appurl = config('app.url'); + } + + /** + * Test the `/contacts` page and see if response is OK. + * + * @return void + */ + public function testContactsPage() + { + $this->visit($this->appurl . '/contacts') + ->assertResponseOK(); + } + + /** + * Test an individual contact page with default profile image. + * + * @return void + */ + public function testContactPageWithDefaultPic() + { + $this->visit($this->appurl . '/contacts/tantek') + ->see(''); + } + + /** + * Test an individual contact page with a specific profile image. + * + * @return void + */ + public function testContactPageWithSpecificPic() + { + $this->visit($this->appurl . '/contacts/aaron') + ->see(''); + } +} diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php new file mode 100644 index 00000000..dee80424 --- /dev/null +++ b/tests/ExampleTest.php @@ -0,0 +1,19 @@ +visit(config('app.url') . '/') + ->see('Jonny Barnes'); + } +} diff --git a/tests/IndieAuthTest.php b/tests/IndieAuthTest.php new file mode 100644 index 00000000..75c15554 --- /dev/null +++ b/tests/IndieAuthTest.php @@ -0,0 +1,79 @@ +appurl = config('app.url'); + } + + /** + * Test the getAuthorizationEndpoint calls the correct service methods, + * though these methods are actually mocked. + * + * @return void + */ + public function testIndieAuthServiceDiscoversEndpoint() + { + $service = new \App\Services\IndieAuthService(); + $client = new \IndieAuth\Client(); + $result = $service->getAuthorizationEndpoint($this->appurl, $client); + $this->assertSame('https://indieauth.com/auth', $result); + } + + /** + * Test that the Service build the correct redirect URL. + * + * @return void + */ + public function testIndieAuthServiceBuildRedirectURL() + { + $client = new \IndieAuth\Client(); + $service = new \App\Services\IndieAuthService(); + $result = $service->buildAuthorizationURL( + 'https://indieauth.com/auth', + $this->appurl, + $client + ); + $this->assertSame( + 'https://indieauth.com/auth?me=', + substr($result, 0, 30) + ); + } + + /** + * Test the `beginauth` method redirects to the client on error. + * + * @return void + */ + public function testIndieAuthControllerBeginAuthRedirectsToClientOnFail() + { + $response = $this->call('GET', $this->appurl . '/beginauth', ['me' => 'http://example.org']); + $this->assertSame($this->appurl . '/notes/new', $response->headers->get('Location')); + } + + /** + * Now we test the `beginauth` method as a whole. + * + * @return void + */ + public function testIndieAuthControllerBeginAuthRedirectsToEndpoint() + { + $response = $this->call('GET', $this->appurl . '/beginauth', ['me' => $this->appurl]); + $this->assertSame( + 'https://indieauth.com/auth?me=', + substr($response->headers->get('Location'), 0, 30) + ); + $response = null; + } +} diff --git a/tests/MicropubClientTest.php b/tests/MicropubClientTest.php new file mode 100644 index 00000000..f94006db --- /dev/null +++ b/tests/MicropubClientTest.php @@ -0,0 +1,73 @@ +appurl = config('app.url'); + } + + /** + * Test the client gets shown for an unauthorised request. + * + * @return void + */ + public function testClientPageUnauthorised() + { + $this->visit($this->appurl . '/notes/new') + ->see('IndieAuth'); + } + + public function testClientPageRecentAuth() + { + $this->withSession([ + 'me' => $this->appurl, + 'syndication' => 'mp-syndicate-to=twitter.com%2Fjbl5', + ])->visit($this->appurl . '/notes/new') + ->see($this->appurl) + ->see('twitter.com/jbl5'); + } + + /** + * This currently creates a new note that stays in the database. + */ + public function testClientCreatesNewNote() + { + $faker = \Faker\Factory::create(); + $note = 'Fake note from PHPUnit: ' . $faker->text; + $this->withSession([ + 'me' => $this->appurl, + 'token' => $this->getToken() + ])->visit($this->appurl . '/notes/new') + ->type($note, 'content') + ->press('Submit'); + $this->seeInDatabase('notes', ['note' => $note]); + + } + + private function getToken() + { + $signer = new Sha256(); + $token = (new Builder()) + ->set('client_id', 'https://quill.p3k.io') + ->set('me', $this->appurl) + ->set('scope', 'post') + ->set('issued_at', time()) + ->sign($signer, env('APP_KEY')) + ->getToken(); + + return $token; + } +} diff --git a/tests/MicropubTest.php b/tests/MicropubTest.php new file mode 100644 index 00000000..1cac5657 --- /dev/null +++ b/tests/MicropubTest.php @@ -0,0 +1,112 @@ +appurl = config('app.url'); + } + + public function testMicropubRequestWithoutToken() + { + $this->call('GET', $this->appurl . '/api/post'); + $this->assertResponseStatus(400); + $this->see('No OAuth token sent with request.'); + } + + public function testMicropubRequestWithoutValidToken() + { + $this->call('GET', $this->appurl . '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer abc123']); + $this->assertResponseStatus(400); + $this->see('Invalid token'); + } + + public function testMicropubRequestWithValidToken() + { + $this->call('GET', $this->appurl . '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); + $this->see('me=https%3A%2F%2Fjbl5.dev'); + } + + public function testMicropubRequestForSyndication() + { + $this->call('GET', $this->appurl . '/api/post', ['q' => 'syndicate-to'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); + $this->see('twitter.com%2Fjonnybarnes'); + } + + public function testMicropubRequestForNearbyPlacesThatExist() + { + $this->call('GET', $this->appurl . '/api/post', ['q' => 'geo:53.5,-2.38'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); + $this->see('the-bridgewater-pub'); + } + + public function testMicropubRequestForNearbyPlacesThatDoNotExist() + { + $this->call('GET', $this->appurl . '/api/post', ['q' => 'geo:1.23,4.56'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); + $this->see('[]'); + } + + public function testMicropubRequestCreateNewNote() + { + $faker = \Faker\Factory::create(); + $note = $faker->text; + $this->call( + 'POST', + $this->appurl . '/api/post', + [ + 'h' => 'entry', + 'content' => $note + ], + [], + [], + ['HTTP_Authorization' => 'Bearer ' . $this->getToken()] + ); + $this->seeInDatabase('notes', ['note' => $note]); + } + + public function testMicropubRequestCreateNewPlace() + { + $faker = \Faker\Factory::create(); + $note = $faker->text; + $this->call( + 'POST', + $this->appurl . '/api/post', + [ + 'h' => 'card', + 'name' => 'The Barton Arms', + 'geo' => 'geo:53.4974,-2.3768' + ], + [], + [], + ['HTTP_Authorization' => 'Bearer ' . $this->getToken()] + ); + $this->seeInDatabase('places', ['slug' => 'the-barton-arms']); + } + + private function getToken() + { + $signer = new Sha256(); + $token = (new Builder()) + ->set('client_id', 'https://quill.p3k.io') + ->set('me', 'https://jbl5.dev') + ->set('scope', 'post') + ->set('issued_at', time()) + ->sign($signer, env('APP_KEY')) + ->getToken(); + + return $token; + } +} diff --git a/tests/NotesTest.php b/tests/NotesTest.php new file mode 100644 index 00000000..233704e3 --- /dev/null +++ b/tests/NotesTest.php @@ -0,0 +1,179 @@ +appurl = config('app.url'); + $this->notesController = new \App\Http\Controllers\NotesController(); + } + + /** + * Test the `/notes` page returns 200, this should + * mean the database is being hit. + * + * @return void + */ + public function testNotesPage() + { + $this->visit($this->appurl . '/notes') + ->assertResponseOk(); + } + + /** + * Test a specific note so that `singleNote()` get called. + * + * @return void + */ + public function testSpecificNote() + { + $this->visit($this->appurl . '/notes/B') + ->see('#beer'); + } + + /** + * Test that `/note/{decID}` redirects to `/notes/{nb60id}`. + * + * @return void + */ + public function testDecIDRedirect() + { + $this->get($this->appurl . '/note/11') + ->assertRedirectedTo(config('app.url') . '/notes/B'); + } + + /** + * Visit the tagged page and see text from the note. + * + * @return void + */ + public function testTaggedNotesPage() + { + $this->visit($this->appurl . '/notes/tagged/beer') + ->see('at the local.'); + } + + /** + * Look for a default image in the contact’s h-card. + * + * @return void + */ + public function testDefaultImageUsed() + { + $this->visit($this->appurl . '/notes/C') + ->see(''); + } + + /** + * Look for a specific profile image in the contact’s h-card. + * + * @return void + */ + public function testProfileImageUsed() + { + $this->visit($this->appurl . '/notes/D') + ->see(''); + } + + /** + * Look for twitter URL when there’s no associated contact. + * + * @return void + */ + public function testTwitterLinkCreatedWhenNoContactFound() + { + $this->visit($this->appurl . '/notes/E') + ->see('@bob'); + } + + /** + * Test hashtag linking. + * + * @return void + */ + public function testHashtags() + { + $this->visit($this->appurl . '/notes/B') + ->see(''); + } + + /** + * Look for the client name after the note. + * + * @return void + */ + public function testClientNameDisplayed() + { + $this->visit($this->appurl . '/notes/D') + ->see('JBL5'); + } + + /** + * Look for the client URL after the note. + * + * @return void + */ + public function testClientURLDisplayed() + { + $this->visit($this->appurl . '/notes/E') + ->see('quill.p3k.io'); + } + + /** + * Test the bridgy url shim method. + * + * @return void + */ + public function testBridgy() + { + $url = 'https://brid-gy.appspot.com/comment/twitter/jonnybarnes/497778866816299008/497781260937203712'; + $expected = 'https://twitter.com/_/status/497781260937203712'; + $this->assertEquals($expected, $this->notesController->bridgyReply($url)); + } + + /** + * Test a correct profile link is formed from a generic URL. + * + * @return void + */ + public function testCreatePhotoLinkWithGenericURL() + { + $homepage = 'https://example.org'; + $expected = '/assets/profile-images/example.org/image'; + $this->assertEquals($expected, $this->notesController->createPhotoLink($homepage)); + } + + /** + * Test a correct profile link is formed from a twitter URL. + * + * @return void + */ + public function testCreatePhotoLinkWithTwitterProfileImageURL() + { + $twitterProfileImage = 'http://pbs.twimg.com/1234'; + $expected = 'https://pbs.twimg.com/1234'; + $this->assertEquals($expected, $this->notesController->createPhotoLink($twitterProfileImage)); + } + + /** + * Test `null` is returned for a twitter profile. + * + * @return void + */ + public function testCreatePhotoLinkWithTwitterURL() + { + $twitterURL = 'https://twitter.com/example'; + $this->assertNull($this->notesController->createPhotoLink($twitterURL)); + } +} diff --git a/tests/PlacesTest.php b/tests/PlacesTest.php new file mode 100644 index 00000000..b81f4ca1 --- /dev/null +++ b/tests/PlacesTest.php @@ -0,0 +1,52 @@ +appurl = config('app.url'); + } + + /** + * Test the `/places` page for OK response. + * + * @return void + */ + public function testPlacesPage() + { + $this->visit($this->appurl . '/places') + ->assertResponseOK(); + } + + /** + * Test a specific place. + * + * @return void + */ + public function testSinglePlace() + { + $this->visit($this->appurl . '/places/the-bridgewater-pub') + ->see('The Bridgewater Pub'); + } + + /** + * Test the nearby method returns a collection. + * + * @return void + */ + public function testNearbyMethod() + { + $nearby = \App\Place::near(53.5, -2.38, 1000); + $this->assertEquals('the-bridgewater-pub', $nearby[0]->slug); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 00000000..8578b17e --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,25 @@ +make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + + return $app; + } +} diff --git a/tests/TokenServiceTest.php b/tests/TokenServiceTest.php new file mode 100644 index 00000000..e3aa00a2 --- /dev/null +++ b/tests/TokenServiceTest.php @@ -0,0 +1,43 @@ +appurl = config('app.url'); + $this->tokenService = new \App\Services\TokenService(); + } + + /** + * Given the token is dependent on a random nonce, the time of creation and + * the APP_KEY, to test, we shall create a token, and then verify it. + * + * @return void + */ + public function testTokenCreationAndValidation() + { + $data = [ + 'me' => 'https://example.org', + 'client_id' => 'https://quill.p3k.io', + 'scope' => 'post' + ]; + $token = $this->tokenService->getNewToken($data); + $valid = $this->tokenService->validateToken($token); + $validData = [ + 'me' => $valid->getClaim('me'), + 'client_id' => $valid->getClaim('client_id'), + 'scope' => $valid->getClaim('scope') + ]; + $this->assertSame($data, $validData); + } +} diff --git a/tests/aaron.png b/tests/aaron.png new file mode 100644 index 0000000000000000000000000000000000000000..289234388005ba7bc557b74edc5d48ce2d1115f6 GIT binary patch literal 6527 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 Date: Thu, 19 May 2016 16:42:29 +0100 Subject: [PATCH 2/5] Rename app --- composer.json | 2 +- readme.md | 28 +++------------------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/composer.json b/composer.json index 6e9e5aa5..d03ad56f 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "jonnybarnes/jbl5", + "name": "jonnybarnes/jonnybarnes.uk", "description": "The code for jonnybanres.uk, based on Laravel 5.2", "keywords": ["framework", "laravel", "indieweb"], "license": "CC0-1.0", diff --git a/readme.md b/readme.md index 7f8816d6..38b34928 100644 --- a/readme.md +++ b/readme.md @@ -1,27 +1,5 @@ -# Laravel PHP Framework +# jonnybarnes.uk -[![Build Status](https://travis-ci.org/laravel/framework.svg)](https://travis-ci.org/laravel/framework) -[![Total Downloads](https://poser.pugx.org/laravel/framework/d/total.svg)](https://packagist.org/packages/laravel/framework) -[![Latest Stable Version](https://poser.pugx.org/laravel/framework/v/stable.svg)](https://packagist.org/packages/laravel/framework) -[![Latest Unstable Version](https://poser.pugx.org/laravel/framework/v/unstable.svg)](https://packagist.org/packages/laravel/framework) -[![License](https://poser.pugx.org/laravel/framework/license.svg)](https://packagist.org/packages/laravel/framework) +This is the code that runs my website, [jonnybarnes.uk](https://jonnybarnes.uk). -Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable, creative experience to be truly fulfilling. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as authentication, routing, sessions, queueing, and caching. - -Laravel is accessible, yet powerful, providing tools needed for large, robust applications. A superb inversion of control container, expressive migration system, and tightly integrated unit testing support give you the tools you need to build any application with which you are tasked. - -## Official Documentation - -Documentation for the framework can be found on the [Laravel website](http://laravel.com/docs). - -## Contributing - -Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](http://laravel.com/docs/contributions). - -## Security Vulnerabilities - -If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed. - -## License - -The Laravel framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). +It’s not quite ready for anyone else, but it will be soon :) From 4559a5bce9a71d1871978b3c41d71f1626eef678 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Tue, 24 May 2016 13:08:41 +0100 Subject: [PATCH 3/5] Updated .lock --- composer.lock | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/composer.lock b/composer.lock index a7fac400..34f3e43b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "6303f502566131a9770f488130aab593", - "content-hash": "8acf6b6b6db3ef7f0418631e6d15eace", + "hash": "4525beccb6fc2efeada96db7dbbedd9f", + "content-hash": "b4fb100b154bd0655bee2f2edcca13eb", "packages": [ { "name": "anahkiasen/underscore-php", @@ -59,16 +59,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.18.10", + "version": "3.18.12", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "483e21b602fc5c9993437e6e04e44d936392c344" + "reference": "12386ad98e3a76df29cee9475264b7364a50542f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/483e21b602fc5c9993437e6e04e44d936392c344", - "reference": "483e21b602fc5c9993437e6e04e44d936392c344", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/12386ad98e3a76df29cee9475264b7364a50542f", + "reference": "12386ad98e3a76df29cee9475264b7364a50542f", "shasum": "" }, "require": { @@ -135,7 +135,7 @@ "s3", "sdk" ], - "time": "2016-05-18 20:23:24" + "time": "2016-05-20 05:19:30" }, { "name": "barnabywalters/mf-cleaner", @@ -1362,16 +1362,16 @@ }, { "name": "league/commonmark", - "version": "0.13.2", + "version": "0.13.3", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "35ac362082ca983a8123df2ee2cdfcf456ab6295" + "reference": "35816f39eb2498484fbb7b1495633a976ee1a8de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/35ac362082ca983a8123df2ee2cdfcf456ab6295", - "reference": "35ac362082ca983a8123df2ee2cdfcf456ab6295", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/35816f39eb2498484fbb7b1495633a976ee1a8de", + "reference": "35816f39eb2498484fbb7b1495633a976ee1a8de", "shasum": "" }, "require": { @@ -1382,6 +1382,7 @@ "colinodell/commonmark-php": "*" }, "require-dev": { + "cebe/markdown": "~1.0", "erusev/parsedown": "~1.0", "jgm/commonmark": "0.25", "michelf/php-markdown": "~1.4", @@ -1426,7 +1427,7 @@ "markdown", "parser" ], - "time": "2016-03-27 19:10:13" + "time": "2016-05-21 18:41:30" }, { "name": "league/flysystem", @@ -3932,16 +3933,16 @@ }, { "name": "mockery/mockery", - "version": "0.9.4", + "version": "0.9.5", "source": { "type": "git", "url": "https://github.com/padraic/mockery.git", - "reference": "70bba85e4aabc9449626651f48b9018ede04f86b" + "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/padraic/mockery/zipball/70bba85e4aabc9449626651f48b9018ede04f86b", - "reference": "70bba85e4aabc9449626651f48b9018ede04f86b", + "url": "https://api.github.com/repos/padraic/mockery/zipball/4db079511a283e5aba1b3c2fb19037c645e70fc2", + "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2", "shasum": "" }, "require": { @@ -3969,7 +3970,7 @@ ], "authors": [ { - "name": "Padraic Brady", + "name": "Pádraic Brady", "email": "padraic.brady@gmail.com", "homepage": "http://blog.astrumfutura.com" }, @@ -3993,7 +3994,7 @@ "test double", "testing" ], - "time": "2015-04-02 19:54:00" + "time": "2016-05-22 21:52:33" }, { "name": "phpdocumentor/reflection-docblock", From d43684229b25cc39c4176b220ab7146c9f7c1821 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Tue, 24 May 2016 13:39:18 +0100 Subject: [PATCH 4/5] Get phaza/laravel-postgis working again? Better travis config --- .travis.yml | 15 +++++++++++++-- composer.json | 6 ++++++ composer.lock | 27 ++++++++++++++++++++------- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 87638d6c..cd687b56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,10 @@ addons: services: - postgresql +env: + global: + - setup=basic + php: - 7.0 - nightly @@ -15,12 +19,19 @@ matrix: allow_failures: - php: nightly +before_install: + - phpenv config-rm xdebug.ini + - travis_retry composer self-update --preview + +install: + - if [[ $setup = 'basic' ]]; then travis_retry composer install --no-interaction --prefer-dist; fi + - if [[ $setup = 'stable' ]]; then travis_retry composer update --no-interaction --prefer-dist --prefer-stable; fi + - if [[ $setup = 'lowest' ]]; then travis_retry composer update --no-interaction --prefer-dist --prefer-lowest --prefer-stable; fi + before_script: - psql -U travis -c 'create database travis_ci_test' - psql -U travis -d travis_ci_test -c 'create extension postgis' - cp .env.travis .env - - travis_retry composer self-update --preview - - travis_retry composer install --no-interaction - php artisan key:generate - php artisan migrate - php artisan db:seed diff --git a/composer.json b/composer.json index d03ad56f..f9969344 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,12 @@ "barryvdh/laravel-debugbar": "~2.0", "filp/whoops": "~2.0" }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/njbarrett/laravel-postgis" + } + ], "autoload": { "classmap": [ "database" diff --git a/composer.lock b/composer.lock index 34f3e43b..906cbbba 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "4525beccb6fc2efeada96db7dbbedd9f", - "content-hash": "b4fb100b154bd0655bee2f2edcca13eb", + "hash": "daf7804a781d9e4f7de63ae2da8dee9e", + "content-hash": "59a5ff5c293a0de8dbc63e7b8f0cf055", "packages": [ { "name": "anahkiasen/underscore-php", @@ -2104,12 +2104,12 @@ "source": { "type": "git", "url": "https://github.com/njbarrett/laravel-postgis.git", - "reference": "1e1a0247fdc1e3310153468a73c67a961bdb454d" + "reference": "accec379af8ceba903ceb10df37beeb9bfb411cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/njbarrett/laravel-postgis/zipball/1e1a0247fdc1e3310153468a73c67a961bdb454d", - "reference": "1e1a0247fdc1e3310153468a73c67a961bdb454d", + "url": "https://api.github.com/repos/njbarrett/laravel-postgis/zipball/accec379af8ceba903ceb10df37beeb9bfb411cc", + "reference": "accec379af8ceba903ceb10df37beeb9bfb411cc", "shasum": "" }, "require": { @@ -2131,7 +2131,12 @@ "Phaza\\LaravelPostgis\\": "src/" } }, - "notification-url": "https://packagist.org/downloads/", + "autoload-dev": { + "classmap": [ + "tests/BaseTestCase.php", + "tests/Stubs/" + ] + }, "license": [ "MIT" ], @@ -2139,10 +2144,18 @@ { "name": "Peter Haza", "email": "peter.haza@gmail.com" + }, + { + "name": "Nicholas Barrett", + "email": "njbarrett7@gmail.com" } ], "description": "Postgis extensions for laravel. Aims to make it easy to work with geometries from laravel models", - "time": "2016-05-18 07:54:54" + "support": { + "source": "https://github.com/njbarrett/laravel-postgis/tree/master", + "issues": "https://github.com/njbarrett/laravel-postgis/issues" + }, + "time": "2016-05-21 08:00:18" }, { "name": "predis/predis", From 44e32a8261de9ae79cd790b34373622cb0a2e570 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Wed, 25 May 2016 15:39:12 +0100 Subject: [PATCH 5/5] Set relase date in changelog --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.md diff --git a/changelog.md b/changelog.md new file mode 100644 index 00000000..9ff53f79 --- /dev/null +++ b/changelog.md @@ -0,0 +1,4 @@ +# Changelog + +## Version 0.0.1 (2016-05-25) +Initial release

    Or do you want to delete this contact?